Prof. Powershell
Fanfare for the Common Parameter Part 3: Success
The third part of the common parameter series will look at saving PowerShell commands.
- By Jeffery Hicks
- 07/09/2013
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.