I want to include Whatif
and Confirm
to my functions but I encountered an issue with these parameters.
My functions are structured like this:
function Get-Stuff {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
param ( {...} )
process {
if ($PSCmdlet.ShouldProcess($Name, "Delete user")) {
$result = Invoke-RestMethod @restBody
}
}
end {
Write-Output -InputObject $result
Remove-Variable -Name result
}
}
I took on a habit to clean up my variables in the end-block with Remove-Variable
. When I use now the -WhatIf
or the -Confirm
parameter (and denying it), I get an error that the $result
variable is null.
ErrorRecord : Cannot find a variable with the name 'result'.
I understand that the RestMethod is skipped in this case but I would assume that the rest of the function would not be executed further.
My question is now, does one add an else-clause to end the continuing execution of the function or do I use these parameters incorrectly?
There's no good reason to remove your variables in the end
block, since they go out of scope automatically anyway, given that they're local to your function.
(The only thing that makes sense is to .Dispose()
of variables containing objects that implement the System.IDisposable
interface; if releasing memory as quickly as possible is paramount - at the expense of blocking execution temporarily - you can additionally call [GC]::Collect(); [GC]::WaitForPendingFinalizers()
)
If you still want to call Remove-Variable
, you have two options:
Simply ignore a non-existent variable by adding -ErrorAction Ignore
to the Remove-Variable
call.
Remove-Variable -Name result -ErrorAction Ignore
Alternatively, protect the call - and the Write-Output
object - with an explicit test for the existence of the variable:
if (Get-Variable -Scope Local result -ErrorAction Ignore) {
$result # short for: Write-Output -InputObject
Remove-Variable -Name result
}
Also note that it's typical for output objects to be emitted directly from the process
block - emitting from the end
block is only a necessity for commands that for conceptual reasons must collect all input first, such as Sort-Object
.
Emitting output objects from the process
block - which is invoked for each input object - ensures the streaming output behavior - emitting objects one by one, as soon as they're available - that the pipeline was designed for.