Prof. Powershell

Fanfare for the Common Parameter Part 3: Success

The third part of the common parameter series will look at saving PowerShell commands.

In the last lesson we continued our exploration of the cmdlet common parameters by looking at some error-related items. This week, let's turn our attention to something more positive. Hopefully, when you run a PowerShell command, it works and you get a result. PowerShell will write the results to the success pipeline and they eventually make it to your screen. But sometimes you want to save the results. I'm sure most of you would do something like this:

PS C:\> $p = get-process
PS C:\> $p[0].name
avgcsrva

The variable $p contains all of the process objects from Get-Process. However, we can also use the common parameter –OutVariable, or its alias –ov.

PS C:\> get-process -OutVariable procs

This will run Get-Process normally, meaning you will get results written to the screen. But they have also been saved to the variable $procs.

PS C:\> $procs.count
104
PS C:\> $procs[0].name
avgcsrva

You should be able to use this variable the same way you would have used $p.

PS C:\> $procs | sort workingset -descending | Select -First 3

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
673      71   176508     195948   833    29.80   2092 powershell
630     111   343372     192748 -1450    14.37   2568 sqlservr
1881      89   152796     177592   475   363.31   5240 chrome

There are some caveats when using –Outvariable. First, it is per cmdlet which actually makes for some interesting possibilities.

PS C:\> $data = get-process -ov myprocs | where {$_.Company} -ov w | group Company -ov g

Output from the entire expression has been saved to $data and each part of the expression has had its output saved to a separate variable.

PS C:\> $data[0]

Count Name                      Group
----- ----                      -----
8 AVG Technologies CZ, s... {System.Diagnostics.Process (avgcsrva), System.Di...

PS C:\> $w[0]

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
270      12    40380      89096   223    72.38    680 avgcsrva

PS C:\> $g[0]

Count Name                      Group
----- ----                      -----
8 AVG Technologies CZ, s... {System.Diagnostics.Process (avgcsrva), System.Di...

Although from a practical perspective, $g and $data are identical. But a technique like this can be useful when troubleshooting a complex expression because you can examine the results at each step of the process.

One important thing to remember is that the variable isn't fully populated until the entire expression completes. What this means is that you can't rely on using the variable within the expression. Here's an example:

PS C:\> get-process -ov ps | where {$_.id -le $ps.count*20} | measure

Count    : 10
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

Yes, I know this example is silly from a production point of view but it illustrates my point. The expression should return all processes where the process is less than or equal to the number of processes times 20. So if I have 104 processes, it should get all processes with an id of 2080 or less. Using the variable within the expression shows a result of 10. But actually, when I try this without relying on the variable I get many more processes.

PS C:\> $ps | where {$_.id -le 2080} | measure

Count    : 21
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

This is a great demonstration of the fact that PowerShell cmdlets (typically) process objects in batches and then hand them off to the next cmdlet. So in this case, Get-Process ran through 10 object and then passed them to Where-Object. By the time Where-Object started working, $ps only had 10 objects. That's not to say this will never work, you just have to be smart about it.

PS C:\> get-process -ov ps | sort id | where {$_.id -le $ps.count*20} | measure

Count    : 21
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

Now, by the time Where-Object starts to work, $ps is fully populated.

Finally, you can also append to the outvariable. You might start with a command like this:

PS C:\> get-service -comp dc01 -ov svc

Later, you re-run the command appending the results to $svc.

PS C:\> get-service -comp server1,server2 -ov +svc

The $svc variable now contains the results from all three computers. The primary thing to remember is that when you specify the variable name, you don't include the $.

I'll be back with more common parameter goodness next time.

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