Slide 1

Slide 1 text

WRITING ROBUST POWERSHELL CODE Guy Leech @guyrleech

Slide 2

Slide 2 text

whoami /user • Wrote my first code (on Commodore PET) in 1980 (in BASIC) • Unix developer in C/C++ for 6 years after graduation from University of Manchester (Comp Sci) • Started with Windows (NT 3.51) in 1995 via Citrix (installed via 35 floppies!) • Invented & wrote what is now Ivanti Application Control security product (was AppSense) • Freelance consultant writing PowerShell for software vendors like ControlUp, Flexxible IT, PolicyPak • Microsoft MVP, Citrix CTP, VMware vExpert, Parallels VIPP • Master of Dad jokes @guyrleech Slide 1 of 0xdead

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" @guyrleech

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? @guyrleech

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) @guyrleech

Slide 6

Slide 6 text

Checking for Errors • Validate return values • Abort, abort, abort! • $? • $error • Array • $error.Clear() • -ErrorVariable (works with –ErrorAction SilentlyContinue) • -PassThru • Extra checks, e.g. if folder creation, check folder created @guyrleech

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" @guyrleech

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 @guyrleech

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 cmdlets 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($null -ne $guysobject.PSObject.Properties[ 'SomeProperty' ] ) { • 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, only use them interactively (or for tweets) @guyrleech

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 • -is [array] • Use –as instead of [type] cast • 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 @guyrleech

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 • "What If" code walk throughs @guyrleech

Slide 12

Slide 12 text

Aids • Set-StrictMode • PSScriptAnalyzer • ISE Steroids • Pester • Code review • Other people's code @guyrleech

Slide 13

Slide 13 text

References • Guy’s In Person PowerShell Workshops • 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_advance d_parameters?view=powershell-5.1 • https://github.com/PowerShell/PSScriptAnalyzer • https://powershell.one/isesteroids/quickstart/overview • https://github.com/guyrleech @guyrleech

Slide 14

Slide 14 text

Questions @guyrleech