Summary: Microsoft Scripting Guy, Ed Wilson, shares his top five Windows PowerShell 3.0 tips and tricks.
Microsoft Scripting Guy, Ed Wilson, is here. Today marks a red letter day. No, we have not yet sold out Windows PowerShell Saturday in Charlotte, North Carolina (but we are really close). And no, the Scripting Wife and I have not sold our house and moved to Australia (although we would not really mind doing that). No, it is something more primeval, something more substantive, and frankly, something more exciting than either of the two previous possibilities…
I restart my radio series on TechNet Radio: IT Time with Microsoft IT Pro evangelist, Blain Barton. You can catch the earlier episodes via the Learn PowerShell page if you are so inclined. For our first session of the new fiscal year, we discussed my new Microsoft Press Windows PowerShell 3.0 Step by Step book a bit. In the next episode, we will talk about my favorite Windows PowerShell 3.0 tips and tricks. Don’t worry, todays blog will not necessarily spoil the plot because Blain is an absolutely top notch interviewer. In fact, I would place him right up there will the likes of Hal Rotenberg and Jonathan Medd. Yep, he is that good.
Way cool Windows PowerShell 3.0 stuff
Much of the way cool stuff that is written about Windows PowerShell 3.0 has to do with new cmdlets—especially all the new cmdlets in Windows 8 and in Windows Server 2012. These are the bells and whistles, but some of my favorite new things in Windows PowerShell 3.0 are the stuff that makes my life easier day in and day out. For example, how often, really, will I be typing Get-NetIpAddress or Set-NetConnectionProfile? On the other hand, how many times do I need to access a single property from each object in a collection? For me, I need the latter a whole lot more times.
So here are my top five Windows PowerShell 3.0 tricks. They are all language related, and I predict that they will also become your favorites.
My favorite Windows PowerShell trick is the automatic foreach
In Windows PowerShell 1.0 and Windows PowerShell 2.0, if you have a collection of objects, you must iterate through that collection, individually retrieve a desired property, and then possibly store it back in the variable for later use. It worked, and the behavior was similar to the behavior in other languages. In fact, this behavior still works in the Windows PowerShell 3.0 world today. Here is an example of using the Get-Process cmdlet where I store the collection of process objects in a variable named $process, and then pipe the resulting objects to the Foreach-Object cmdlet to retrieve the name property from the current object in the pipeline. I store these retrieved names in a $names variable.
$process = Get-Process
$Names = $process | foreach { $_.name }
$names
This command sequence is not that difficult, and it is one that the enterprise scripter will eventually type hundreds and hundreds of times over the course of a couple years. But in Windows PowerShell 3.0 this sequence is no longer required, and entire $process pipeline to the Foreach-Object command sequence is eliminated. Instead, Windows PowerShell 3.0 makes desired properties immediately available, and directly accessible. This revision of commands is shown here.
$process = Get-Process
$process.name
Although simply displaying process names may be somewhat illuminating, this sequence saves me tons of time when I am gathering the names of servers to use in further remoting scenarios. This sequence is shown here.
$servers = Get-ADComputer –Filter *
Get-HotFix –CN ($servers.name)
Where are squiggle brackets for Where-Object?
My second favorite feature in Windows PowerShell 3.0 is the streamlined Where-Object syntax for simple where clauses. In Windows PowerShell 1.0 and in Windows PowerShell 2.0, to use the Where-Object cmdlet to filter returned information required the use of script blocks, special variables, and understanding how pipelining worked. In short, this important task was fraught with stumbling blocks for the beginner Windows PowerShell scripter.
But you may say, “YOU are not a beginner Windows PowerShell scripter. So why is this syntax so popular with you?” I will tell you…
Of all the cmdlets I use, the Where-Object cmdlet consistently ranks in the top four cmdlets I always use. In fact, I can prove this statement because I wrote a script that parses cmdlets used in scripts. In the Weekend Scripter: Hey, Scripting Guy! Blog post Playing Around With the Windows PowerShell Tokenizer, I include a script that I use to parse my scripts to reveal which cmdlets I use the most. When you have run the script against your script directory, use the following command to process the contents.
Get-Content $logpath | sort | group -NoElement | sort count
The long way of using the Where-Object is shown here.
Get-Process | where { $_.name -match 'word' }
Here is the short way of using the Where-Object.
Get-Process | where name -match 'word'
Not only is it less typing, but it is also easier to read.
Using local variables in remote sessions
With Windows PowerShell remoting gaining in popularity and importance, ease-of-use becomes vital. If I created a local variable in Windows PowerShell 2.0, and I needed to use it in a remote session, I had to write a bit of code to accomplish this feat, and I had to pass the local variable as an argument and as a parameter in the remote session. Sound confusing? Well, it wasn’t after the first 100 times doing it. By that time, it was just annoying. Here is what I am talking about (icm is an alias for the Invoke-Command cmdlet).
$class = "win32_bios"
icm -cn dc3 {param($class) gwmi -class $class} -ArgumentList $class
In Windows PowerShell 3.0, this process is much more straightforward and easier to understand. Here is the Windows PowerShell 3.0 syntax that is so sweet it checks in at number 3 on the Scripting Guy’s top five tricks list.
$class = "win32_bios"
icm -cn dc3 {gwmi -class $using:class}
Flexible script formatting
Because it seems that I am constantly writing a blog or a book, or teaching a class, I am always confronted with a narrow screen or a large font that takes up lots of screen real estate. Typically, I work with a maximum of 82 – 85 characters of width. This is a problem with a verbose easy-to-read language. Couple this with the fact that many of my readers or my audience is just learning Windows PowerShell, and I have a real problem. I have learned to despise line continuation because of the unnecessary errors that it potentially introduces. In Windows PowerShell 2.0 or Windows PowerShell 1.0, my basic choices were lots of variables, breaking at the pipeline character, or line continuation. In Windows PowerShell 3.0, flexible formatting enters the picture. This means that I can use a syntax such as the one shown here.
(get-process).
name.
gettype()
This feature is so cool that it deserves a picture. Seeing is believing with flexible formatting. OK, maybe it is just me, but it is good enough for number 4 in my top 5 Windows PowerShell 3.0 tricks.
Variable validation attributes
Windows PowerShell 2.0 had parameter validation attributes, but if I wanted to ensure that a variable value met specific requirements (other than parameters), I needed to write code to verify those requirements, or I needed to be ready to catch an error. In Windows PowerShell 3.0, the introduction of variable validation attributes can vastly simplify this error checking requirement to a single command. For people who write a lot of scripts (such as myself), this is a huge win. Here is an example of setting a validation attribute where the value of $c must be within the range of 1 to 5.
[ValidateRange(1,5)][int]$c = 1
When I run the command and exceed the permissible range, an error message appears. The following command runs 10 times and sets a random number between 1 and 8 to the value of $c.
1..10 | % {$c = Get-Random -Minimum 1 -Maximum 8 ; $c}
The command and the error are shown in the image that follows.
Come back tomorrow when I will talk about more Windows PowerShell cool 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