Do Not Assume Anything in Your PowerShell Script

Do Not Assume Anything in Your PowerShell Script

  • Comments 1
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, discusses making assumptions in his review of the 2011 Scripting games.

Microsoft Scripting Guy, Ed Wilson, is here. One of the things that was really great about grading scripts for the 2011 Scripting Games is that I got to see lots of scripts written by some excellent scripters. As I reviewed my comments on the scripts, I began to see a series of common themes. For the next two weeks, we will review those themes. These next two weeks’ worth of blogs are going to be some of the most important Windows PowerShell blogs this year because they run right to the heart of a discussion I began last weekend about code reuse and the use of aliases.

Making assumptions can simplify things. For example, if you always leave the garage door open, you may hop into your car; put it into reverse, stomp on the accelerator, and assume the door is open. This scenario may even work—most of the time. But what happens when the garage door is closed? Is the risk of damage to both the motor vehicle and to the garage door worth the convenience of assuming that the door is open…probably not.

In much the same way, a Windows PowerShell script with faulty or dangerous assumptions can cause unexpected results. When I was grading Windows PowerShell scripts for the 2011 Scripting Games, I ran across many scripts that had assumptions—some of the assumptions were pretty safe, and others caused scripts to fail.

Assuming the path

First, let’s look at a fairly safe assumption and how to remove the assumption. In Beginner Event 6 of the 2011 Scripting Games, the scenario calls for querying the WindowsUpdate.log file. This file resides in the root of the Windows directory as shown here:

C:\Windows\WindowsUpdate.log

In the scenario, you are troubleshooting problems with Windows Update; and therefore, it is assumed you are working at the Windows PowerShell console. In addition, you will want to accomplish the task with the least amount of trouble. This is a case where it is perfectly acceptable to use the defaults if they work in your particular environment. After all, I know where I installed Windows 7 on my computer! If I am troubleshooting my computer, I should be allowed to make certain assumptions about my environment. This was also the approach taken my Microsoft PowerShell MVP, Sean Kearney, in his solution to the event.

Now for an aside…

One of the great things about this year’s Scripting Games has been the interaction with the community. Every morning, the first thing I have done is look at comments posted to the various Hey Scripting Guy! blogs. The comments have become a great source of conversation and dialogue running parallel to the games. Several comments posted to Sean’s article point out that using a hardcoded path to the Windows directory is a potential source of failure. This is true—but in my environment, it is not something I worry about because I took the defaults on all of my Windows installations. In fact, for every copy of Windows I have installed since Windows 3.1, I have used the default path. In the old days installing Citrix used to create an “M” drive, but I believe that is no longer used. But, you know what? If one does not make an assumption as to where Windows installs, it does not matter. If I assume that Windows is installed to C:\Windows, I can search the WindowsUpdate.log file as shown here.

Select-String -Path "C:\Windows\WindowsUpdate.log" -simplematch "fail"

To get rid of my assumption as to the location of Windows I can use one of two environmental variables as shown here.

Select-String -Path "$env:windir\WindowsUpdate.log" -simplematch "fail"

Select-String -Path "$env:systemroot\WindowsUpdate.log" -simplematch "fail"

So, what does the community say about these two environmental variables? The community says that $env:windir seems more legacy, and they prefer $env:systemroot. Now, just for the sake of completeness, I should tell you that $env:windir is the same as %windir% from batch language.

Assuming a process is running

Another assumption I saw while grading scripts is that a process is running. When working with a process such as the Desktop Window Manager (dwm.exe) on Windows 7, it is a pretty safe assumption that the process is running. But Notepad.exe is not a normal process that is expected to be running. One approach to providing a solution to Beginner Event 1 involved using the Get-Process cmdlet to retrieve an instance of the Notepad process so an examination of its properties can take place.

In most of the scripts I reviewed, scripters who adopted this technique assumed that Notepad was running. This is not necessarily a bad thing given the scenario, but scripters who wanted to gain all five points at stake for the event did not assume anything. They checked to see if Notepad was running, and if it was not running, they started it. Here is some code that accomplishes that exact task.

if(!(Get-Process | where { $_.name -eq 'notepad'} ))

  { Start-Process notepad ; Get-Process -Name notepad }

Else { Get-Process -Name notepad }

Assuming the culture

I did not specifically see any scripts fail due to assumptions related to cultural settings on the computer. It was not one of the areas I wanted to stress this year; but given the complications that arise in this area, I might very well include it in next year’s Scripting Games. Therefore, to start the learning for next year’s games a bit early, let me share the following tip.

Use Get-Culture to detect the current culture of the computer. The command returns a CultureInfo object. The default properties that are returned by the command are shown here.

PS C:\Users\ed.NWTRADERS> Get-Culture

 

LCID             Name             DisplayName                                                                                                                 

----             ----             -----------                                                                                                                 

1033             en-US            English (United States)                                                                                                     

The easiest property to use is the LCID because it is a number and is therefore easily matched. For example, suppose I want to check the culture, and if it is 1033 (US English), I will display the date in month, day, year format. If the culture is anything else, I display the format in year, month, day format. The code to do this is shown here.

if((Get-Culture).lcid -eq 1033) { Get-Date -UFormat "%m%d%Y" }

Else { Get-Date -UFormat "%Y%m%d" }

One cool thing that is available via the Get-Culture cmdlet is the DateTimeFormat property. This property returns a DateTimeInfo object. By using Select-Object and the ExpandProperty property, I can return the properties of this object and use them to inspect the rules that are applicable to the date-time formatting for the culture. This is illustrated in the following image.

Image of command output

Well that is all there is to talk about watching for assumptions in scripts. Join me tomorrow as I welcome Don Jones as the guest blogger.

 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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Right!!!

    That's absolutely true!

    1. Expect the Unexepted

    2. Don't expect that you can handle each facet of the Unexpected

    3. Include error handling to at least be notified, if the Unexpected strikes you:-)

    kind regards, Klaus