I've just started doing some PowerShell scripting, and I'm running into a problem testing variables for a value. I try to run everything with all warnings enabled, especially while I'm learning, in order to catch dumb mistakes. So, I'm using CTPV3 and setting strict mode on with "set-strictmode -version latest". But I'm running into a road block with checking incoming variables for a value. These variables may or may not already be set.
# all FAIL if $var is undefined under "Set-StrictMode -version latest"
if ( !$var ) { $var = "new-value"; }
if ( $var -eq $null ) { $var = "new-value"; }
I can't find a way to test if a variable has a value that doesn't cause warnings when the variable is missing unless I turn off strict mode. And I don't want to turn strict mode on and off all over the place just to test the variables. I'm sure I'd forget to turn it back on somewhere and it looks terribly cluttered. That can't be right. What am I missing?
Typically, whenever you assign a variable a value you use the -eq operator and test if the variable matches a value like $Variable -eq 'some string'. However, if want to test if the variable exists at all you can simply replace that value with $null.
To display the value of a variable, type the variable name, preceded by a dollar sign ( $ ). To change the value of a variable, assign a new value to the variable. The following examples display the value of the $MyVariable variable, changes the value of the variable, and then displays the new value.
In PowerShell, Set is an alias for the Set-Variable cmdlet, but it doesn't work with environment variables. Instead, you have to use the Get-ChildItem, Get-Item, or Remove-Item cmdlet with the ENV: drive.
This command turns strict mode on and sets it to version 2.0 . As a result, PowerShell returns an error if you use method syntax, which uses parentheses and commas, for a function call or reference uninitialized variables or non-existent properties. The sample output shows the effect of version 2.0 strict mode.
You're really testing for two things here, existence and value. And the existence test is the one causing the warnings under the strict mode operation. So, separate the tests. Remembering that PowerShell sees variables as just another provider (just like a file or registry provider) and that all PowerShell variables exist as files in the root folder of the drive called 'variable:', it becomes obvious that you can use the same mechanism that you would ordinarily use to test for any other file existence. Hence, use test-path
:
if (!(test-path variable:\var)) {$var = $null} # test for EXISTENCE & create
if ( !$var ) { $var = "new-value"; } # test the VALUE
Note that the current strict mode can be changed in child scopes without affecting the parent scope (eg, in script-blocks). So, you could write a script block that encapsulates removing strict mode and setting the variable without affecting the surrounding program's strictness. It's a bit tricky because of variable scoping. Two possibilities I can think of:
#1 - return the value from the script block
$var = & { Set-StrictMode -off; switch( $var ) { $null { "new-value" } default { $var } }}
or #2 - use scope modifiers
& { Set-StrictMode -off; if (!$var) { set-variable -scope 1 var "new-value" }}
Probably the worst part about these are the error-prone, repetitive use of $var (both with and without the leading $). It seems very error prone. So, instead I'd use a subroutine:
function set-Variable-IfMissingOrNull ($name, $value)
{
$isMissingOrNull = !(test-path ('variable:'+$name)) -or ((get-variable $name -value) -eq $null)
if ($isMissingOrNull) { set-variable -scope 1 $name $value }
}
set-alias ?? set-Variable-IfMissingOrNull
#...
## in use, `var` must not have a leading $ or the shell attempts to read the possibly non-existant $var
set-Variable-IfMissingOrNull var "new-value"
?? varX 1
This last is probably the way I'd script it.
EDIT: After thinking about your question for a bit longer, I came up with a simpler function that more closely matches your coding style. Try this function:
function test-variable
{# return $false if variable:\$name is missing or $null
param( [string]$name )
$isMissingOrNull = (!(test-path ('variable:'+$name)) -or ((get-variable -name $name -value) -eq $null))
return !$isMissingOrNull
}
set-alias ?-var test-variable
if (!(?-var var)) {$var = "default-value"}
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With