Search code examples
powershellfunctionerror-handlingwindows-11elevation

How can I change the default PowerShell error for when a command needs elevation?


I have a lot of code in a PowerShell script that are mix of commands that need elevation to run and commands that don't, those that need elevation show errors in PowerShell console like:

"You don't have enough permissions to perform the requested operation"

and

 "Requested registry access is not allowed."

is there a way to globally suppress only the kinds of errors that PowerShell shows due to lack of necessary privileges?

I thought about a function that checks for elevation and performs actions based on the result, like this:

https://devblogs.microsoft.com/scripting/use-function-to-determine-elevation-of-powershell-console/

Function Test-IsAdmin

{    
   
 $identity = [Security.Principal.WindowsIdentity]::GetCurrent()

 $principal = New-Object Security.Principal.WindowsPrincipal $identity

 $principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)

   }

and

if(-NOT (Test-IsAdmin))

   { write-host "Skipping Admin command" }

else { $code }

but I don't know how to apply it globally to the whole script, so that commands that don't need elevation run, and those that need elevation show a custom message or skip that part silently.

another thing that can help my situation would be to find out if a PowerShell command needs elevation before actually running it and causing it to show errors in console due to lack of privileges.


Solution

  • It seems that errors stemming from a lack of privileges typically - but not necessarily - involve a System.UnauthorizedAccessException or System.Security.SecurityException .NET exception behind the scenes, whose name is then reflected as part of the .FullyQualifiedErrorId property of the resulting PowerShell error record, which is of type System.Management.Automation.ErrorRecord.

    Assuming that this applies to all errors you care about, you can use a (rarely used anymore) trap statement as follows:

    trap {
      if ($_.FullyQualifiedErrorId -match 'UnauthorizedAccessException|SecurityException') { 
        Write-Warning "Skipping admin command ($($_.InvocationInfo.Line.Trim()))"
        continue # Suppress the original error and continue.
      }
      # If the error was created with `throw`, emit the error and abort processing.
      # SEE CAVEAT BELOW.
      elseif ($_.Exception.WasThrownFromThrowStatement) { break }
      # Otherwise: emit the error and continue.
    }
    
    # ... your script
    

    Caveat:

    • If your script implicitly raises script-terminating errors - via -ErrorAction Stop or $ErrorActionPreference = 'Stop' - the above solution in effect turns them into statement-terminating errors and continues execution (only explicit script-terminating errors created with a throw statement are recognized as such in the code above, and result in the script getting aborted).

    • Unfortunately, as of PowerShell 7.2.x, there is no way to generally discover whether a given error is (a) non-terminating, (b) statement-terminating or (c) script-terminating (fatal).

      • See GitHub issue #4781 for a proposal to add properties to [System.Management.Automation.ErrorRecord] to allow such discovery in the future.