Slide 1

Slide 1 text

WRITING ROBUST POWERSHELL CODE Guy Leech @guyrleech

Slide 2

Slide 2 text

WHOAMI • Wrote my first code (on Commodore PET) in 1980 (in BASIC) • Unix developer in C/C++ for 6 years after Comp Sci degree from University of Manchester • Started with Windows (NT 3.51) in 1995 via Citrix • Invented & wrote what is now Ivanti Application Control security product • Freelance consultant writing PowerShell for software vendors like ControlUp, Flexxible IT • Only been doing PowerShell (and C#) for 7 years but it's "just another language"Microsoft • MVP, Citrix CTP, VMware vExpert

Slide 3

Slide 3 text

WHY WRITE ROBUST CODE? • Less comeback • Fewer problems to rectify afterwards • Higher successful outcomes • Why not? Do it as you code, not "later" so becomes habit • Reputation • "Write it once, write it right" • It's a mindset

Slide 4

Slide 4 text

QUESTIONS ABOUT ERROR HANDLING • Does it benefit the user if the error is reported? • Is there anything that can be done to avoid/predict the error? • Is there anything that can be done to fix the error? • Is it a fatal error or can we continue (change to warning)? • Does the error message make sense to mere mortals? • Change the error text to display remedial action, KB references, etc • Can the user actually deal with raw errors?

Slide 5

Slide 5 text

ERRORS • Check for errors even if not obvious that has errored • Be Consistent • Expected errors (e.g. create folder when already exists) • If you explicitly ignore/hide an error have a comment saying why • Beware modules/cmdlets that output error to stdout • Or don't output errors at all or return status (and use Write-Host) • Zero can be error ($false) or success (ERROR_SUCCESS in Windows APIs)

Slide 6

Slide 6 text

CHECKING FOR ERRORS • Validate return values • $? • $error • Array • $error.Clear() • -ErrorVariable (works with –ErrorAction SilentlyContinue) • -PassThru • Extra checks, e.g. if folder creation, check folder created

Slide 7

Slide 7 text

EXCEPTIONS • Designed to simplify error checking • Compromise – 1x try catch around whole code vs try catch around everything • Can be ignored but is that wise? • Use $_ to examine exception in catch block • Catch specific exceptions if you are going to deal with them differently • catch [System.Management.Automation.DriveNotFoundException] • $_.Exception.gettype().FullName • Try catch finally – finally useful for tidy up like removing temp files • Beware error message containing "At line:1 char:1"

Slide 8

Slide 8 text

VARIABLES: STRONG TYPING & INITIALISATION • Declaring type helps catch static errors & helps intellisense • Script variables and parameters • Get type name from a variable via GetType().FullName • Declare and initialise to known value, typically $null or -1 • De-initialisation • Call Dispose(), Close() etc as relevant (Get-Member) • Set to $null when finished or even remove variable

Slide 9

Slide 9 text

ADDITIONALLY #1 • Comments (and update/delete them) • Meaningful variable names $i • $ErrorActionPreference = 'SilentlyContinue' Never! • But do use it on individual cmldlets as necessary/appropriate • $null and zero are different – which do you need to check for? –not ! • Check property exists before referencing if may be missing • If( $guysobject.PSObject.Properties[ 'SomeProperty' ] -$ne $null ) { • Invoke-SomeFunction –InputObject $guysobject.SomeProperty } • Use named parameters with full name, not positional or abbreviated • Sanity checks parameters as much as possible & give meaningful errors • No aliases in scripts, just use them interactively

Slide 10

Slide 10 text

ADDITIONALLY #2 • Check size of array before indexing in to it • [-1] for last item • Check not $null before using Count property • Watch for array flattening where single item not returned as array • Wrap in @() • Opposite – get an array when expecting single item • Select –First/-Last, depending on sort order and if appropriate • -is [array] • Use –as instead of [type] cast – soft fail • TryParse & TryParseExact methods • [string]::IsNullOrEmpty() • Use extra parentheses if makes it easier to read/understand • If you are copying & pasting the same chunk of code, you should use functions

Slide 11

Slide 11 text

TESTING • Different PowerShell versions (#requires –version) • Different environments • Different operating systems • Admin vs non-admin (#requires -runasadministrator) • Edge cases (what if the user has (stupidly) done …) • Different users • Clean profile • "What If" code walk throughs – what could fail?

Slide 12

Slide 12 text

AIDS • Set-StrictMode • PSScriptAnalyzer • ISE Steroids • Pester • Code review • Other people's code

Slide 13

Slide 13 text

REFERENCES • https://powershellexplained.com/2017-04-10-Powershell-exceptions- everything-you-ever-wanted-to-know • https://docs.microsoft.com/en- us/powershell/module/microsoft.powershell.core/about/about_functions_ad vanced_parameters?view=powershell-5.1 • https://github.com/PowerShell/PSScriptAnalyzer • https://powershell.one/isesteroids/quickstart/overview • https://gitgub.com/guyrleech

Slide 14

Slide 14 text

QUESTIONS