Making functions *really* read-only
Over at the excellent PowerShell Team Blog, Bruce Payette wrote about Controlling PowerShell Function (Re)Definition.
However, making a function constant
does not prevent it from being shadowed in child scopes. Given that a child scope is created in any script, new function definition or script block, this makes it very unconstant.
Consider this:
# define a constant function, one that cannot be replaced set-item function:/funca -option constant { write-host "this is the outer funca" # redefine the function in this new scope function funca { write-host "this is the inner funca" } # call this new funca funca } # call the outer one funca
If you run it, you will see that the inner funca is defined and executed. So much for being constant.
You can, however, make it a bit more permanent by adding the allscope
option to the outer function, like this:
# define a constant function, one that cannot be replaced set-item function:/funca -option constant,allscope { write-host "this is the outer funca" # redefine the function in this new scope - this will fail! function funca { write-host "this is the inner funca" } } # call the outer one funca
When we run this, we get an error:
PS> funcs this is the outer funca Cannot write to function funca because it is read-only or constant. At C:/Documents and Settings/adrian/My Documents/proj/ps1/funcs.ps1:5 char:17 + function funca <<<< {
Why? Because allscope
copies the function to all child scopes that are created. The default behaviour, when finding a function (or variable) is to look in the current scope, then the parent, and so on up to global
. By automatically copying the constant function to all scopes, you can prevent the function from ever being redefined.
So to make a function as constant as possible, define it with constant,allscope
in your $profile
.
PS. It appears that you can use scope modifiers with test-path
. These two commands do seem to work, although I’ve not seen any documentation regarding it:
test-path function:/funca test-path function:/script:funca
However, get-childitem function:
only shows one.
hmm. I can’t reproduce that behavior on my rtm powershell. The outer function is always run and the inner function falls out of scope so I get:
outer funca
inner funca
how are you getting those results? tia
Assuming you’re talking about the first example, you are seeing what I’m seeing, namely that the the outer constant funca is overridden in its own body, then executed, thus demonstrating that the outer funca is not constant.
My output is:
this is the outer funca
this is the inner funca
Maybe I wasn’t clear.