Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to work with embedded objects.
Microsoft Scripting Guy, Ed Wilson, is here. This morning I have my Zune 1.0 cranked up, and I am listening to some tunes. I have a nice cup of English Breakfast tea, and a warm croissant beside me. I also was able to score some homemade orange marmalade.
Anyway, a few years ago, the Scripting Wife and I were in Maui, Hawaii, and we took an early morning drive up a winding road. We entered clouds, and it seemed like it was raining. I thought about turning back because of the rain, but there was no good place to turn. Then we emerged from the clouds, and the view was way cool. Here is a picture:
It was like another world that was hidden by the clouds below. In some respect, that is the way embedded objects in Windows PowerShell objects appear.
Here is a basic example of embedded objects. When I use the Get-Process cmdlet to look at a specific process, such as Notepad, Windows PowerShell returns basic information. Often the information like that shown here is enough:
PS C:\> Get-Process notepad
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
85 8 1636 9800 113 0.05 6220 notepad
If I want to see more information, I pipe the resulting object to the Format-List cmdlet and select all of the properties:
PS C:\> Get-Process notepad | fl *
__NounName : Process
Name : notepad
Handles : 85
VM : 118321152
WS : 10035200
PM : 1675264
NPM : 8688
Path : C:\Windows\System32\notepad.exe
Company : Microsoft Corporation
CPU : 0.046875
FileVersion : 6.3.9600.16384 (winblue_rtm.130821-1623)
ProductVersion : 6.3.9600.16384
Description : Notepad
Product : Microsoft® Windows® Operating System
Id : 6220
PriorityClass : Normal
HandleCount : 85
WorkingSet : 10035200
PagedMemorySize : 1675264
PrivateMemorySize : 1675264
VirtualMemorySize : 118321152
TotalProcessorTime : 00:00:00.0468750
BasePriority : 8
ExitCode :
HasExited : False
ExitTime :
Handle : 3132
MachineName : .
MainWindowHandle : 2361006
MainWindowTitle : Untitled - Notepad
MainModule : System.Diagnostics.ProcessModule (notepad.exe)
MaxWorkingSet : 1413120
MinWorkingSet : 204800
Modules : {System.Diagnostics.ProcessModule (notepad.exe),
System.Diagnostics.ProcessModule (ntdll.dll),
System.Diagnostics.ProcessModule (KERNEL32.DLL),
System.Diagnostics.ProcessModule (KERNELBASE.dll)...}
NonpagedSystemMemorySize : 8688
NonpagedSystemMemorySize64 : 8688
PagedMemorySize64 : 1675264
PagedSystemMemorySize : 231168
PagedSystemMemorySize64 : 231168
PeakPagedMemorySize : 1675264
PeakPagedMemorySize64 : 1675264
PeakWorkingSet : 10072064
PeakWorkingSet64 : 10072064
PeakVirtualMemorySize : 118374400
PeakVirtualMemorySize64 : 2199141629952
PriorityBoostEnabled : True
PrivateMemorySize64 : 1675264
PrivilegedProcessorTime : 00:00:00.0468750
ProcessName : notepad
ProcessorAffinity : 255
Responding : True
SessionId : 1
StartInfo : System.Diagnostics.ProcessStartInfo
StartTime : 4/4/2015 1:39:29 PM
SynchronizingObject :
Threads : {4012}
UserProcessorTime : 00:00:00
VirtualMemorySize64 : 2199141576704
EnableRaisingEvents : False
StandardInput :
StandardOutput :
StandardError :
WorkingSet64 : 10035200
Site :
Container :
As you can see, the Modules, MainModule, and StartInfo objects contain other objects. As an example, here is the StartInfo object:
PS C:\> Get-Process notepad | select startinfo
StartInfo
---------
System.Diagnostics.ProcessStartInfo
I can look up the object on MSDN, but I am not sure if it is worth the trouble. I can also use what I call “group and dot.” All I need to do is put parentheses around the object, and select the StartInfo property. When I do this, I can see everything that is contained in the object. This is shown here:
PS C:\> (Get-Process notepad).startinfo
Verb :
Arguments :
CreateNoWindow : False
EnvironmentVariables : {ProgramW6432, Path, PROCESSOR_IDENTIFIER, TEMP...}
RedirectStandardInput : False
RedirectStandardOutput : False
RedirectStandardError : False
StandardErrorEncoding :
StandardOutputEncoding :
UseShellExecute : True
Verbs : {}
UserName :
Password :
Domain :
LoadUserProfile : False
FileName :
WorkingDirectory :
ErrorDialog : False
ErrorDialogParentHandle : 0
WindowStyle : Normal
One of the cool things I can do, is continue down the road. I can use a double dot (if you will), and select the WindowStyle property from the ProcessStartInfo object. Because I have already seen that (Get-Process notepad).StartInfo returns a ProcessStartInfo object, I know that I can return a single property from this object. This technique is shown here:
PS C:\> (Get-Process notepad).startinfo.WindowStyle
Normal
Windows PowerShell also has a built-in method of handling this situation. I can use the –ExpandProperty parameter from the Select-Object cmdlet. This is faster (for me) than using the “group and dot” technique because I do not have to back up on the command line. Here is the command:
PS C:\> Get-Process notepad | select -ExpandProperty startinfo
Verb :
Arguments :
CreateNoWindow : False
EnvironmentVariables : {ProgramW6432, Path, PROCESSOR_IDENTIFIER, TEMP...}
RedirectStandardInput : False
RedirectStandardOutput : False
RedirectStandardError : False
StandardErrorEncoding :
StandardOutputEncoding :
UseShellExecute : True
Verbs : {}
UserName :
Password :
Domain :
LoadUserProfile : False
FileName :
WorkingDirectory :
ErrorDialog : False
ErrorDialogParentHandle : 0
WindowStyle : Normal
This is good information, and it shows me what property contains, but it does not help me match it with the process name. What if I also want to see the process name? I specify the Property name in addition to the property I want to expand:
PS C:\> Get-Process notepad | Select -Property name -ExpandProperty startinfo
Name : notepad
Verb :
Arguments :
CreateNoWindow : False
EnvironmentVariables : {ProgramW6432, Path, PROCESSOR_IDENTIFIER, TEMP...}
RedirectStandardInput : False
RedirectStandardOutput : False
RedirectStandardError : False
StandardErrorEncoding :
StandardOutputEncoding :
UseShellExecute : True
Verbs : {}
UserName :
Password :
Domain :
LoadUserProfile : False
FileName :
WorkingDirectory :
ErrorDialog : False
ErrorDialogParentHandle : 0
WindowStyle : Normal
What if I am only interested in the WindowStyle property from the StartInfo object? I can create a custom property by using a hash table with the Select-Object cmdlet. This technique involves specifying a label and an expression. The label is a string, and it can be abbreviated as L. The expression is a script block, and can be abbreviated as E. Here is an example:
Get-Process notepad | select -Property name, @{L="Style";E={$_.startinfo.WindowStyle}}
When I run this, it returns the following custom object:
This will work for all processes, for a single process, and for other embedded objects.
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