3.2. Work with Structured ObjectsJust as a DateTime object has properties for year, month, day, and so on, so too do the other types we've already seen. The Process class includes process ID, name, and other information, and the get-process cmdlet generates a sequence of objects, one for each process running on a system, with each of these values set accordingly. It's not immediately obvious from the output of get-process how much information is lurking within these objects. Next, we'll see that there's far more than just process name and ID. Let's take a more detailed look at what these objects contain and howwith just the few cmdlets we've discussed so farthere's much more information waiting to be tapped.
3.2.1. How Do I Do That?With all of the information stored inside these objects, we need a guidesomething that will help us get more familiar with these new data structures we're working with . The get-member cmdlet is here to make life easier. With no parameters, it lists every detail about the object. For the following examples, we'll be focusing on the properties (the "public" values and settings). Therefore, we'll tell get-member to just return those: MSH D:\MshScripts> get-process | get-member -MemberType Property TypeName: System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- BasePriority Property System.Int32 BasePriority {get;} ExitCode Property System.Int32 ExitCode {get;} HasExited Property System.Boolean HasExited {get;} ExitTime Property System.DateTime ExitTime {get;} Handle Property System.IntPtr Handle {get;} HandleCount Property System.Int32 HandleCount {get;} Id Property System.Int32 Id {get;} MachineName Property System.String MachineName {get;} MainWindowHandle Property System.IntPtr MainWindowHandle {get;} MainWindowTitle Property System.String MainWindowTitle {get;} MainModule Property System.Diagnostics.ProcessModule MainM... MaxWorkingSet Property System.IntPtr MaxWorkingSet {get;set;} MinWorkingSet Property System.IntPtr MinWorkingSet {get;set;} Modules Property System.Diagnostics.ProcessModuleCollec... NonpagedSystemMemorySize Property System.Int32 NonpagedSystemMemorySize ... NonpagedSystemMemorySize64 Property System.Int64 NonpagedSystemMemorySize6... PagedMemorySize Property System.Int32 PagedMemorySize {get;} PagedMemorySize64 Property System.Int64 PagedMemorySize64 {get;} PagedSystemMemorySize Property System.Int32 PagedSystemMemorySize {get;} PagedSystemMemorySize64 Property System.Int64 PagedSystemMemorySize64 {... PeakPagedMemorySize Property System.Int32 PeakPagedMemorySize {get;} PeakPagedMemorySize64 Property System.Int64 PeakPagedMemorySize64 {get;} PeakWorkingSet Property System.Int32 PeakWorkingSet {get;} PeakWorkingSet64 Property System.Int64 PeakWorkingSet64 {get;} PeakVirtualMemorySize Property System.Int32 PeakVirtualMemorySize {get;} PeakVirtualMemorySize64 Property System.Int64 PeakVirtualMemorySize64 {... PriorityBoostEnabled Property System.Boolean PriorityBoostEnabled {g... PriorityClass Property System.Diagnostics.ProcessPriorityClas... PrivateMemorySize Property System.Int32 PrivateMemorySize {get;} PrivateMemorySize64 Property System.Int64 PrivateMemorySize64 {get;} PrivilegedProcessorTime Property System.TimeSpan PrivilegedProcessorTim... ProcessName Property System.String ProcessName {get;} ProcessorAffinity Property System.IntPtr ProcessorAffinity {get;s... Responding Property System.Boolean Responding {get;} SessionId Property System.Int32 SessionId {get;} StartInfo Property System.Diagnostics.ProcessStartInfo St... StartTime Property System.DateTime StartTime {get;} SynchronizingObject Property System.ComponentModel.ISynchronizeInvo... Threads Property System.Diagnostics.ProcessThreadCollec... TotalProcessorTime Property System.TimeSpan TotalProcessorTime {get;} UserProcessorTime Property System.TimeSpan UserProcessorTime {get;} VirtualMemorySize Property System.Int32 VirtualMemorySize {get;} VirtualMemorySize64 Property System.Int64 VirtualMemorySize64 {get;} EnableRaisingEvents Property System.Boolean EnableRaisingEvents {ge... StandardInput Property System.IO.StreamWriter StandardInput {... StandardOutput Property System.IO.StreamReader StandardOutput ... StandardError Property System.IO.StreamReader StandardError {... WorkingSet Property System.Int32 WorkingSet {get;} WorkingSet64 Property System.Int64 WorkingSet64 {get;} Site Property System.ComponentModel.ISite Site {get;... Container Property System.ComponentModel.IContainer Conta... Back to the output of get-process we saw earlier, it's clear that there is more information than the default view shows. For example, process names such as svchost and lsass can often be too cryptic to immediately understand their purpose. We can use a new cmdlet, select-object, to pick out a couple of interesting propertiesin this case, the process name and its longer description: MSH D:\MshScripts> get-process | select-object ProcessName,Description ProcessName Description ----------- ----------- alg Application Layer Gateway Service CcmExec CCM Executive cmd Windows Command Processor cmd Windows Command Processor csrss explorer Windows Explorer Idle lsass LSA Shell (Export Version) msh msh notepad Notepad notepad Notepad ntvdm NTVDM.EXE regedit Registry Editor services Services and Controller app smss Windows NT Session Manager ... As we've already seen, get-process can take a parameter for matching a process name; in this case, we'll specify msh. By enclosing the cmdlet and parameters in parentheses, we're now able to access properties on the object that it returns: MSH D:\MshScripts> (get-process msh).Threads BasePriority : 8 CurrentPriority : 8 Id : 1716 IdealProcessor : PriorityBoostEnabled : True PriorityLevel : Normal PrivilegedProcessorTime : 00:00:01.0414976 StartAddress : 2011608519 StartTime : 5/20/2005 4:26:17 PM ThreadState : Ready TotalProcessorTime : 00:00:04.7167824 UserProcessorTime : 00:00:03.6752848 WaitReason : ProcessorAffinity : Site : Container : BasePriority : 8 CurrentPriority : 8 Id : 1136 IdealProcessor : PriorityBoostEnabled : True PriorityLevel : Normal PrivilegedProcessorTime : 00:00:00 StartAddress : 2011608507 StartTime : 5/20/2005 4:26:17 PM ThreadState : Wait TotalProcessorTime : 00:00:00 UserProcessorTime : 00:00:00 WaitReason : UserRequest ProcessorAffinity : Site : Container : BasePriority : 10 CurrentPriority : 12 Id : 916 IdealProcessor : PriorityBoostEnabled : True PriorityLevel : Highest PrivilegedProcessorTime : 00:00:00.8412096 StartAddress : 2011608507 StartTime : 5/20/2005 4:26:17 PM ThreadState : Wait TotalProcessorTime : 00:00:03.9657024 UserProcessorTime : 00:00:03.1244928 WaitReason : UserRequest ProcessorAffinity : Site : Container : ... Now let's take a look at another set of data associated with each process: its Modules property, which is a collection of all of the assemblies and DLLs used by the process. Because that's probably going to be a long list, we'll use where-object to select just those that are greater than 5 MB in size: MSH D:\MshScripts> (get-process msh).Modules | where-object {$_.ModuleMemorySize -gt 5M} Size ModuleName FileName ---- ---------- -------- 5,076k mscorwks.dll C:\WINDOWS\Mic... 10,392k mscorlib.ni.dll C:\WINDOWS\ass... 8,256k shell32.dll C:\WINDOWS\sys... 7,696k System.ni.dll C:\WINDOWS\ass... 10,512k System.Xml.ni.dll C:\WINDOWS\ass... 6,776k System.Data.ni.dll C:\WINDOWS\ass... 3.2.2. What Just Happened?get-member is useful for finding out property names and values if you're not familiar with the class you're dealing with. Because Process objects have many properties and methods, we used the MemberType parameter to select just a subset. Feel free to explore the output when no member type is specified. You'll see how much information is available from a seemingly simple command. From what we saw in the previous section, it seems as though get-member should be run on every running process (since there will be a corresponding object for each in the pipeline). If that's the case, why did we see the properties only once? As get-member is commonly used on a stream of identical classes, its default behavior is to list only the members of a type it hasn't seen yet. If, for some reason, you need get-member to list for every type, this behavior can be overridden with the -ForEachObject option. select-object is a useful tool for simplifying objects as they pass through the pipeline. Given a number of properties of interest, it will take these from each object it sees and create a simple new object with just these fields. This can bring about performance gains (since the new objects are significantly smaller) and simplify downstream processing. Here we also see a new conceptthe idea of a collection. When dealing with the THReads property, instead of seeing just a single value (as we did with ProcessName, for example), we get back a sequence of objects, one for each of the threads in the process. These objects are put into the pipeline, in order, which means that we can now use the familiar, group-object, sort-object, and where-object cmdlets on this data. 3.2.3. What About......Supplying other properties to select-object? In the previous example, ProcessName and Description might not be the two most useful fields to select. By all means, feel free to pick out other properties to meet your own needs; any of the properties revealed by get-member are fair game: MSH D:\MshScripts> get-process | select-object Id,Name,Threads ...Using MSH to determine which processes are using a certain module? By combining a handful of cmdlets together, we can filter the Modules list to select just those processes that match specific criteria. Let's say we're interested in finding all processes using the Crypto API that is located in the file crypt32.dll. We use the -Expand option on select-object to break each process's Modules collection into separate ProcessModule objects. Instead of the whole Modules collection going into the pipeline in one big chunk, each of the ProcessModule objects will go through in turn (accompanied by the Id and ProcessName properties of the parent Process): MSH D:\MshScripts> get-process | select-object Id,ProcessName -Expand Modules | where-object {$_.ModuleName -eq "CRYPT32.dll"} | select-object Id,ProcessName Collections have properties that differ from those of the objects they contain. Looking back at the contents of the Threads property output, it's clear that there are a number of threads; we saw the details of each in turn. The option -InputObject on get-member can be used to inspect the THReads collection rather than the properties of the ProcessThread objects it contains: MSH D:\MshScripts> get-member -InputObject (get-process msh).Threads TypeName: System.Diagnostics.ProcessThreadCollection Name MemberType Definition ---- ---------- ---------- Count Property System.Int32 Count {get;} get_Item Method ProcessThread get_Item(Int32 index) Add Method Int32 Add(ProcessThread thread) Insert Method Void Insert(Int32 index, ProcessThread thread) IndexOf Method Int32 IndexOf(ProcessThread thread) Contains Method Boolean Contains(ProcessThread thread) Remove Method Void Remove(ProcessThread thread) CopyTo Method Void CopyTo(ProcessThread[] array, Int32 index) get_Count Method Int32 get_Count( ) GetEnumerator Method IEnumerator GetEnumerator( ) GetType Method Type GetType( ) ToString Method String ToString( ) Equals Method Boolean Equals(Object obj) GetHashCode Method Int32 GetHashCode( ) Note that we couldn't just do (get-process msh).Threads | get-member; that would have caused automatic expansion of the Threads collection, resulting in get-member showing the properties of the individual objects contained within. As it stands, we see that the Threads collection has a Count property that seems to be what we're looking for. Using the same dot notation as earlier, we can easily get a tally of the threads in use. Note that you might get a different number of threads when trying this on your own machinethat just shows that the expression is returning the number of threads running inside your MSH process: MSH D:\MshScripts> (get-process msh).Threads.Count 7 3.2.4. Where Can I Learn More?The built-in help for the two new commands we've covered in this section has further usage information: MSH D:\MshScripts> get-help get-member MSH D:\MshScripts> get-help select-object |