This is what Gemini states:
Yes, it is technically possible and valid in PowerShell, but it is generally considered a bad practice.
While the PowerShell parser allows you to put complex logic inside a [Parameter()] attribute or a default variable assignment, doing so creates several hidden issues.
🛑 Why Complex Scriptblocks as Defaults are Problematic
- Performance Overhead: PowerShell evaluates the default parameter expressions every time the function is called, even if you explicitly pass a different value for that parameter. If your scriptblock queries Active Directory, reads a file, or performs heavy math, it will slow down every single execution of your function.
- Polluted Help and Syntax: When users run
Get-Help Your-Function or look at IntelliSense autocomplete, PowerShell tries to render the default value. If it contains a massive scriptblock, your function's syntax block becomes unreadable and messy. - Difficult Error Handling: If your complex scriptblock fails (e.g., a network resource is down), the function will throw an error before it even begins executing the
param() block. This makes debugging and standard try/catch blocks inside your function useless for catching that error.
🛠️ The Recommended Alternative: Use $PSBoundParameters
Instead of writing a complex scriptblock directly in the parameter definition, set the default value to $null (or leave it blank) and handle the complex logic inside the begin block of your function.
You can check if the user omitted the parameter by using the automatic $PSBoundParameters dictionary.
function Get-SystemReport {
[CmdletBinding()]
param (
[string]$ComputerName
)
begin {
# Check if the user forgot to provide a ComputerName
if (-not $PSBoundParameters.ContainsKey('ComputerName')) {
# Put your complex logic safely inside the begin block
Write-Verbose "No ComputerName provided. Fetching local topology..."
$ActiveAdapter = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1
$ComputerName = (Get-CimInstance Win32_ComputerSystem).Name + "." + $ActiveAdapter.InterfaceDescription
}
}
process {
# Your core function logic runs cleanly here
Write-Output "Running report for: $ComputerName"
}
}
📊 Comparison of Approaches
| Feature |
In-Param Scriptblock |
$PSBoundParameters in begin |
| Performance |
Runs every time (even if parameter is provided) |
Only runs when the parameter is missing |
| Readability |
Makes function syntax bloated and messy |
Keeps the function header clean and standard |
| Debugging |
Hard to catch errors; breaks before function starts |
Easy to test, debug, and wrap in try/catch |
I couldn't find a human defined statement in this best practice and style guide but I think the above recommandation is generally correct.
If this is indeed a good code convention, it could even be adopted in the PSScriptAnalizer.
This is what Gemini states:
[Parameter()]attribute or a default variable assignment, doing so creates several hidden issues.Get-Help Your-Functionor look at IntelliSense autocomplete, PowerShell tries to render the default value. If it contains a massive scriptblock, your function's syntax block becomes unreadable and messy.param()block. This makes debugging and standardtry/catchblocks inside your function useless for catching that error.$PSBoundParameters$null(or leave it blank) and handle the complex logic inside thebeginblock of your function.$PSBoundParametersdictionary.I couldn't find a human defined statement in this best practice and style guide but I think the above recommandation is generally correct.
If this is indeed a good code convention, it could even be adopted in the PSScriptAnalizer.