Prof. Powershell

What's In Your Pipeline?

The ease with which we can automate things in PowerShell lies in the pipeline. But use it wisely.

If you've been reading Prof. PowerShell for any length of time you realize how much importance I place on the PowerShell pipeline. It's what makes PowerShell such a magnificent automation engine, once you get your head around the whole "objects in a pipeline" concept:

PS C:\> get-hotfix -description "Security Update*" | where {$_.InstalledOn -gt "7/1/2012"} | Export-Csv c:\work\secupdates.csv -NoTypeInformation

With a single, albeit long, command, I've retrieved all security updates installed since July 1, 2012 and exported them to a CSV file that I can use elsewhere. But just because you can write something as a one-line PowerShell expression, should you?

The answer will sound like something your Mom might say: "It depends."

If you are working interactively at a PowerShell prompt, using a pipelined expression lets you get a lot done with minimal effort. The same could also be true if using a command in a script. But not always. Taking my hotfix example, Get-HotFix takes some time to run, especially when querying remote computers. If I want to do several things with the data, it certainly makes sense to break this up into more manageable pieces:

$hot = get-hotfix -description "Security Update*"
$recent = $hot | where {$_.InstalledOn -gt "7/1/2012"}
$recent | Export-Csv c:\work\secupdates.csv -NoTypeInformation

With this, I can insert additional commands based on this data:

$hot = get-hotfix -description "Security Update*"
Write-host "Found $($hot.count) security updates" -foreground Green
#get a unique list of accounts that installed updates
$hot | select -expand InstalledBy -unique | out-file "c:\work\installers.txt"
if (($hot | select -expand HotfixID) -notcontains 'KB2719985') {
  Write-Warning "Required Security Update Not Found!"
}
$recent = $hot | where {$_.InstalledOn -gt "7/1/2012"}
Write-Host "$($recent.count) are after July 1, 2012" –foreground Green
$file=" c:\work\secupdates.csv"
Write-Host "Exporting to $file" -foreground Green
$recent | Export-Csv -NoTypeInformation

So the first thing to think about is re-use and what you might want to do with data you've collected, especially if it takes a long time to collect it.

It is also possible there might be performance gains, although this is hard to predict. My recommendation is to learn how to use Measure-Command. For example, on my computer this block of code took about 5020 milliseconds.

get-process | where {$_.path} | Select Path -unique | get-acl | Select Path,Owner

While this variation about 5 ms longer. Hardly noticeable.

$paths= get-process | where {$_.path} | Select Path -unique
$paths | get-acl | Select Path,Owner
Interestingly, this only took 4966ms.
$paths= get-process | where {$_.path} | Select Path -unique
  foreach ($path in $paths) {
  $path | get-acl | Select Path,Owner
  }

But I don't recommend letting performance totally guide your decisions. Again, think about what else you might need to do with your command or script. The bottom line is that using pipelines or variables or some combination is as much an art as it is a science.

About the Author

Jeffery Hicks is a multi-year Microsoft MVP in Windows PowerShell, Microsoft Certified Professional and an IT veteran with almost 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 works today as an independent author, trainer and consultant. Jeff is a regular contributor to a variety on online sites, as well as frequent speaker at technology conferences and user groups. Keep up with Jeff and his projects at http://jdhitsolutions.com/blog.

comments powered by Disqus

MCPMag.com

Sign up for our newsletter.

I agree to this site's Privacy Policy.