Summary: Learn how a simple change to a preference variable can help prevent accidental changes when using Windows PowerShell.
Microsoft Scripting Guy Ed Wilson here. When I was teaching my Windows PowerShell Best Practices class out in Irvine, California, recently, I was talking to the class about the whatif parameter. I did my usual introduction to the feature, which goes something like this:
“How many of you have ever typed a command at the command line, and you did not know in advance exactly what the command would do?” (Most of the hands in the room rise). “Okay, now, how many of you have ever done that on a production server?” (Most of the hands lower, but a considerable number are still up. I note for the benefit of the class that my hand is still up.)
One reason so many hands were up was that, when troubleshooting servers or attempting to repair servers that have problems, it is common to find a TechNet article that says open the command prompt and type these dozen cryptic commands and press Enter. It is not that network administrators are cowboys who go riding happily off into uncharted territory, but it is that they are put into the unenviable situation of having to make hard choices. Type the command and hope for the best, or suffer along and hope the server stays up for a bit longer.
I boldly proclaim that if they use the whatif switch on Windows PowerShell commands, it will add at least a fractional percentage point to their system up time. I have no research to back this up, but it does stand to reason. A student in California raised her hand, and asked this:
“But what if the admin does not use the whatif switch? Then what?”
Well, at first, I felt like saying, “I guess you are out of luck.” But then I remembered a little-known and little-used preference variable—the $WhatIfPreference variable. The $WhatIfPreference variable is hanging out on the Variable drive with a value of false. This is shown in the following code:
PS C:\> dir Variable:\WhatIfPreference
Name Value
WhatIfPreference False
What the $WhatIfPreference variable does is flip the whatif parameter to on, for every Windows PowerShell cmdlet that supports a whatif switch. This means that every cmdlet that changes system state will no longer change system state by default. To illustrate, I am going to start an instance of Notepad. I will then use the Get-Process to retrieve the process, and pipe it to Stop-Process—and the Notepad process goes away. This is shown here:
PS C:\> $ErrorView = "CategoryView"
PS C:\> notepad
PS C:\> get-process notepad | Stop-Process
PS C:\> get-process notepad
ObjectNotFound: (notepad:String) [Get-Process], ProcessCommandException
Next, I change and use the whatif parameter when calling the Stop-Process cmdlet. The whatif parameter, lets me know that it would stop an instance of the Notepad process, the one with the process ID of 6052, if the command ran without the whatif parameter. I then use the Get-Process cmdlet to confirm that the instance of Notepad with the process ID of 6052 still runs. These commands and associated output are shown here:
PS C:\> notepad
PS C:\> get-process notepad | Stop-Process -WhatIf
What if: Performing operation "Stop-Process" on Target "notepad (6052)".
PS C:\> get-process notepad
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) ID ProcessName
79 9 4220 8976 82 0.03 6052 notepad
As my student asked, what happens when I forget to use the whatif statement? Well of course, the Notepad process goes away, and there is no prompt, no anything. There’s not even any sign that the process no longer runs. The only way to confirm that Notepad went away is to use Get-Process. These commands and associated output are shown in the following figure.
The solution is to turn on the $WhatIfPreference, which I do by setting the value to $true:
$WhatIfPreference = $true
After the $WhatIfPreference is set to $true, any command that would change system state (and therefore any cmdlet that supports the whatif switched parameter) runs with whatif, and therefore does not actually execute the command, as shown here:
PS C:\> $WhatIfPreference = $true
PS C:\> notepad
PS C:\> get-process notepad | Stop-Process
What if: Performing operation "Stop-Process" on Target "notepad (7840)".
PS C:\>
This includes commands to create a new folder (because it makes a change to the system). This is shown here:
PS C:\> md c:\fso4
What if: Performing operation "Create Directory" on Target "Destination: C:\fso4".
PS C:\> test-path c:\fso4
False
If I want to execute a command that changes system state, I need to set the value for whatif to false. When doing this, I must use $False, and not simply false:
PS C:\> get-process notepad | Stop-Process -whatif:false
InvalidArgument: (:) [Stop-Process], ParameterBindingException
PS C:\> get-process notepad | Stop-Process -whatif:$false
PS C:\> get-process notepad
ObjectNotFound: (notepad:String) [Get-Process], ProcessCommandException
Keep in mind that forcing whatif to $False is per command, so a subsequent call to a command that changes system state will execute the whatif behavior unless I once again override the value. This is shown here:
PS C:\> md c:\fso4
What if: Performing operation "Create Directory" on Target "Destination: C:\fso4".
PS C:\> md c:\fso4 -WhatIf:$false
Directory: C:\
Mode LastWriteTime Length Name
d---- 11/11/2011 6:57 PM fso4
PS C:\> test-path c:\fso4
True
The above commands and associated output are shown in the following figure.
After I close Windows PowerShell and open it up again, the value of the $WhatIfPreference variable resets to $False. I no longer have the added protection of the whatif switch on by default. This appears in the following figure.
The solution, of course, is to add the $WhatIfPreference to the Windows PowerShell profile. I have a number of Hey, Scripting Guy! Posts that talk about working with Windows PowerShell profiles or adding items to profiles. I also have an excerpt from my Windows PowerShell 2.0 Best Practices book that covers the different Windows PowerShell profiles. You will need to decide if you want to enable the preference variable on workstations, servers, or nothing—or for just certain users. Personally, I do not have it enabled on any of my systems, but there have been a couple of times when it might have come in handy. For highly available systems, it might be a very good thing to implement.
That is all there is to using the $WhatIfPreference variable. Join me tomorrow for more Windows PowerShell stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy