November 21st, 2011

Make a Simple Change to PowerShell to Prevent Accidents

Doctor Scripto
Scripter

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.

Image of commands and associated output

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.

Image of commands and associated output

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.

Image of $WhatIfPreference variable resetting to $False

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

 

 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.