Monthly Archives: August 2014

PowerShell for monitoring proces memory usage

Here is a small bit of PowerShell that monitors the memory usage of a process and outputs the results in a CSV format in the locale of your choosing. I needed this because the sysadmins disabled perfmon and I really wanted to import the raw data into Excel to produce some graphs.

You can use it as follows

PS> Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
PS> Monitor-Process -Interval 30 -Locale 'nl-NL' -ProcessName winword | Tee-Object -Append -FilePath C:\Temp\test.txt
-OR-
PS> Monitor-Process -Interval 30 -Locale 'nl-NL' -ProcessId 5800 | Tee-Object -Append -FilePath C:\Temp\test.txt

function Format-MemoryAsCSV
{
  [CmdletBinding(SupportsShouldProcess=$false)]   
  param  
  (   
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Proces to get/format memory from")]    
    [Alias("Process")]    [ValidateNotNull()]    
    $InputObject,
    
    [Parameter(Mandatory=$false, HelpMessage="Which locale to use when formatting numbers (en-US, nl-NL")]
    $Locale = [System.Threading.Thread]::CurrentThread.CurrentCulture.Name 
  )
   process 
   {
            $localeObject = new-object CultureInfo($Locale)
            $Separator = $localeObject.TextInfo.ListSeparator
            $item = Get-Item $InputObject -ErrorAction SilentlyContinue
            $PrivateMemorySize64 = [math]::round($_.PrivateMemorySize64/ 1MB,1).ToString($localeObject ) #Total amount of memory allocated to proces. I.e.. RAM + pagefile. Excludes sharedlibs
            $VirtualMemorySize64 = [math]::round($_.VirtualMemorySize64/ 1MB,1).ToString($localeObject ) #total virtual address space of the process
            $WorkingSet64        = [math]::round($_.WorkingSet64/ 1MB,1).ToString($localeObject ) #Amount of memory thats held in physical RAM chips
            Write-Output "$([DateTime]::Now.ToString($localeObject))$($Separator)$($_.Id)$($Separator)$($_.Name)$($Separator)$($PrivateMemorySize64)$($Separator)$($VirtualMemorySize64)$($Separator)$($WorkingSet64)" 
     }
}

function Monitor-Process
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param  
    ( 
    [Parameter(Mandatory=$false, HelpMessage="NUmber of seconds between samples")]     
    $Interval  = 30,

    [Parameter(Mandatory=$false, HelpMessage="Which locale to use when formatting numbers (en-US, nl-NL")]
    $Locale = [System.Threading.Thread]::CurrentThread.CurrentCulture.Name, 
  

    [Parameter(parametersetname="ByName")]
    [Parameter( Mandatory=$false, HelpMessage="Name of the process(es) to monitor")]
    $ProcessName,

    [Parameter(parametersetname="ByPID")]
    [Parameter(Mandatory=$false, HelpMessage="PID of the process to monitor")]
    $ProcessId
    
    )

    process
    {
        do
        {
            switch ($PsCmdlet.ParameterSetName)
            {
                "ByName" {  Get-Process -Name $ProcessName -ErrorAction SilentlyContinue  | Format-MemoryAsCSV -Locale $Locale }
                "ByPID"  {  Get-Process -Id   $ProcessId   -ErrorAction SilentlyContinue  | Format-MemoryAsCSV -Locale $Locale }
            }

            [System.Threading.Thread]::Sleep(1000 * $Interval)
        } while ($true)
    }
}

PowerShell for recursive file and directory listings with MD5 hashes

The other day I needed to know if the files in a specific directory structure on different systems were identical or different. Many tools exist for doing file and directory comparisons but the challenge here was that each system was locked-down, no installation of software was possible. And even worse, we needed to compare at least 3 different machines that couldn’t reach each others drives or shares. Instead of hunting around to find which one of the many tools would work in this environment I thought that Windows Powershell should be able to do this quite easily. In fact, it turned out to be so easy that just finding another tool would have taken much longer.

The script uses the Get-ChildItem cmdlet to recursively get each file/directory in the form of a System.IO.FileInfo or System.IO.DirectoryInfo object. We calculate the MD5 hash using the ComputeHash() method of the System.Security.Cryptography.MD5CryptoServiceProvider class. We simply write the hash and some interesting fields as a CSV string to the output.

Here’s the bits of code glued into a single script.

function Get-MD5
{
  [CmdletBinding(SupportsShouldProcess=$false)]
  param
  (
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="file(s) to create hash for")]
    [Alias("File", "Path", "PSPath", "String")]
    [ValidateNotNull()]
    $InputObject
  )
 
  begin
  {
     $hasher = new-object System.Security.Cryptography.MD5CryptoServiceProvider
  }
 
  process
  {
    $hashBytes = ''

    $item = Get-Item $InputObject -ErrorAction SilentlyContinue
 
    if ($item)
    {
      $InputObject = $item
    }
 
    if ($InputObject -is [System.IO.FileInfo])
    {
      $stream    = $null;
      $hashBytes = $null
 
      try
      {
        $stream     = $InputObject.OpenRead();
        $hashBytes  = $hasher.ComputeHash($stream);
      }
      finally
      {
        if ($stream -ne $null)
        {
          $stream.Close();
        }
      }
    }

 
    Write-Output ([BitConverter]::ToString($hashBytes)).Replace("-",'')
  }
}

function Get-FilesWithHash
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param
    (
        [string]$Directory,
        [switch]$Recurse
    )
 

    Get-ChildItem -Path $Directory -Recurse:$Recurse | foreach {
        $item = $_
        $hash = ''
        if (!$_.PSIsContainer) 
        {
            $hash = Get-MD5 $_    
        }
        else
        {
            $hash = ''
        }
        Write-Output "$($item.FullName),$hash,$($item.Length),$($item.CreationTime),$($item.LastWriteTime)" 
        
    }
}