System administration has always been Windows' Achilles' heel. The graphical tools that simplify basic chores just get in the way when there's heavy lifting to be done. And CMD.EXE, the hapless command shell, pales in comparison to the Unix shells that inspired it. Win32 Perl has been my ace in the hole, combining a powerful scripting language with extensions that can wield Windows' directory, registry, event log, and COM services. But I've always thought there should be a better way.
Jeffrey Snover thought so, too. He's the architect of Monad, aka MSH (Microsoft Shell), the radical new Windows command shell first shown at the Professional Developers Conference last fall.
...
MSH is quirky, complex, delightful, and utterly addictive. You can, for example, convert objects to and from XML so that programs that don't natively speak .Net can have a crack at them. There's SQL-like sorting and grouping. You write ad hoc extensions in a built-in scripting language that feels vaguely Perlish. For more permanent extensions, called cmdlets, you use .Net languages.
With MSH, Windows system administration manages to be both fun and productive. And the story will only improve as the .Net Framework continues to enfold Windows' management APIs. Competitors take note: Windows is about to convert one of its great weaknesses into a strength. [Full story at InfoWorld.com]
Here's a sequence of examples to give you a bit of the flavor of MSH. First, a raw process dump:
MSH> get-process Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 105 5 1224 88 32 0.11 1956 alg 41 2 816 180 23 0.09 1340 aspnet_admin 69 3 2336 68 36 0.86 760 cmd 35 2 860 148 27 0.23 1352 Crypserv 539 6 1868 2312 27 44.89 556 csrss 100 5 960 1308 29 1.30 1252 ctfmon ...etc...
The console output doesn't show everything that's in the returned set of System.Diagnostics.Process objects, but here's one way to see more:
MSH> get-process | get-member -p Class Name MemberData ----- ---- ---------- Property __NounName System.String Property BasePriority System.Int32 Property Company System.Management.Automation.MshObject Property Container Property CPU System.Management.Automation.MshObject Property Description System.Management.Automation.MshObject ...etc...
Alternatively:
MSH> get-process | out-grid
Or:
MSH> get-process | out-excel
Here are processes using more than 15MB of virtual memory:
MSH> get-process | where { $_.virtualmemorysize -gt 150000000} Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 2411 89 74680 42572 211 1,176.00 396 firefox 395 11 32720 14848 272 79.89 3504 msh 484 18 30180 16012 235 337.41 2068 OUTLOOK 398 16 19172 1220 173 12.33 3636 WINWORD
Grouped by vendor:
MSH> get-process | where { $_.vs -gt 150000000} | group-object company Count Name Group ----- ---- ----- 1 Mozilla {firefox} 1 - {msh} 2 Microsoft Corporation {OUTLOOK, WINWORD}
Just selected properties:
MSH> get-process | where { $_.vs -gt 150000000} | pick-object name, path, id, vs name path id vs ---- ---- -- -- firefox C:\\firefox.09\\fi... 396 220983296 msh C:\\Program Files... 3504 285908992 OUTLOOK C:\\PROGRA~1\\MICR... 2068 245936128 WINWORD C:\\Program Files... 3636 181805056
Ordered by virtual memory size:
MSH> get-process | where { $_.vs -gt 150000000} | pick-object name, path, id, vs | sort-object vs -d name path id vs ---- ---- -- -- msh C:\\Program Files... 3504 285908992 OUTLOOK C:\\PROGRA~1\\MICR... 2068 245936128 firefox C:\\firefox.09\\fi... 396 220983296 WINWORD C:\\Program Files... 3636 181805056
Results assigned to a variable:
MSH> $v = get-process | where { $_.vs -gt 150000000} | pick-object name, path, id, vs | sort-object vs -d MSH> $v name path id vs ---- ---- -- -- msh C:\\Program Files... 3504 285908992 OUTLOOK C:\\PROGRA~1\\MICR... 2068 245936128 firefox C:\\firefox.09\\fi... 396 220983296 WINWORD C:\\Program Files... 3636 181805056 MSH> $v[0].id 3504
Results as XML:
MSH> get-process | pick-object name,vs | where { $_.vs -gt 150000000} | convert-xml <?xml version="1.0" encoding="utf-16" standalone="yes"?> <MshObjects xmlns="http://msh"> <MshObject ReferenceID="ReferenceId-0" Version="1.1" xmlns="http://schemas.microsoft.com/msh/2004/04"> <MemberSet> <Note Name="name" IsHidden="false" IsInstance="true" IsSettable="true"> <string>firefox</string> </Note> <Note Name="vs" IsHidden="false" IsInstance="true" IsSettable="true"> <int>220983296</int> </Note> </MemberSet> </MshObject> ...etc...
Preview a request to kill processes using more than 20MB of virtual memory:
MSH> get-process | where { $_.vs -gt 200000000} | stop-process -whatif # stop-process on firefox (Mozilla Firefox) # stop-process on msh (Windows command shell preview) # stop-process on OUTLOOK (Inbox - Microsoft Outlook)
Former URL: http://weblog.infoworld.com/udell/2004/11/02.html#a1106