Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PowerShell Performance Tips

PowerShell Performance Tips

Guy shared from his five decades of software development experience to show tips and techniques on how to write efficient yet readable PowerShell code. Showing what is good, bad and ugly especially when looping and also how to use various collection types for data caching.

From the 45 minute session given at the PS Day UK conference in London, 3rd
March, 2023

Guy Leech

March 06, 2023

More Decks by Guy Leech

Other Decks in Technology


  1. @guyrleech Guy Leech • Freelance consultant writing PowerShell for software

    vendors like ControlUp, Flexxible, Avanite, Netwrix, Parallels (Alludo) • Wrote my first code (on Commodore PET) in 1980 (in BASIC) • Unix developer in C/C++ for 6 years after graduation • Started with Windows (NT 3.51) in 1995 via Citrix • Invented & wrote what is now Ivanti Application Control security product
  2. @guyrleech Loops  Don't keep evaluating/fetching/setting the same thing 

    Do you need Write-Verbose, Write-Progress etc on every iteration?  .Where (collections) versus Where-Object  ForEach versus ForEach-Object versus .ForEach (collections)  . { Process { } }  Start-Sleep – consider the impact of the script on your environment  Reduce the process' base priority  (Get-Process –id $pid).PriorityClass = 'BelowNormal'
  3. @guyrleech +=  For arrays and strings, takes a complete

    copy of existing object  Can get slow for large items  It is ok for hashtables  Arrays  Assign results to an array rather than adding to it within the loop  Wrap in @( ) to avoid PowerShell's "helpful" array flattening "feature"  Instead use System.Collections.Generic.List[object] which has Add/Remove methods  Iterate backwards if calling Remove()  Do not use System.Collections.ArrayList  Strings  $oldstring = $oldstring + $newstring  $oldstring = "$oldstring$newstring"  $oldstring = -join ( $oldstring , $newstring )
  4. @guyrleech Caching Data  Is it quicker/cheaper/safer to keep in

    memory than look up individually/once?  Get-ADUser  Get-BrokerMachine  But what is the memory overhead?  Be selective what properties are cached  Trim own working set  Destroy unused data/variables  [gc]::Collect()  Hashtable or array ?  Unique key ?  Hashtable of arrays  Sort ?  Most likely to be accessed near the start  Binary search via index ?  Number of elements  .Where() versus Where-Object  .Where takes optional count x, for where-object pipe through Select-Object –First x  [System.Management.Automation.WhereOperatorSelectionMode]  .Where always returns a collection
  5. @guyrleech Caching Commands How long does it take PowerShell to

    find a command? Always use Import-Module in scripts in case of new/non- persistent profile In a loop, it can add time locating command Could module qualify (also helps avoid ambiguity/incorrect cmdlet use)  VMware.VimAutomation.Core\Get-VM versus Hyper-V\Get-VM Get-Command Call with . or &
  6. @guyrleech Parallelisation Can the tasks be split into separate, unrelated,

    activities? Pwsh 7.x has ForEach-Object –Parallel  3rd party module available for Windows PowerShell Windows PowerShell has Invoke-Command –ComputerName  Can use localhost  Needs remoting configured Jobs Runspaces  Not as scary as you might think!  Take some working code (give credit) and modify
  7. @guyrleech But Is Performance Important? Not usually Nowhere near as

    important as (correct) functionality Does taking 15 minutes instead of 5 really matter? How much time/money will it take to make it significantly faster? Do not run scripts on key infrastructure servers use a jump box Think about performance when writing code Expressions evaluated left to right in an if statement Filter as far left as possible
  8. @guyrleech Measuring Performance Measure-Command Once is not enough Watch for

    file system caching and other optimisations Get-Date [Diagnostics.Stopwatch] Guy's clock/stopwatch PSProfiler