Expert Commentary: 2012 Scripting Games Beginner Event 1

Expert Commentary: 2012 Scripting Games Beginner Event 1

  • Comments 6
  • Likes

Summary: Microsoft Windows PowerShell MVP, Thomas Lee, provides expert commentary for 2012 Scripting Games Beginner Event 1.

Microsoft Scripting Guy, Ed Wilson, is here. Thomas Lee is the expert commentator for Beginner Event 1.

Photo of Thomas Lee

Thomas is an IT Pro with over 40 years experience. He’s a WindowsPowerShell MVP, and he is very busy writing, consulting, and training for some of the key Microsoft technologies, including Windows PowerShell, Lync, and Windows Server and client. In his spare time, he lives in a small cottage in the UK with his wife, daughter, and a nice wine cellar. He has a large collection of Grateful Dead live recordings (which are managed, of course, by using Windows PowerShell).

Blogs:

Under The Stairs

PowerShell Scripts Blog

Twitter: @doctordns

I really enjoy the annual Scripting Games contest. It is an opportunity to show off one’s scripting skills and learn some things in the bargain. As a judge, I cannot enter, but I still get a chance to see what other folks manage to make of each of the tasks. I love looking at how others solve the various problems, and I often learn myself!

When coming up with a solution to the scripting games events, there are a couple of aspects you need to think about. First, especially for the beginner category, it is important that your solution do what your boss wanted. In this first task, the boss wants a list of processes, so getting a list of services would be of little use.

At the same time, it is worthwhile thinking about what the boss wants, as opposed to what he asked for. And while doing that, you should be thinking about reuse and modularity. If your solution can be generalized, perhaps it can be reused in other situations.

And finally, you have to look at all the ways you could solve the problem, and come up with the quickest solution.

The Event

This event asks you to get a list of the 10 processes on a given machine, that are consuming the most memory. This raises two questions: “How do I get the processes?” and “How do I determine which property to use to ascertain memory use (because there are several)?” 

There are at least three ways to get a list of processes running on a given machine:

  • Use WMI: Use Get-WMIObject and specify the class Win32_process
  • Use native .NET: Use [System.Diagnostics.Process]::GetProcesses
  • Use a built-in cmdlet: Use the Get-Process cmdlet

All three of these mechanisms can be used to get all the processes. The objects returned by all three methods will enable you to sort by the memory used and then select the highest 10. So which is the best answer?

Developing the solution

You could use Get-WMIObject, but that might be more work (and as it turns out, the formatting would be more difficult, as I explain below). You could also use the GetProcesses() .NET Method, but that method does not provide an easy way to work against remote machines (the other two mechanisms provide a simple way to operate against any computer in your domain). But wherever possible, I tend to try to use the built-in cmdlets. Hence, I would choose to use Get-Process to get the processes.

Get-Process uses the ComputerName property to get the list of processes from a given machine (the default is the local host). Get-WmiObject also provides a ComputerName property, and it also provides a Credential property to enable you to use alternate credentials. If the environment includes computers in a different forest, or non-domain joined computers, you might be better off using Get-WMIObject to get the list of processes, but the directions did not give any clues about this point.

Another thing to note: The output that is specified in the Event details is very familiar. It’s the output generated by Get-Process. In this case, Windows PowerShell comes with some default display XML that formats the System.Diagnostics.Process objects into the nice eight-column format noted in the event instructions. You could use a set of hash tables plus a call to Format-Table to format the objects that are returned by the sorting the results returned from the Get-WMIObject cmdlet. Or you could use the default formatting that comes with Windows PowerShell.

So all things considered, I would use Get-Process to get the processes we need to examine. If the requirement changed, you might need to revisit this decision. For example, if the computers you want to examine are not in your domain, you may need to use WMI, or perhaps Windows PowerShell remoting, to get to the remote machines’ specific alternate credentials.

So if we use Get-Process to get the processes, how do we determine which processes are using the most memory? Windows has several memory counters that measure various aspects of memory usage (however, a complete discussion is beyond the scope of this blog). But in this case, your boss has decided he wants you to use WorkingSet as the counter. The working set value measures the amount of physical memory that a process is using.

Solution

So using all this, we can formulate a solution as follows:

Get-Process * | Sort-Object –Property WS –Descending | Select –First 10

This set of commands gets all the processes on your machine and sorts them by the WS (WorkingSet) property. Then we select the first ten (that is, those ten with the largest working set size). On my machine, this looks something like this:

Image of command output

This simple pipeline can be adjusted to point to a different computer by using the Computer property in with Get-Process, such as this:

Get-Process * -computer <computername> | Sort-Object –Property WS –Descending | Select –First 10

On my machine, this looks something like this:

Image of command output

Advanced solution

There is one further thing that you could do with this solution.  Given that there are two ways to get this list (local and remote), you could write a function like this:

Function Get-MemoryConsumingProcesses {
Param ($computer)
If ($computer) {
  Get-Process * -computer $computer | Sort-Object –Property WS –Descending |
     Select –First 10
} Else {
  Get-Process * | Sort-Object –Property WS –Descending | Select –First 10
}
}

The basic one-liner scripts (those with and without a Computer parameter) work just fine. But you might get an extra point if you modularized the solution as I showed here.

~Thomas

The 2012 Scripting Games Guest Commentator Week will continue tomorrow when we will present the scenario for Event 2.

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 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • I'm just curious as to why you're using a wildcard (*) after Get-Process; it looks like it doesn't affect the output either way.

  • @Andrew - I was wondering the same thing LOL.

  • I lost a point on my entry because I did not use invoke-expression.  If $computer is an array of computer names, then it will not return the top 10 processes on each remote machine but rather the top 10 processes on all of the machines combined.  Does this mean the expert solution loses a point too? :)

  • @clbarnett Design point also says "no need to write a script for this event" and "can be done with a one-liner"... So another point lost? ;)

  • @Dawn  Nope, I did submit a one-liner, basically identical to the one-liner above, and got a point deducted for not using invoke-expression.  But don't get me wrong, I was very glad to get the feedback!  It was one of those 'Doh, how did I miss that?' moments.

  • Get-Process cmdlet doesn't have a -Credential parameter, hence sometimes it gives error on connecting a remote machine, even if on the same domain. I faced with the same issue, and it can be resolved using Invoke-Command cmdlet instead. Refer to this : http://serverfault.com/questions/452856/powershell-get-process-cannot-connect-to-remote-computer/452860#452860?newreg=869ed768939546bcbb87cb2c91534504