PSDefaultParameterValuesis a hashtable allowing us to overwrite default values of any parameter on any cmdlet with our own desired default values.
The cmdlet will then use the custom default value unless a different value is specified in the command.
This may not sound like the most important feature but trust me, after this post you will ask yourself how you ever worked without it.
How to use PowerShell PSDefaultParameterValues
Parameters
Lets take a closer look at how to set a default.
$PSDefaulParameterValues.Add("Command:Parameter","Value")As you can see we simply add a new key to the hashtable specifying the cmdlet and parameter to set a default for, separated by a :. The value obviously needs to be of a type accepted by the parameter or you will get errors when using the cmdlet.A concrete example would be to specify a custom separator for Write-Host.# DefaultPS> Write-Host "Hello","World"Hello World# Adding the custom defaultPS> $PSDefaultParameterValues.Add("Write-Host:Separator", "`n")# Changed outputPS> Write-Host "Hello","World"HelloWorld
Switches
For switch parameters this is nearly the same, we just use a boolean to indicate if we want the switch present $true or absent $false.
For example, we could use it to enable debugging for all Invoke-WebRequest calls in a script at once.
# Default, no verbosityPS> (Invoke-WebRequest "https://ps1.guru").StatusCode 200# Adding the custom defaultPS> $PSDefaultParameterValues.Add("Invoke-WebRequest:Verbose", $true)# Changed output, with verbosityPS> (Invoke-WebRequest "https://ps1.guru").StatusCodeVERBOSE: GET https://ps1.guru/ with 0-byte payloadVERBOSE: received 4801-byte response of content type text/html200
Wildcards
Staying with the Verbose parameter from the previous example we could use wildcards to set it for all cmdlets. This is a great trick I commonly use for debugging my scripts.
PS> $PSDefaultParameterValues.Add("*:Verbose", $true)
Advanced Values
Instead of a static value it is possible to use a script block as the default of a parameter. This enables an extreme level of customization depending on system state like the host you are on, the current directory and many more.
Staying with our verbosity example from before we could make its behavior dependent on a variable $verbose.
PS> $PSDefaultParameterValues.Add("*:Verbose", {$verbose -eq $true})
Now we can control the default verbosity of our session by setting and removing a variable. Keep in mind this script block is run every time you use the cmdlet, so keep it fast. You can measure it like this:
PS> Measure-Command {$verbose -eq $true} | ftDaysHoursMinutes Seconds Milliseconds---- ----- ------- ------- ------------0 0 0 0 0
Persistence
Everything we did up to now will not persist between sessions, for defaults to do so you need to add them to your profile. To find all defaults you have added in the current session just query the history like this.
Get-History | Where-Object CommandLine -like "`$PSDEfaultParameterValues*"
Real-World Example of PSDefaultParameterValues
You may ask why this is a good thing to have, let me show you on a quick example.
Lets say you always export data to CSV files for someone to open in Excel. If they just double-click your CSV they will not get a great result.

Fig. 1: Imported data in Excel
Most of us would then simply open up a new Excel file and import the data with Data > From Text, clicking through the plethora of screens and configuring Excel to actually detect the delimiter.

Fig. 2: Manually edited data import
But there is a better way! Instead of just exporting CSV.
Get-Process -Name Microsoft* | Export-Csv msproc.csv
you could specify a custom delimiter and, while your at it, remove type information and clobber.
Get-Process -Name Microsoft* | Export-Csv bettermsproc.csv -Delimiter ";"-NoTypeInformation -NoClobber
Now importing, exporting, converting from and converting to CSV will use the delimiter ; and not include any type information or clobber.
If you open the resulting CSV file directly with excel you can see a result similar to the data import dance we did before.

Fig. 3: Data import after configuration with PowerShell
But always typing out those parameters is cumbersome and has an inherently high margin of error.This is where we will set some defaults
$PSDefaultParams.Add("Export-Csv:Delimiter", ";")$PSDefaultParams.Add("Export-Csv:NoTypeInformation", $true)$PSDefaultParams.Add("Export-Csv:NoClobber", $true)
With this we can go back to simply using Export-Csv and the resulting file will be opened in Excel just as expected.We could even go one step further and change those parameters for all cmdlets in the CSV family using wildcards.
$PSDefaultParams.Add("*-Csv:Delimiter", ";")$PSDefaultParams.Add("*-Csv:NoTypeInformation", $true)$PSDefaultParams.Add("*-Csv:NoClobber", $true)
Using PSDefaultParameterValues in Scripts
Now that you learned about $PSDefaulParameterValues I want to caution you please dont use them
in your scripts.
There are some good reasons for this:
- Other users may not have your default values and therefore the script will break for them
- You may change your defaults down the line and the script will break for you
To mitigate this I would suggest just disabling PSDefaultParameterValues first thing in all your scripts:
# Disable PSDefaultParameterValues$PSDefaultParameterValues.Add("Disabled", $true)
And re-enabling them at the end:
# Re-Enable PSDefaultParameterValues$PSDefaultParameterValues.Remove("Disabled")