Summary: Microsoft PowerShell MVP and guest blogger Dave Moravec talks about using default parameter values to simplify Windows PowerShell scripts.
Microsoft Scripting Guy, Ed Wilson, is here. Well, our European Tour is drawing down, but it’s not over yet. Yesterday, we had a great time with Bartek in Warsaw, and last night we took the train back from Warsaw to Berlin.
This morning, we are on a train to Prague to see Windows PowerShell MVP Dave Moravec. We will not have too much time—only about six hours before we have to hop back on a train to Frankfurt. But when Dave began talking to the Scripting Wife on Facebook and on Twitter, well, it was decided that we had the time, and we wanted to meet Dave. In honor of the occasion, I asked Dave to write a little bit about his favorite Windows PowerShell 3.0 feature. I will admit I was a bit surprised by his choice—perhaps you will be as well.
Take it away, Dave …
I have been in the IT industry for 15 years. The last 10 years working mainly with Microsoft management technologies. I work for one of the biggest international accounting companies as an administrator responsible for System Center: Configuration Manager (SCCM). I like to automate my infrastructure-related tasks with Windows PowerShell. I’m an author and speaker for Microsoft Czech Republic, and I run my own blog at PowerShell.cz. You can reach me on Twitter at @makovec.
Changing default parameter values
When I was asked to write about my favorite Windows PowerShell 3.0 feature, my #1 $PSDefaultParameterValues came to mind immediately. From my point of view, this was something I was looking for, for a long time.
How does it work? With $PSDefaultParameterValues, you can define (overwrite) default values of parameters for Windows PowerShell cmdlets. Actually, I just found that Scripting Guy already showed a nice usage of this a month ago in his PowerTip: Automatically Format Your PowerShell Table. Let me show you a few other practical examples.
How to set a default value
Let’s imagine you work frequently with Windows PowerShell jobs (and I am sure you do!). So I will use a really complicated example:
PS> Start-Job -Name sj -ScriptBlock { $pid } | Wait-Job | Receive-Job
8828
PS> Receive-Job -Name sj
PS>
No result received, as expected. If you want to leave the data in queue, you have to use the -Keep switch parameter. By using $PSDefaultParameterValues, you can tell PowerShell to set -Keep to True every time. $PSDefaultParameterValues is a hash table where the Key is combination of CmdletName:ParameterName and Value is the actual value you want to assign. In our example, the assignment is:
PS> $PSDefaultParameterValues = @{'Receive-Job:Keep'=$true}
You see that for the Keep parameter of the Receive-Job cmdlet, we used variable $true (as it is a switch, True means it’s enabled), so now we can write:
PS> Start-Job -Name sj2 -ScriptBlock { $pid } | Wait-Job | Receive-Job
2433
PS> Receive-Job -Name sj2
2432
PS>
If you check $PSDefaultParameterValues, you can see that it’s really a hash table.
PS> $PSDefaultParameterValues
Name Value
---- -----
Receive-Job:Keep True
If you want to overwrite the actual default value, you can specify $false for Keep parameter
PS> Start-Job -Name sj3 -ScriptBlock { $pid } | Wait-Job | Receive-Job –Keep:$false
998
PS> Receive-Job -Name sj3
PS>
Another usage for $PSDefaultParameterValues I found relates to work with the Export-Csv cmdlet. I export a lot of data from our infrastructure very often and pass them on in CSV format to my boss. Therefore, I don’t like the default behavior, which includes type info at the beginning of the file. I decided to change that. Furthermore, as work with different language settings, I also changed the delimiter.
PS> $PSDefaultParameterValues = @{'Export-Csv:Delimiter'=';'; 'Export-Csv:NoTypeInformation'=$true}
PS> Get-Process -Name p* | Select Name, WS | Export-Csv -Path c:\tmp\ps.csv
PS> Get-Content C:\tmp\ps.csv
“Name”;”WS”
“powershell_ise”;”17477223’
PS> $PSDefaultParameterValues
Name Value
---- -----
Export-Csv:Delimiter ;
Export-Csv:NoTypeInformation True
Works like a charm, but in the last output, you may have noticed an unpleasant surprise. Our modification from the first example (Receive-Job) disappeared. You probably discovered it happened during our second modification of $PSDefaultParameterValues. To avoid this, we will use techniques for work with the hash tables. There are two different possibilities:
PS> $PSDefaultParameterValues['Receive-Job:Keep']=$true
PS> $PSDefaultParameterValues.Add('Enter-PSSession:ComputerName', 'localhost')
After that, two additional default values were received, and we should have four in total now. Let’s check it:
PS> $PSDefaultParameterValues
Name Value
---- -----
Export-Csv:Delimiter ;
Receive-Job:Keep True
Export-Csv:NoTypeInformation True
Enter-PSSession:ComputerName localhost
You can immediately test newly added values. As of now, if you write Enter-PSSession, you will be connected to your local computer by default. This is probably not so useful, so feel free to modify it for the server you are mostly connecting to.
There are other options for $PSDefaultParameterValues modification:
- $PSDefaultParameterValues = @{'Get-ChildItem:Force' = $true} will allow you to run dir command with force enabled, so you’ll see hidden files and folders.
- $PSDefaultParameterValues = @{'*:Credential' = $cred} is very useful if you have your administrator credentials stored in a variable. As $PSDefaultParameterValues supports wild cards. This example will use these credentials for all cmdlets supporting it.
- Do you know people who are adjusting their watch ten minutes ahead? Let’s replicate this in Windows PowerShell: $PSDefaultParameterValues = @{'Get-Date:Date' = {[System.DateTime]::Now.AddMinutes(10)}} Here I used the possibility of $PSDefaultParameterValues to use ScriptBlock as value for the parameter.
The last one was a bit funny, I know. You can also do some awful assignments, but I will not show you any examples.
Changing the default value
If you want to change the actual value, you can use a standard operation used for work with the hash tables. We will change the delimiter for the Export-Csv cmdlet:
PS> $PSDefaultParameterValues[‘Export-Csv:Delimiter’]=’%’
Now all my exported CSVs will be delimited by the percent sign. If I don’t like it, I can overwrite the behavior as I did in the first example with Receive-Job.
PS> Get-Process –Name p* | Select Name, WS | Export-Csv –Path c:\tmp\ps.csv –Delimiter ‘,’
PS> Get-Content c:\tmp\ps.csv
“Name”,”WS”
“powershell_ise”,”17477223’
Removing the default value
If you want to remove your settings from $PSDefaultParameterValues, you can remove just a single record, or you can remove all records at once. Removing a single record is as easy as adding one; just use Remove method of the hash table:
PS> $PSDefaultParameterValues
PS> $PSDefaultParameterValues.Remove(‘Enter-PSSession:ComputerName’)
PS> $PSDefaultParameterValues
Removing the whole variable is arranged by using the Remove-Variable cmdlet. As this variable is automatic, Remove-Variable cleans its content only. As the Windows PowerShell team is full of clever people, they invented an additional option—temporarily disabling $PSDefaultParameterValues. You can set its Disable key to True and after that any of $PSDefaultParameterValues will apply.
You can see how it works from the above image. I removed all actual values from $PSDefaultParameterValues and then set Delimiter for Export-Csv. The next lines contain testing of disabled and enabled functionality of $PSDefaultParameterValues. As a confirmation, you see the content of all three exported files.
A few extra tips
You are probably aware of scoping in Windows PowerShell (if not, please read the about_Scopes Help file). If you define $PSDefaultParameterValues in your Global scope, it will be inherited to your script or function scope. This can sometimes lead to a really bad side effect. You can use disabling of $PSDefaultParameterValues in this case.
The second point you need to be aware of is that $PSDefaultParameterValues is active in your current session. If you have some useful assignments, you have to define it in your profile script.
For further investigation of the $PSDefaultParameterValues concept, see about_Parameters_Default_Values.
~David
Thank you, David, for an excellent article.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy