header image

Scripting Games 2012 Comments: #3 Beginners Event 1

Posted by: | April 11, 2012 | No Comment |

I thought I’d publish a series on how I would go about solving these plus some comments and observations on the submitted scripts.

First event of the games


Firstly pick out the salient points of the event

Need to:

  • Identify Top 10 processes consuming memory resources on each computer
  • Decided that working set is the property to measure
  • Don’t need a script – implies a single pipeline will be acceptable
  • Should be capable of running remotely – not required to have multiple computers available
  • Aliases are acceptable – not compulsory though (we’ll come back to that statement)
  • Should return an object
  • Should be able to write results to file (but not a requirement)
  • Computers are Windows 7 & Windows 2008 R2
  • Single AD domain
  • Remoting is enabled

What do we have that can work with processes:

PS> Get-Command *process

CommandType     Name
———–     —-
Cmdlet          Debug-Process
Cmdlet          Get-Process
Cmdlet          Start-Process
Cmdlet          Stop-Process
Cmdlet          Wait-Process


Get-Process should work for us but it returns a whole bunch of processes and none of them are labelled working set! If we need to be able to find the top 10 working set consumers then need to be able to sort on working set

Time to use Get-Member

PS> Get-Process | Get-Member w* -MemberType property

   TypeName: System.Diagnostics.Process

Name         MemberType Definition
—-         ———- ———-
WorkingSet   Property   System.Int32 WorkingSet {get;}
WorkingSet64 Property   System.Int64 WorkingSet64 {get;}

One thing to be aware of is that sometimes the PowerShell team alias property names to make life easier for us. You also need to be aware that the column WS (K ) is workingset recast to kb instead of bytes

PS> Get-Process | Get-Member w* -MemberType aliasproperty

   TypeName: System.Diagnostics.Process

Name MemberType    Definition
—- ———-    ———-
WS   AliasProperty WS = WorkingSet


So we have a choice –  Workingset or WS its alias. Also we have to assume that the boss meant workingset even on 64 bit machines where WorkingSet64 may be a better answer

So lets sort on workingset

Get-Process | sort Workingset

This gives us the processes sorted in ascending order of working set usage. At this point we could just select the last 10

Get-Process | sort Workingset | select -Last 10

but that still leaves the results in ascending order which isn’t the way we usually look at things. So lets turn it round

Get-Process | sort Workingset -Descending | select -First 10

This gives us the top 10 consumers of working set on the local machine.

I have used aliases for sort-object (sort) and select-object (select) for a couple of reasons:

  • its easier
  • its still simple to read
  • its less typing
  • its accepted convention

I have left the rest of the script as full names so that if I save as script I can still read it.  Aliases are great at the command line if, and only if, you can remember them. Its better to use the full name and get the job done compared to hunting for the alias because its interactive work and some one says use aliases at the prompt.

If you are learning PowerShell stick with the full names (tab completion is a big help) until you are confident with a cmdlet – then introduce using aliases BUT ONLY FOR INTERACTIVE WORK.

So we can get the result for the local machine.  What about writing to a file?

Couple of ways to do that

Get-Process | sort Workingset -Descending | select -First 10 | Out-File top10proc.txt

gives the results in a text file – viewable with

Get-Content top10proc.txt

or use a csv file

Get-Process | sort Workingset -Descending | select -First 10 | Export-Csv top10proc.csv -NoTypeInformation
Import-Csv top10proc.csv

But notice you get the process information back formatted as a list with ALL of the properties presented.

If you want to be very clever here use tee-object which sends objects to a file and along the pipeline

Get-Process | sort Workingset -Descending | select -First 10 | Tee-Object -FilePath top10proc.txt

You get the display on screen and the data saved in a file

What about remote systems?

All your machines are in a domain for which you are the admin so presumably you have suitable permissions across all systems. Plus all machines are Windows 7 or Windows 2008 R2 so have PowerShell v2 available AND remoting is enabled.

There are two ways to approach this:

  • use the –computername parameter on get-process
  • use PowerShell remoting – probably invoke-command because we are only visiting a machine once

When you use the computername parameter and attempt to access the local machine there are three ways of accessing it without typing the name

Get-Process -ComputerName . | sort Workingset -Descending | select -First 10
Get-Process -ComputerName localhost | sort Workingset -Descending | select -First 10
Get-Process -ComputerName $env:COMPUTERNAME | sort Workingset -Descending | select -First 10

The second one doesn’t work on Windows 7 but does work on Windows 2008 R2.  There are other cmdlets that have problems with localhost so I advise against using it. My preference is to use $env:COMPUTERNAME

You might try this

"Win7", "Win7Test", "WebR201" |
Get-Process |
sort Workingset -Descending |
select -First 10

Note its still one pipeline – just split across multiple lines to make reading easier

But you’ll get an error

Get-Process : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of
the parameters that take pipeline input.

The problem is that the computername will only take pipeline input based on property name – so it expects an object that will have a computername property.

PS> get-help Get-Process -Parameter computername

-ComputerName <string[]>
    Gets the processes running on the specified computers. The default is the local computer.

    Type the NetBIOS name, an IP address, or a fully qualified domain name of one or more computers. To specify the loc
    al computer, type the computer name, a dot (.), or "localhost".

    This parameter does not rely on Windows PowerShell remoting. You can use the ComputerName parameter of Get-Process
    even if your computer is not configured to run remote commands.

    Required?                    false
    Position?                    named
    Default value
    Accept pipeline input?       true (ByPropertyName)
    Accept wildcard characters?  false

You can get round that like this

Get-Process -ComputerName "Win7", "Win7Test", "WebR201" 
sort Workingset -Descending |
select -First 10

but you then hit the problem that you can’t differentiate the results from each machine.

You also need to have a number of services running on the remote machine including the Remote Registry service AND the firewall configured to allow remote management.

This is starting to get messy.

Remember that remoting was enabled across the domain. This means we can do this

Invoke-Command -ComputerName "Win7", "Win7Test", "WebR201"  -ScriptBlock {
Get-Process |
sort Workingset -Descending |
select -First 10 }

Still a single pipeline.  The big advantage is that we get a property – PSComputerName – tacked onto the output that enables us to decide on the source of the data. That should answer all of requirements in the event. The computer names could be fed to Invoke-Command through a file or pipeline.

Change the script to this

Invoke-Command -ComputerName "Win7", "Win7Test", "WebR201"  -ScriptBlock {
Get-Process |
sort Workingset -Descending |
select -First 10 } |
Format-Table -GroupBy PSComputerName –AutoSize

and you have a nicely formatted output. Push that to a file

Invoke-Command -ComputerName "Win7", "Win7Test", "WebR201"  -ScriptBlock {            
Get-Process |            
sort Workingset -Descending |             
select -First 10 } |            
Format-Table -GroupBy PSComputerName -AutoSize |            
Out-File top10proc.txt

and you have a report ready to give to the boss.

Jobs a goodun!

Oh you want aliases.  Well if you must

icm -Cn "Win7", "Win7Test", "WebR201"  -Sc {

ps |

sort WS -Des |

select -F 10 }

trying to alias or abbreviate parameters can be problematic because the abbreviation must be resolvable unambiguously. Unless you really know the parameters on a cmdlet it can be confusing and take extra time to get right – its why I never bother and just use tab completion!

under: PowerShell User Group, Scripting Games