Executing elevated powershell scripts from C# in .NET Core 3.0

Question:

I’m calling a self-elevating powershell script from C# code. The Script resets DNS Settings.
The script works fine when called from unelevated powershell, but takes no effect when called from C# code with no exceptions thrown.
My Execution policy is temporarily set on unrestricted and I’m running Visual Studio as Admin.

Does anyone know what’s wrong?

The C#:

The script:

Answer:

As you’ve just determined yourself, the primary problem was that script execution was disabled on your system, necessitating (at least) a process-level change of PowerShell’s execution policy, as the following C# code demonstrates, which calls
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass before invoking the script file (*.ps1):

  • For an alternative approach that uses the initial session state to set the per-process execution policy, see this answer.
  • The approach below can in principle be used to persistently change the execution policy for the current user, namely by replacing .AddParameter("Scope", "Process") with .AddParameter("Scope", "CurrentUser")
    • Caveat: When using a PowerShell (Core) 7+ SDK, persistent changes to the local machine‘s policy (.AddParameter("Scope", "LocalMachine")) – which require running with elevation (as admin) – are seen by that SDK project only; see this answer for details.

Caveat: If the current user’s / machine’s execution policy is controlled by a GPO (Group Policy Object), it can NOT be overridden programmatically – neither per process, nor persistently (except via GPO changes).

Note that the code also reports any non-terminating errors that the script may have reported, via stderr (the standard error output stream).

Without the Set-ExecutionPolicy call, if the execution policy didn’t permit (unsigned) script execution, PowerShell would report a non-terminating error via its error stream (.Streams.Error) rather than throw an exception.

If you had checked .Streams.Error to begin with, you would have discovered the specific cause of your problem sooner.

Therefore:

  • When using the PowerShell SDK, in addition to relying on / catching exceptions, you must examine .Streams.Error to determine if (at least formally less severe) errors occurred.

Potential issues with your PowerShell script:

  • You’re not waiting for the elevated process to terminate before returning from your PowerShell script.
  • You’re not capturing the elevated process’ output, which you’d have to via the .RedirectStandardInput and .RedirectStandardError properties of the System.Diagnostics.ProcessStartInfo instance, and then make your script output the results.
  • See this answer for how to do that.

The following, streamlined version of your code addresses the first point, and invokes the powershell.exe CLI via -ExecutionPolicy Bypass too.

  • If you’re using the Windows PowerShell SDK, this shouldn’t be necessary (because the execution policy was already changed in the C# code), but it could be if you’re using the PowerShell [Core] SDK, given that the two PowerShell editions have separate execution-policy settings.

Source:

Executing elevated powershell scripts from C# in .NET Core 3.0 by licensed under CC BY-SA | With most appropriate answer!

Leave a Reply