PowerShell (My) Best Practices
PowerShell is one of my favorite scripting languages, there are many reasons for this. The first is that it’s the language I know the best, it gets points for that. I like the modules that you can import, how it works with Task Scheduler for automated runs, and the fact that I can do most of a module’s function natively by writing my own code. I’ve written literally thousands of scripts over the years to basically take humans out of a tedious process. This allows standard operations to be automated, reducing the likelihood of human errors. The only downside is multithreading and some specific security and network-based operations that require or at least are easier to do in Python that are better documented. PowerShell is also made for linear execution not multithreading. I have only seen a need to multithread a few times for Infrastructure Management, and you can do it in PowerShell, but it gets complicated fast.
Import Modules at the top of the script. This lets you know what modules are available so you can choose the cmdlets you want to run later.
Variables should be placed under the modules so that you can call them as needed. Having them at the top makes them easier to change without hunting through the body.
I rarely define variables in the body that will regularly change. Those stay at the top. Dynamic values from a
.csvor.jsonlive in the body.Create Functions under the Variables where appropriate so you can reuse code without duplicating it.
When you need to connect to services such as M365 or Remote PowerShell, put the connection code next. Get the logons done before the work starts.
Script as you will not be the person running it or who understands what it does.
Less is more. Most of the time you just need it to do a function well.
Error checking for production scripts. I don’t waste time on scripts only I run. If another user or process runs it, I log failures to a database or a
.csv.
The layout below is a guide. The code doesn’t do anything useful on purpose.
## Modules
Import-Module WhateverModuleYouWant
## Variables
$TestVar1 = "Testing1"
$TestVar2 = "Testing2"
$outputFile = "C:\Errors.csv"
$errorList = @()
## Functions
function TestFunction {
param (
$Test,
$Test123 = "Testing 123"
)
}
## Connect to Services
$CredM365 = Connect-ExchangeOnline
## Start Script Body
try {
$Testing = TestFunction -Test 123456
} catch {
$errorDetails = [PSCustomObject]@{
TimeStamp = Get-Date
Message = $_.Exception.Message
}
$errorList += $errorDetails
}
if ($errorList.Count -gt 0) {
$errorList | Export-Csv -Path $outputFile -NoTypeInformation -Force
Write-Output "Errors have been logged to $outputFile"
} else {
Write-Output "No errors occurred."
}GitHub: Public scripts live in Technolitero/Powershell-Public↗.