Safe automation
Support -WhatIf in your own functions, use the output streams, catch mistakes with strict mode, and keep secrets safe.
- Make your functions support -WhatIf and -Confirm with SupportsShouldProcess
- Use the verbose, warning and information streams, and redirect them
- Catch mistakes early with Set-StrictMode, PSScriptAnalyzer and Pester, and handle credentials safely
Automation multiplies mistakes as easily as it multiplies work. PowerShell has unusually good guard rails - use them.
-WhatIf for your own functions. Add SupportsShouldProcess to [CmdletBinding()] and wrap every change in if ($PSCmdlet.ShouldProcess(target, action)) { ... }. Your function instantly gains -WhatIf and -Confirm, and it passes them on to the cmdlets it calls.
1function Remove-OldFeedLog {
2 [CmdletBinding(SupportsShouldProcess)]
3 param([Parameter(Mandatory)][string[]]$Name)
4 foreach ($log in $Name) {
5 if ($PSCmdlet.ShouldProcess($log, 'Delete feeding log')) {
6 "deleted $log"
7 }
8 }
9}
10Remove-OldFeedLog -Name 'monday.csv', 'tuesday.csv' -WhatIf
11Remove-OldFeedLog -Name 'monday.csv'What if: Performing the operation "Delete feeding log" on target "monday.csv". What if: Performing the operation "Delete feeding log" on target "tuesday.csv". deleted monday.csv
Six output streams
Results aren’t the only thing a command can produce. PowerShell has numbered streams, each with its own cmdlet:
| # | Stream | Write with | Shown by default? |
|---|---|---|---|
| 1 | Success (output) | Write-Output / bare values | yes |
| 2 | Error | Write-Error | yes |
| 3 | Warning | Write-Warning | yes |
| 4 | Verbose | Write-Verbose | only with -Verbose |
| 5 | Debug | Write-Debug | only with -Debug |
| 6 | Information | Write-Information (and Write-Host) | Write-Host: yes |
Sprinkle Write-Verbose through advanced functions: silent normally, a detailed narrative with -Verbose. Redirect streams like this: 3> warnings.txt, 2>&1 (errors into output), *> all.txt (everything).
1function Invoke-Feeding {
2 [CmdletBinding()]
3 param([string]$Dragon)
4 Write-Verbose "Fetching food for $Dragon"
5 "$Dragon fed"
6}
7Invoke-Feeding -Dragon Ember
8Invoke-Feeding -Dragon Glim -Verbose 4>&1 | ForEach-Object { "[$_]" }Ember fed [Fetching food for Glim] [Glim fed]
Catching mistakes early
Set-StrictMode -Version Latestturns sloppy code into errors: using a variable that was never assigned, reading a property that doesn’t exist, calling functions with method syntax. Put it at the top of scripts.- PSScriptAnalyzer (
Install-Module PSScriptAnalyzer, thenInvoke-ScriptAnalyzer .\script.ps1) is the linter: unapproved verbs, aliases in scripts, unused variables, plain-text passwords and more. VS Code runs it as you type. - Pester is the test framework. Tests read almost like English:
1Describe 'Get-FeedingAmount' {
2 It 'doubles the amount for hungry dragons' {
3 Get-FeedingAmount -Wingspan 10 -Hungry | Should -Be 60
4 }
5}1$dragon = 'Ember'
2"Without strict mode: [$dragn]"
3Set-StrictMode -Version Latest
4try {
5 "With strict mode: [$dragn]"
6} catch {
7 'Strict mode caught the typo: $dragn was never set'
8}Without strict mode: [] Strict mode caught the typo: $dragn was never set
Key takeaways
[CmdletBinding(SupportsShouldProcess)]plus$PSCmdlet.ShouldProcess()gives your functions -WhatIf and -Confirm.Output, error, warning, verbose, debug and information are separate streams; redirect them with
n>,2>&1and*>.Set-StrictMode -Version Latest, PSScriptAnalyzer and Pester catch mistakes before they bite.Keep secrets out of scripts: Get-Credential and SecretManagement.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: write PowerShell scripts
Write a script in the editor and run it for real against sample input, which is piped into your script as $input. Scripts run on PowerShell 6.2 through Try It Online (tio.run), a free public service, so these exercises avoid PowerShell 7-only syntax; your script and test input are sent there.
A cleanup that supports -WhatIf
Write Remove-FeedLog with [CmdletBinding(SupportsShouldProcess)] and a mandatory -Name parameter (a file name). It deletes that file from the current folder and outputs deleted <name>, but only when $PSCmdlet.ShouldProcess($Name, 'Delete feeding log') says so.
The starter creates a log file for each input line, rehearses deleting them all with -WhatIf, really deletes only the .old ones, and lists what’s left.
- Three logs
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Verbose feeding
Write an advanced function Invoke-Feeding that takes -Dragon and -Kilograms and outputs Ember fed 20 kg. Before that, it writes a verbose message: checking Ember's diet. If the kilograms are over 50 it writes a warning: Ember is getting a lot of food.
The starter calls it once normally and once with -Verbose, merging the verbose (4) and warning (3) streams into the output so you can see them.
- Two dragons
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…