Powershell: Colon in commandlet parameters
What's the deal with Powershell commandlet switch parameters that require a colon?
Consider Exchange 2010 management shell cmdlet Move-ActiveMailboxDatabase. The Confirm switch is a System.Management.Automation.SwitchParameter
and must be used like so,
Move-ActiveMailboxDatabase -Confirm:$false
Without the colon the command fails to recognize the don't confirm switch like so,
Move-ActiveMailboxDatabase -Confirm $false
Why is that? What's the difference the colon makes there? Why Exchange2010 seems to be about the only thing I've noticed this behavior?
I've browsed through Powershell in Action and Powershell 2.0, but didn't find anything about this syntax. Scope resolution and .Net object access uses are documented on those books though.
My Google-fu found an article which claims that it explicitly forwards switch parameter values, but fails to explain what that is about.
Solution 1:
When you do:
Move-ActiveMailboxDatabase -Confirm $false
you are not saying Confirm
parameter accepts the $false
. You are saying -Confirm
and also passing an (separate) argument to the cmdlet with value $false
.
Since Confirm
is a switch, just the presence of -Confirm
means it is true. Absence of -Confirm
means it is false.
Let me give you a script example:
param([switch]$test)
write-host Test is $test
If you just run the script without any arguments / paramters i.e .\script.ps1
you get output:
Test is False
If you run it as .\script.ps1 -test
, the output is
Test is True
If you run it as .\script.ps1 -test $false
, the output is
Test is True
If you run it as .\script.ps1 -test:$false
the output is
Test is False
It is in scenarios where the value for a switch variable itself has to be determined from another variable that the :
is used.
For example, consider the script:
param ([boolean]$in)
function func([switch] $test){
write-host Test is $test
}
func -test:$in
Here if you run it as .\script.ps1 -in $false
, you get
Test is false
If you weren't able to use the :
, you would have had to write it as:
if($in){ func -test}
else { func }
Solution 2:
The colon can be used with every parameter value but is more special in the case of switch parameters. Switch parameters don't take values, they are either present ($true) or absent ($false).
Imagine you have a function like this:
function test-switch ([string]$name,[switch]$force) { ... }
And you call it like so:
test-switch -force $false
Since switch parameters are either present or not, $false would actually bind to the Name parameter. So, how do you bind a value to a switch parameter? With the colon:
test-switch -force:$false
Now the parameter binder knows which parameter the value goes to.