Creating Write-Protected Functions

by Nov 22, 2018

PowerShell functions by default can be overridden anytime, and you can also remove them using Remove-Item:

function Test-Lifespan
{
  "Hello!"
}

Test-Lifespan

Remove-Item -Path function:Test-Lifespan

Test-Lifespan

For security-relevant functions, you might want to create functions in a way that makes them immune against overwriting. Here is how:

$FuncName = 'Test-ConstantFunc'
$Expression = {
  param($Text)
  "Hello $Text, I cannot be removed!"
}

Set-Item -Path function:$FuncName -Value $Expression -Options Constant,AllScope

The new function is created directly on the function: drive using Set-Item. This way, you can apply additional options to the function, like Constant and AllScope. The function works as expected:

 
PS C:\> Test-ConstantFunc -Text $env:username 
Hello DemoUser, I cannot be removed! 
 

“Constant” makes sure the function can neither be overwritten nor deleted:

 
PS C:\> function Test-ConstantFunc { "Got you!!" }
Cannot write to function Test-ConstantFunc because it is read-only or constant.
At line:1 char:1
+ function Test-ConstantFunc { "got you!!" }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (Test-ConstantFunc:String) [], Sessio 
   nStateUnauthorizedAccessException
    + FullyQualifiedErrorId : FunctionNotWritable
 
 
PS C:\> Remove-Item -Path function:Test-ConstantFunc
Remove-Item : Cannot remove function Test-ConstantFunc because it is constant.
At line:1 char:1
+ Remove-Item -Path function:Test-ConstantFunc
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (Test-ConstantFunc:String) [Remove-It 
   em], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : FunctionNotRemovable,Microsoft.PowerShell.Command 
   s.RemoveItemCommand
 

Even more importantly, “AllScope” makes sure the function cannot be masked in child scopes. With write protection, a common workaround is to use a separate child scope to define a new function with same name:

& {
  function Test-ConstantFunc { "I am the second function in a child scope!" }
  Test-ConstantFunc

}

As it turns out, due to the option “AllScope”, this no longer works for masking the original protected function:

 
Cannot write to function Test-ConstantFunc because it is read-only or constant.
At line:4 char:3
+   function Test-ConstantFunc { "I am a second function in a child sco ...
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (Test-ConstantFunc:String) [], Sessio 
   nStateUnauthorizedAccessException
    + FullyQualifiedErrorId : FunctionNotWritable
 
Hello , I cannot be removed!
 

Twitter This Tip! ReTweet this Tip!