Reputation: 1096
I want to test whether a function exists. I wrote a function to do that for me, but when I put it in the module, it operates in the module's scope, when what I want is for it to operate in the scope of the session that called it.
If you copy and paste this into a PowerShell prompt, it works as expected.
function Test-Function($functionName) {
$values = @(get-command -all | where {$_.Name -eq "$functionName" -and $_.CommandType -eq "Function"})
return $values.Count -gt 0
}
At this point, you can run things like test-function Get-ChildItem
($false
, since that is a cmdlet), or test-function test-function
($true
, since that is a function).
But, what if you're going to use this function a lot?
If you save that in a .psm1 file and add a call to Export-ModuleMember
to expose the function, it will work... sometimes.
import Test.psm1
Test-Function Test-Function
# Returns $true
function blah() { echo "whatever" }
Test-Function blah
# Returns $false
As far as I can tell, this is a scoping issue - the module has its own scope, and it can't see other functions that I create outside of it.
Basically, I'd like to save this function for later and use it in several script files - it sounds like a candidate for a module to me. But, unless there's a clever solution to this scoping issue, I'm stuck with some crappy workarounds:
Don't put it in a module, put it in a .ps1 file and dot-source it.
This is what we do now, and it does work, and it's probably the least ugly thing to do if there isn't another workaround.
Don't put it in the module at all, and force anyone that wants to use it to reimplement
It's only a couple of lines, I guess, so this would work. The problem is it's already in our deployment scripts in a few places, and it would be so nice if I could just make it a function...
Do something weird with scoping or scriptblocks or something.
Like, put this in the module:
$testFuncBlock = {
param($functionName)
$values = @(get-command -all | where {$_.Name -eq "$functionName" -and $_.CommandType -eq "Function"})
return $values.Count -gt 0
}
Export-ModuleMember -variable testFuncBlock
And call it by dot-sourcing the scriptblock:
. $testFuncBlock Function-Name
Obviously that's hella ugly though
That's all I an think of. Is there something that will let me save this in the module and refer to it later without a scriptblock?
Upvotes: 3
Views: 351
Reputation: 52639
Get-Command
has different behavior depending on the version of PowerShell. Look at the version specific notes in the parameter documentation.
Instead I recommend using the function:
drive:
function Test-Function ($Name) {
Test-Path -Path "function:${Name}"
}
Upvotes: 2