How do I distinguish an unset parameter from $ false, 0, an empty string?
I have a function that updates an object in WMI. I want the user to be able to specify in the parameters only the values that he wants to update. How can i do this?
function UpdateObject ([bool] $b1, [bool] $b2, [int] $n1, [string] $s1)
{
$myObject = GetObjectFromWmi #(...)
#(...)
#This is bad. As it overrides all the properties.
$myObject.b1 = $b1
$myObject.b2 = $b2
$myObject.n1 = $n1
$myObject.s1 = $s1
#This is what I was thinking but don't kwow how to do
if(IsSet($b1)) { $myObject.b1 = $b1 }
if(IsSet($b2)) { $myObject.b2 = $b2 }
if(IsSet($n1)) { $myObject.n1 = $n1 }
if(IsSet($s1)) { $myObject.s1 = $s1 }
#(...) Store myObject in WMI.
}
I tried passing $null
as a parameter, but it is automatically converted to $false
for bool
, 0
for int
and empty string
forstring
What are your suggestions?
source to share
Check $PSBoundParameters
to see if it contains a key with your parameter name:
if($PSBoundParameters.ContainsKey('b1')) { $myObject.b1 = $b1 }
if($PSBoundParameters.ContainsKey('b2')) { $myObject.b2 = $b2 }
if($PSBoundParameters.ContainsKey('n1')) { $myObject.n1 = $n1 }
if($PSBoundParameters.ContainsKey('s1')) { $myObject.s1 = $s1 }
$PSBoundParameters
acts like a hash table where keys are parameter names and values are parameter values, but they only contain associated parameters, which means explicitly passed parameters. It does not contain parameters filled with a default value (other than those passed by $PSDefaultParameterValues
).
source to share
Based on briantist's answer , if you know that all parameters exist as properties of the target, you can just loop through the hash table $PSBoundParameters
and add them one by one:
foreach($ParameterName in $PSBoundParameters.Keys){
$myObject.$ParameterName = $PSBoundParameters[$ParameterName]
}
If only some of the input parameters need to be passed as property values, you can still specify the list only once using:
$PropertyNames = 'b1','b2','n1','s1'
foreach($ParameterName in $PSBoundParameters.Keys |Where-Object {$PropertyNames -contains $_}){
$myObject.$ParameterName = $PSBoundParameters[$ParameterName]
}
source to share
If you want to specify a parameter [Boolean]
that you want to be explicitly specified or omitted (rather than a parameter [Switch]
that may or may not be present), you can use [Nullable[Boolean]]
. Example:
function Test-Boolean {
param(
[Nullable[Boolean]] $Test
)
if ( $Test -ne $null ) {
if ( $Test ) {
"You specified -Test `$true"
}
else {
"You specified -Test `$false"
}
}
else {
"You did not specify -Test"
}
}
In this example function, the variable $Test
would be $null
(user specified no parameter), $true
(user specified -Test $true
), or $false
(user specified -Test $false
). If the user specifies -Test
without a parameter argument, PowerShell will throw an error.
In other words: This gives you a tri-state parameter [Boolean]
(missing, explicitly true, or explicitly false). [Switch]
gives only two states (present or explicitly true, absent or explicitly false).
source to share
To save yourself the trouble of creating a parameter for every property that you can change, consider using a hash table or other object to pass this information to your function.
For example:
function UpdateObject ([hashtable]$properties){
$myObject = GetObjectFromWmi
foreach($property in $properties.Keys){
# without checking
$myObject.$property = $properties.$property
# with checking (assuming members of the wmiobject have MemberType Property.
if($property -in (($myObject | Get-Member | Where-Object {$_.MemberType -eq "Property"}).Name)){
Write-Output "Updating $property to $($properties.$property)"
$myObject.$property = $properties.$property
}else{
Write-Output "Property $property not recognised"
}
}
}
UpdateObject -properties {"b1" = $true; "b2" = $false}
source to share