Prof. Powershell

Scriptblock Surprises

PowerShell Functions can save you time. Scriptblocks save you even more time.

In Windows PowerShell, if you want to modularize a block of code so that you don't have to keep typing it, one way is to create a function. You can even create them on the fly.

PS C:\> function t {(get-date).ToShortTimeString()}
PS C:\> t
12:30:35 PM

But another way is to use a scriptblock. You actually see scriptblocks all over PowerShell. A scriptblock is a collection of PowerShell code inside a set of curly braces { }.

PS C:\> $sb={get-wmiobject win32_logicaldisk -filter "drivetype=3"}
PS C:\> $sb
get-wmiobject win32_logicaldisk -filter "drivetype=3"

When looking at the scriptblock variable, $sb, we get the definition which I can verify is a scriptblock object.

PS C:\> $sb.gettype().name
ScriptBlock

To execute the scriptblock I merely prepend the invoke operator, &, like this:

PS C:\> &$sb

The pipelined output is the same as if you had run the Get-WMIObject command manually. The scriptblock is in essence a shortcut so I only have to type the command once. There's no limit to the amount of code you can put in a scriptblock. You can separate out multiple commands with a ; if you want to type it all on one line.

PS C:\> $stopped={$stopped=get-service | where {$_.status -eq "stopped"};$stopped | select Name; Write-Host "`nFound $($stopped.count) stopped services" -foregroundcolor green}

Or spread it out like this.

PS C:\> $stopped={$stopped=get-service | where {$_.status -eq "stopped"}
>> $stopped | select Name
>> Write-Host "`nFound $($stopped.count) stopped services" -foregroundcolor green}
>>
PS C:\>

They'll both work the same way when you invoke $stopped. The last part of the scriptblock lesson is how to pass parameters. Let's go back to my first WMI scriptblock. Wouldn't it be nice to be able to specify a computername? You can by defining a parameter as part of your scriptblock.

PS C:\> $sb={Param([string]$computername=$env:computername) get-wmiobject win32_logicaldisk -filter "drivetype=3" -computername $computername}

The Param statement contains a comma separated list of parameters. My example only has one. Use the variable within your scriptblock. I strongly recommend providing a default value. In this example, the default computer is the local host. That means no errors when I invoke the scriptblock:

PS C:\> &$sb

Or I can specify a computername:

PS C:\> &$sb jdhit-dc01

Because I only have one parameter I don't have to specify it, but I could if I wanted to.

PS C:\> &$sb -computername jdhit-dc01

Otherwise keep in mind that parameters are positional.

If you need a lot of error handling or a more robust solution then developing a function is the better way to go. But for quick and re-usable code to save typing and your sanity, I encourage you to explore scriptblocks. You might be pleasantly surprised.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular