Summary: Microsoft Scripting Guy, Ed Wilson, talks about a couple of issues he saw while grading scripts for the 2012 Windows PowerShell Scripting Games.
Microsoft Scripting Guy, Ed Wilson, is here. The Scripting Wife and I are in Atlanta for SQL Saturday #111. I will be talking about Windows PowerShell and SQL best practices. One of the great things about the Scripting Games is seeing what other people are doing. When you are the Microsoft Scripting Guy, it is good to see where people still have some confusion, and then use that information to generate ideas for blog posts. I am not alone in this endeavor. I saw a tweet the other day that said the person was generating a huge list of subjects for blog posts as a result of the 2012 Scripting Games. Today I want to look at a few things that caused me to repeat myself over and over again as I was grading scripts.
The mystery of the compound Where clause
In Windows PowerShell 3.0, we have simplified the simple Where clause. I am not going to write about that right now, but it is enough to say that when you have a single condition, it is easier to write in Windows PowerShell 3.0 than in Windows PowerShell 2.0. But there are many times when you want to use a compound Where clause. For example, Beginner Event 3 requires you to find running services that also support a Stop command. I saw lots of scripts where the person obviously did not know about using a compound Where clause. Here is one such example:
gsv -computername localhost | where {($_.status -eq "Running") -and ($_.CanStop -eq $true)}
Now, there is nothing wrong with this line of code—in fact, it meets the needs of the scenario, and it works perfectly fine. But the code can be simplified by using a compound Where clause. Simple and compound do not often go together, but they do here. Here is the way I would write the Where clause:
where { $_.status -eq 'running' -and $_.canstop }
Notice, that instead of having two separate groupings, I in fact, have no grouping at all. (The grouping is the parentheses.) The compound Where clause says where the status of the current object (the $_ represents, the current object in the pipeline) is equal to Running. It also says, AND $_.CanStop. (I will talk about this in a little bit.) Where is an alias for the Where-Object cmdlet. The question mark (?) is also an alias for the Where-Object cmdlet. But notice that in the script block of the Where-Object cmdlet, condition one is equal to Running, AND condition two exists.
What is a Boolean value, and what do I do about it?
In the get running services that also accept a Stop command event, there is a property called CanStop that exists on the System.ServiceProcess.ServiceController object. This CanStop property is shown here.
PS C:\Users\ed.IAMMRED> Get-Service | Get-Member canstop
TypeName: System.ServiceProcess.ServiceController
Name MemberType Definition
---- ---------- ----------
CanStop Property System.Boolean CanStop {get;}
Notice that under the definition, it says that the CanStop property is a System.Boolean. Boolean values are On/Off, True/False, -1/0, Enabled/Disabled, Exist/Don’t exist, and so on. One of the cool things about Windows PowerShell, is that if something exists, and it is a Boolean value, I only need to say Where plus ThePropertyOfTheObject. Let’s go back to Beginner Event 3. So, in the long version of the Where clause, the writer had the following:
where {($_.status -eq "Running") -and ($_.CanStop -eq $true)}
As I mentioned, it works. But it can be shortened by saying –and $_.CanStop. Here we are saying, “Does the CanStop property exist on the object?” If it does, this is all we want. Therefore, I can reduce this by saying, “Does it exist?” This is shown here.
where { $_.status -eq 'running' -and $_.canstop }
The nice thing is that I can negate the Boolean value. For example, if I want the running services that do NOT accept a Stop command, I have several choices. I would probably use the Not operator (!). This is shown here.
where { $_.status -eq 'running' -AND !$_.canstop }
Most of the time, I will use grouping around the Boolean value to make the code a bit clearer. This is shown here.
where { $_.status -eq 'running' -AND !($_.canstop)
If you do not like the exclamation point (!) for the Not operator, you also can use the –not operator. This is shown here.
where { $_.status -eq 'running' -AND -not $_.canstop }
Once again, I generally put grouping around the Boolean value to make the command easier to read (at least for me). This is shown here.
where { $_.status -eq 'running' -AND -not ($_.canstop) }
Not handling the default
I also saw lots of scripts that had a hardcoded value for ComputerName. Some said Server01, others said NameOfRemoteServer. I am calling this out because it is a problem. It causes someone to immediately edit the script before they can run it. I wrote a really good blog about this issue that I will refer you to: Create and Use Default Values in PowerShell Scripts.
Well, that is about it for now. There are thousands of scripts that need to be graded in the next few days. So until tomorrow, have a great day.
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