tags:

views:

117

answers:

3

Is it possible to test for the existence of a script-scoped variable in PowerShell?

I've been using the PowerShell Community Extensions (PSCX) but I've noticed that if you import the module while Set-PSDebug -Strict is set, an error is produced:

The variable '$SCRIPT:helpCache' cannot be retrieved because it has not been set.
At C:\Users\...\Modules\Pscx\Modules\GetHelp\Pscx.GetHelp.psm1:5 char:24

While investigating how I might fix this, I found this piece of code in Pscx.GetHelp.psm1:

#requires -version 2.0

param([string[]]$PreCacheList)

if ((!$SCRIPT:helpCache) -or $RefreshCache) {
    $SCRIPT:helpCache = @{}
}

This is pretty straight forward code; if the cache doesn't exist or needs to be refreshed, create a new, empty cache. The problem is that calling $SCRIPT:helpCache while Set-PSDebug -Strict is in force casues the error because the variable hasn't been defined yet.

Ideally, we could use a Test-Variable cmdlet but such a thing doesn't exist! I thought about looking in the variable: provider but I don't know how to determine the scope of a variable.

So my question is: how can I test for the existence of a variable while Set-PSDebug -Strict is in force, without causing an error?

+2  A: 

Use test-path variable:SCRIPT:helpCache

if (!(test-path variable:script:helpCache)) {
  $script:helpCache = @{}
}

This works for me without problems. Checked using this code:

@'
Set-PsDebug -strict
write-host (test-path variable:script:helpCache)
$script:helpCache = "this is test"
write-host (test-path variable:script:helpCache) and value is $script:helpCache
'@ | set-content stricttest.ps1

.\stricttest.ps1
stej
I added an example that really works for me. If you have any problems, I need to know what the problems are ;)
stej
This is probably the best way. The trick with [h]elpCache is faster (just a little bit) but it is hacky. Also, Test-Path way is much better when a variable’s name is a variable itself, i.e. Test-Path variable:script:$name
Roman Kuzmin
FWIW, using `test-path variable:` is the approach we usually take in PSCX. I'll take a look at this issue later tonight.
Keith Hill
A: 

You can use Get-Variable with the -Scope parameter. This cmdlet will (by default at least) not return only the variable's value but a PSVariable object and will throw an exception if the variable isn't found:

Get-Variable foo -Scope script
Joey
@Johannes Thanks for the answer. It's the exception that's thrown by `Get-Variable` that I'm trying to avoid though. I can do that with `try/catch` obviously, but I'd like to know if there's a more readable way that doesn't splurge red text into my output window. :)
Damian Powell
*Get-Variable -ErrorAction SilentlyContinue* should do the trick. You can check the result of the command call. N.B. The error is still added to the $Error list, unfortunately.
Roman Kuzmin
@Roman Kuzmin The `-ErrorAction` trick didn't help. Shame, because that seems like a good solution.
Damian Powell
+3  A: 

Try this trick:

Get-Variable [h]elpCache -Scope Script

It should not throw or emit any errors because we use a wildcard [h]elpCache. On the other hand this kind of a wildcard is a literal name de facto.

Roman Kuzmin
That's a neat one :-)
Joey
Yes, this way is hacky. @stej proposes a better solution. Still, the trick with fake wildcard is useful in many cases, e.g. for Get-Process (there is no Test-Path alternative for processes).
Roman Kuzmin
@Roman That's definitely a trick I'll remember.
Damian Powell
+1 @Roman, nice trick :)
stej