Skip to content

Instantly share code, notes, and snippets.

@jikuja
Last active November 2, 2025 23:44
Show Gist options
  • Select an option

  • Save jikuja/89372a5479ac06278ca9b9966939dbd8 to your computer and use it in GitHub Desktop.

Select an option

Save jikuja/89372a5479ac06278ca9b9966939dbd8 to your computer and use it in GitHub Desktop.
PowerShell notes

Feature comparison

Changes

Automatic enumeration on Process:

Type Example Enumerated? Notes
System.Collections.IEnumerable ✅ Yes
Object[] (array) @(1,2,3) ✅ Yes Each element (1, 2, 3) passes separately.
List<T> [System.Collections.Generic.List[int]]@(1,2,3) ✅ Yes Same behavior as arrays.
Collection<T> New-Object System.Collections.ObjectModel.Collection[int] ✅ Yes Each item is passed individually.
Hashtable @{A=1;B=2} ✅ Yes Enumerates as DictionaryEntry objects.
String[] "a","b","c" ✅ Yes Each string passed separately.

No enumeration on Process:

Type Example Reason
System.String "hello" Strings are IEnumerable<char> but treated as atomic (single object).
System.Management.Automation.PSObject Any PowerShell-wrapped object PSObject is a wrapper, not a collection.
System.Data.DataTable $table Although it contains rows, treated as one object.
System.Xml.XmlDocument [xml]'<root><a/></root>' Represents a whole document, not a collection.

Pipeline inputs

TBD

When you pipe multiple objects to a command, PowerShell sends the objects to the command one at a time. When you use a command parameter, the objects are sent as a single array object. This minor difference has significant consequences.

ByValue / ValueFromPipeline

The parameter accepts values that match the expected .NET type or that can be converted to that type.

Accepts values of the same type expected by the parameter or that can be converted to the type that the parameter is expecting.

ByPropertyName / ValueFromPipelineByPropertyName

The parameter accepts input only when the input object has a property of the same name as the parameter.

Accepts values of the same type expected by the parameter but must also be of the same name as the parameter accepting pipeline input.

TBD

autoload

PowerShell introduced module autoloading in version 3. To take advantage of this feature, the script module must be saved in a folder with the same base name as the .psm1 file. That folder must be located in one of the directories specified in the $env:PSModulePath environment variable.

Every module should include a module manifest, which is a .psd1 file containing metadata about the module.

tbd

The Invoke-Build module is a new alternative to PSake, it is well documented and frequently updated

TBD

$ConfirmPreference

Valid values of $ConfirmPreference:

  • None: PowerShell doesn't prompt automatically. To request confirmation of a particular command, use the Confirm parameter of the cmdlet or function.
  • Low: PowerShell prompts for confirmation before running cmdlets or functions with a low, medium, or high risk.
  • Medium: PowerShell prompts for confirmation before running cmdlets or functions with a medium, or high risk.
  • High: PowerShell prompts for confirmation before running cmdlets or functions with a high risk.

To override the $ConfirmPreference for a single command, use a cmdlet's or function's Confirm parameter.

  • To request confirmation, use -Confirm. => $ConfirmPreference = 'Low'
  • To suppress confirmation, use -Confirm:$false. => $ConfirmPreference = 'None'

ConfirmImpact

ConfirmImpact does not propagate from CmdLet to CmdLets being called

Examples

cmdlet ConfirmImpact
New-AzADGroup Medium
$ConfirmPreference = 'Medium' ; New-AzADGroup <...> 
# => prompts Confirmation

$ConfirmPreference = 'Low' ; New-AzADGroup <...> 
# => prompts Confirmation

$ConfirmPreference = 'High' ; New-AzADGroup <...> 
=> No confirmation

$ConfirmPreference = 'None' ; New-AzADGroup <...> 
=> No confirmation
$ConfirmPreference = 'High'; `
`
$DebugPreference = 'SilentlyContinue'; `
$VerbosePreference = 'SilentlyContinue'; `
$InformationPreference = 'SilentlyContinue'; `
$WarningPreference = 'Continue'; `
$ErrorActionPreference = 'Continue'; `
`
$WhatIfPreference = $false
function Test-ShouldProcess {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'Medium'
)]
param(
[Switch]$Force
)
if ($Force -and -not $Confirm){
# confirmation is still asked if called with `-force -debug`
# to disable confirmation `-force -debug -confirm:$false` must be used
Write-Host "Changing `$ConfirmPreference"
$ConfirmPreference = 'None'
}
Show-EnvironmentInformation -Force -PSBoundParameters_ $PSBoundParameters -MyInvocation_ $MyInvocation
# The call to $PSCmdlet.ShouldProcess($file.name) checks for the -WhatIf (and -Confirm parameter) then handles it accordingly.
# Logic is: https://github.com/PowerShell/PowerShell/blob/69e9b439fd38177ff7f3af1ef62f5617454bcf23/src/System.Management.Automation/engine/MshCommandRuntime.cs#L2974-L3000
if ($PSCmdlet.ShouldProcess('TARGET', 'ShouldProcess')){
Write-Host "ShouldProcess"
}
<#
/// <summary>
/// Confirm an operation or grouping of operations with the user.
/// This differs from ShouldProcess in that it is not affected by
/// preference settings or command-line parameters,
/// it always does the query.
/// This variant only offers Yes/No, not YesToAll/NoToAll.
/// </summary>
/// <remarks>
/// Cmdlets using ShouldContinue should also offer a "bool Force"
/// parameter which bypasses the calls to ShouldContinue
/// and ShouldProcess.
/// If this is not done, it will be difficult to use the Cmdlet
/// from scripts and non-interactive hosts.
/// ...
/// </remarks>
#>
if ($Force -or $PSCmdlet.ShouldContinue('TARGET','ShouldContinue')) {
Write-Host "ShouldContinue"
}
<#
/// <remarks>
/// Use WriteDebug to display debug information on the inner workings
/// of your Cmdlet. By default, debug output will
/// not be displayed, although this can be configured with the
/// DebugPreference shell variable or the -Debug command-line option.
/// </remarks>
/// <remarks>
/// Use WriteVerbose to display more detailed information about
/// the activity of your Cmdlet. By default, verbose output will
/// not be displayed, although this can be configured with the
/// VerbosePreference shell variable
/// or the -Verbose and -Debug command-line options.
/// </remarks>
/// <remarks>
/// Use WriteWarning to display warnings about
/// the activity of your Cmdlet. By default, warning output will
/// be displayed, although this can be configured with the
/// WarningPreference shell variable
/// or the -Verbose and -Debug command-line options.
/// </remarks>
#>
Write-Host "Write(s) with differenct levels"
Write-Debug "Debug"
Write-Verbose "Verbose"
Write-Information "Information"
Write-Warning "Warning"
Write-Error "Error"
}
<#
> $ConfirmPreference="Low" ; Test-ShouldProcess -force -confirm
Asks confirmation for ShouldProcess
> $ConfirmPreference="High" ; Test-ShouldProcess
Asks confirmation for both
> $ConfirmPreference="High" ; Test-ShouldProcess -Force
No confirmation asked
> $ConfirmPreference="High" ; Test-ShouldProcess -Force -Confirm
Asks confirmation for ShouldProcess
If both -Confirm and -Force are used Confirmation for ShouldProcess are requested.
Still logic of `if ($Force -and -not $Confirm){` does not make any sense and will not work on strict mode
#>
function Show-EnvironmentInformation {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess' ,"")]
[CmdletBinding(ConfirmImpact = "None", SupportsShouldProcess = $true)]
param(
[switch]
$Force,
$PSBoundParameters_ = $PSBoundParameters,
$MyInvocation_ = $MyInvocation
)
function Get-ValueFromPSBoundParameters {
param(
[Parameter(Mandatory=$true)]
[string]
$ParameterName,
$PSBoundParameters_
)
$PSBoundParameters_[$ParameterName] ? $PSBoundParameters_[$ParameterName].IsPresent: "NULL(N/A)"
}
if ($Force -and -not $PSBoundParameters.ContainsKey('Confirm')) {
Write-Verbose "Changing `$ConfirmPreference to None"
$ConfirmPreference = 'None'
}
if ($Force -or $Env:PrintRuntimeInformation) {
Write-Host "Confirm:"
Write-Host "ConfirmImpact: $($MyInvocation_.MyCommand.ScriptBlock.Attributes | Where-Object { $_ -is [System.Management.Automation.CmdletBindingAttribute] } | Select-Object -ExpandProperty ConfirmImpact)"
Write-Host "`$Confirm: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "Confirm")"
Write-Host "`$ConfirmPreference: $ConfirmPreference"
Write-Host "Prefrerences:"
Write-Host "`$Debug: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "Debug")"
Write-Host "`$DebugPreference: $DebugPreference"
Write-Host "`$Verbose: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "Verbose")"
Write-Host "`$VerbosePreference: $VerbosePreference"
Write-Host "`$Information: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "Information")"
Write-Host "`$InformationPreference: $InformationPreference"
Write-Host "`$Warning: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "Warning")"
Write-Host "`$WarningPreference: $WarningPreference"
Write-Host "`$Error: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "Error")"
Write-Host "`$ErrorPreference: $ErrorPreference"
Write-Host "`$WhatIf: $(Get-ValueFromPSBoundParameters -PSBoundParameters_ $PSBoundParameters_ -ParameterName "WhatIf")"
Write-Host "`$WhatIfPreference: $WhatIfPreference"
Write-Host "Parameters:"
Write-Host "`$PSBoundParameters.key: $($PSBoundParameters_.keys)"
}
}

PowershellConfirmPreference / impact

function Test-ShouldProcess {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param(
[Switch]$Force
)
Write-Verbose "`$PSCmdLet: $PSCmdLet"
Write-Verbose "`$DebugPreference: $DebugPreference"
Write-Verbose "`$ConfirmPreference: $ConfirmPreference"
Write-Verbose "`$Confirm: $Confirm"
Write-Verbose "`$Confirm: $($null -eq $Confirm ? "NULL": "NONNULL")"
if ($Force -and -not $Confirm){
Write-Verbose "Changing `$ConfirmPreference"
$ConfirmPreference = 'None'
} else {
Write-Verbose "XXXX"
}
Write-Verbose "`$DebugPreference: $DebugPreference"
Write-Verbose "`$ConfirmPreference: $ConfirmPreference"
Write-Verbose "`$Confirm: $Confirm"
Write-Verbose "`$Confirm: $($null -eq $Confirm ? "NULL": "NONNULL")"
# Does this ignore $ConfirmPreference?
# The call to $PSCmdlet.ShouldProcess($file.name) checks for the -WhatIf (and -Confirm parameter) then handles it accordingly.
if ($PSCmdlet.ShouldProcess('TARGET')){
Write-Output "Some Action"
}
if ($Force -or $PSCmdlet.ShouldContinue('TARGET','OPERATION')) {
Write-Output "Some Action"
}
}
<#
> $ConfirmPreference="Low" ; Test-ShouldProcess -force -confirm
Asks confirmation for ShouldProcess
> $ConfirmPreference="High" ; Test-ShouldProcess
Asks confirmation for both
> $ConfirmPreference="High" ; Test-ShouldProcess -Force
No confirmation asked
> $ConfirmPreference="High" ; Test-ShouldProcess -Force -Confirm
Asks confirmation for ShouldProcess
If both -Confirm and -Force are used Confirmation for ShouldProcess are requested.
Still logic of `if ($Force -and -not $Confirm){` does not make any sense and will not work on strict mode
#>

Strict mode off:

Set-StrictMode -Off

Strict mode latest:

Set-StrictMode -Version 'Latest'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment