Skip to the main content.

ScriptRunner Blog

PowerShell PSDefaultParameterValues

Table of Contents

Post Featured Image

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



 Let’s take a closer look at how to set a default.

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.

# Default
PS> Write-Host "Hello","World"
Hello World
# Adding the custom default
PS> $PSDefaultParameterValues.Add("Write-Host:Separator", "`n")
# Changed output
PS> Write-Host "Hello","World"


 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 verbosity
PS> (Invoke-WebRequest "").StatusCode 
# Adding the custom default
PS> $PSDefaultParameterValues.Add("Invoke-WebRequest:Verbose", $true)
# Changed output, with verbosity
PS> (Invoke-WebRequest "").StatusCode
VERBOSE: GET with 0-byte payload
VERBOSE: received 4801-byte response of content type text/html


 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} | ft
Days	Hours	Minutes Seconds Milliseconds
---- 	----- 	------- ------- ------------
0       0       0       0       0


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.

Let’s 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.

Screenshot of an Excel data sheet. You can see several rows of data for which the import settings were manually edited so that delimiters were recognized and correctly interpreted

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.

Screenshot of an Excel data sheet. You can see several rows with data that are clearly structured, similar to the example in Figure 2

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 don’t 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

Related posts

3 min read

ScriptRunner now available in the Microsoft Azure Marketplace

6 min read

Managing Microsoft Exchange with PowerShell

2 min read

VMUG Webcast: Mastering VMware Management with PowerCLI

About the author: