Supporting -Whatif, -Confirm, -Verbose – In SCRIPTS!

Supporting -Whatif, -Confirm, -Verbose – In SCRIPTS!

Rate This
  • Comments 11

<This is a super-important issue so you should definitely start using this in your scripts that you share with others (that have side effects on the system).
Please try it out and blog about it to others so that it becomes a community norm.
Thanks-jps>

One of the greatest things about PowerShell is that when you use a Cmdlet which is going to have a side effect on the system, you can always type –Whatif, -Confirm or –Verbose. Sadly, you lose this option when it comes to scripts. Over time we want to makes scripts be the semantic equivalent of Cmdlets – that is to say that a Cmdlet is a Cmdlet independent of whether you implement it in C#, VB.NET or PowerShell. That said, it takes us a while to get releases out and it really torques me that most scripts don't support –Whatif, -Confirm, and –Verbose so I decided to do something about it. I wrote a PowerShell fuction, Should-Process, which helps you implement these in your scripts (this is very similar to how we do it in Cmdlets). First let me show you a script using it and a transcript of using that script. This is a script which stops all the running calc programs:

function Stop-Calc ([Switch]$Verbose, [Switch]$Confirm, [Switch]$Whatif)
{
$AllAnswer = $null
foreach ($p in Get-Process calc)
{ if (Should-Process Stop-Calc $p.Id ([REF]$AllAnswer) "`n***Are you crazy?" -Verbose:$Verbose -Confirm:$Confirm -Whatif:$Whatif)
{ Stop-Process $p.Id
}
}
}

Here is a transcript of using that function:

PS> calc;calc;calc
PS> Stop-Calc -Whatif
What if: Performing operation "Stop-Calc" on Target "436"
What if: Performing operation "Stop-Calc" on Target "3776"
What if: Performing operation "Stop-Calc" on Target "4104"
PS>
PS>
PS>
PS> Stop-Calc -Verbose
VERBOSE: Performing "Stop-Calc" on Target "436".
VERBOSE: Performing "Stop-Calc" on Target "3776".
VERBOSE: Performing "Stop-Calc" on Target "4104".
PS> calc;calc;calc
PS>
PS>
PS>
PS> Stop-Calc -Confirm
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Calc" on Target "4596".
***Are you crazy?
[Y] Yes [A] Yes to All [N] No [L] No to all [S] Suspend [?] Help (defau
lt is "Y"): n
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Calc" on Target "5492".
***Are you crazy?
[Y] Yes [A] Yes to All [N] No [L] No to all [S] Suspend [?] Help (defau
lt is "Y"): s
PS> gps calc

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
55 3 1252 5148 49 0.02 4596 calc
55 3 1248 4936 49 0.06 5492 calc
55 3 1248 5168 49 0.06 5588 calc


PS> exit
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Calc" on Target "5492".
***Are you crazy?
[Y] Yes [A] Yes to All [N] No [L] No to all [S] Suspend [?] Help (defau
lt is "Y"): l
PS>
PS>
PS>
PS> Stop-Calc -Confirm
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Calc" on Target "4596".
***Are you crazy?
[Y] Yes [A] Yes to All [N] No [L] No to all [S] Suspend [?] Help (defau
lt is "Y"): ?
Y - Continue with only the next step of the operation.
A - Continue with all the steps of the operation.
N - Skip this operation and proceed with the next operation.
L - Skip this operation and all subsequent operations.
S - Pause the current pipeline and return to the command prompt. Type "exit"
to resume the pipeline.
[Y] Yes [A] Yes to All [N] No [L] No to all [S] Suspend [?] Help (defau
lt is "Y"): a
PS>

Here is the function that makes this all possible:

Function Should-Process ($Operation, $Target, [REF]$AllAnswer, $Warning = "", [Switch]$Verbose, [Switch]$Confirm, [Switch]$Whatif)
{
# Check to see if "YES to All" or "NO to all" has previously been selected
# Note that this technique requires the [REF] attribute on the variable.
# Here is an example of how to use this:
# function Stop-Calc ([Switch]$Verbose, [Switch]$Confirm, [Switch]$Whatif)
# {
# $AllAnswer = $null
# foreach ($p in Get-Process calc)
# { if (Should-Process Stop-Calc $p.Id ([REF]$AllAnswer) "`n***Are you crazy?" -Verbose:$Verbose -Confirm:$Confirm -Whatif:$Whatif)
# { Stop-Process $p.Id
# }
# }
# }
if ($AllAnswer.Value -eq $false)
{ return $false
}elseif ($AllAnswer.Value -eq $true)
{ return $true
}



if ($Whatif)
{ Write-Host "What if: Performing operation `"$Operation`" on Target `"$Target`""
return $false
}
if ($Confirm)
{
$ConfirmText = @"
Confirm
Are you sure you want to perform this action?
Performing operation "$Operation" on Target "$Target". $Warning
"@
Write-Host $ConfirmText
while ($True)
{
$answer = Read-Host @"
[Y] Yes [A] Yes to All [N] No [L] No to all [S] Suspend [?] Help (default is "Y")
"@
switch ($Answer)
{
"Y" { return $true}
"" { return $true}
"A" { $AllAnswer.Value = $true; return $true }
"N" { return $false }
"L" { $AllAnswer.Value = $false; return $false }
"S" { $host.EnterNestedPrompt(); Write-Host $ConfirmText }
"?" { Write-Host @"
Y - Continue with only the next step of the operation.
A - Continue with all the steps of the operation.
N - Skip this operation and proceed with the next operation.
L - Skip this operation and all subsequent operations.
S - Pause the current pipeline and return to the command prompt. Type "exit" to resume the pipeline.
"@
}
}
}
}
if ($verbose)
{
Write-Verbose "Performing `"$Operation`" on Target `"$Target`"."
}

return $true
}

I'm including this as an attachment to this entry just in case you have any copy/paste issues.

Use this often – it works great.

BTW – this all depends upon a technique that is not well documented – the [REF] attribute on parameters. Yes – PowerShell supports reference parameters! This is how we can set a variable in the Should-Process function in a way that that change is seen in the parent's scope. We do that in order to handle the YES-TO-ALL/NO-TO-ALL feature. We need to change state and then see that change the next time we get called. Notice that this requires you to pass a reference variable using a very specific syntax ([REF]$AllAnswer). Then when we want to access this parameter, we have to access it's VALUE – e.g. $AllAnswer.Value . This deserves an entire blog entry for itself but I needed to use it here so I thought a quick explanation was in order.

Jeffrey Snover [MSFT]
Windows PowerShell/MMC Architect
Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.msp

Attachment: should-process.ps1
Leave a Comment
  • Please add 3 and 1 and type the answer here:
  • Post
  • In the Newsgroup Microsoft.Public.Windows.PowerShell, BJ Stigall asked what the equivalent of the batch

  • Slowly.  Bit-by-bit.  We are getting all of your secrets.

    Good blog.  Much good info beyond the purpose of the blog.

    I like your statement about the treatment of CmdLets in any language.  It's gives us a little more fundamental knowledge about how PowerShell is intended to work and how it may change in the future.

  • Those .NET XML Configuration files, you know the ones - web.config - app.config - thingy.exe.config -

  • I got interrupted.  I'll comment later.  picked up this link out of latest TechNET magazine - august.

     Greg McGlynn

  • Thanks for this.  I took BASIC a long time ago on a Z80.  I didn't like it.  Powershell is what I've been waiting for.  Thank you for creating this.

  • In my continued resolution to make PowerShell my full time command line interface, I've been porting

  • And I almost forgot the beginners events, not much special here : Event 3 d ir c:\scripts\*.txt |% {(get-content

  • Is there any plan to have BUILT-IN SUPPORT for this into v2 so we don't have to keep including this script everywhere?

  • > Is there any plan to have BUILT-IN SUPPORT for this into v2 so we don't have to keep including this script everywhere?

    Absolutely!  

    jps

  • PowerShell is Microsoft's new command line shell for Windows. Version 1 was released in 2006, and version 2 has been in CTP for about a year now; it will finally RTM with Windows 7. It's a truly fantastic shell, and if you haven't looked into it alread

  • 在上次的介绍中我们主要介绍了Windows PowerShell V2 中高级函数的一些基础概念,在本次介绍中我们将要涉及的是如何使用高级函数达到类似cmdlet的使用体验(下面就以高级函数来称呼)。

Page 1 of 1 (11 items)