2

When you run Get-ExecutionPolicy in PowerShell, it gets the effective execution policy. I need to know the best way to get that information in C#. I don't need to know how to change it like many other questions about PowerShell Execution Policy, I just need to know how to get it in C#.

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
Unknown
  • 141
  • 7
  • 2
    Can't you just call `Get-ExecutionPolicy`? It's pretty easy to [invoke PS code from C#](https://learn.microsoft.com/en-us/powershell/scripting/developer/hosting/windows-powershell-host-quickstart?view=powershell-7.2). – boxdog Jun 16 '22 at 20:41
  • 1
    Are you asking about Windows PowerShell or PowerShell (Core), and, if the latter, for a particular platform? That would impact solutions that don't ask PowerShell itself via `Get-ExecutionPolicy`. – Lance U. Matthews Jun 16 '22 at 22:02

2 Answers2

3

Note:

  • PowerShell execution policies apply only on Windows.

  • With respect to Windows, the answer below covers both PowerShell editions.


It can be inferred from the docs that boxdog pointed to in a comment, but to spell it out:

using System;
using System.Management.Automation;

namespace demo
{
  class ConsoleApp {
    static void Main() {
      using (var ps = PowerShell.Create()) {
        var effectivePolicy = ps.AddCommand("Get-ExecutionPolicy").Invoke()[0].ToString();
        ps.Commands.Clear();
        Console.WriteLine("Effective execution policy: " + effectivePolicy);
      }
    }
  }
}

Note:

  • The above assumes that you're using the PowerShell SDK - see this answer for the appropriate NuGet package to add to your project.

  • If you're using a PowerShell (Core) 7+ SDK, additional considerations apply:

    • On Unix-like platforms, execution policies fundamentally do not apply (Unrestricted is reported, though in effect it is Bypass), so the following applies to Windows only:

    • The LocalMachine scope of any - by definition install-on-demand - PowerShell (Core) 7+ version does not apply; only - if defined - the CurrentUser and GPO-based policies (which preempt the former) do.

  • On Windows:

    • In the absence of a relevant execution policy being defined, Restricted is the default, which categorically prevents execution of script files (.ps1).

    • If your application needs to execute .ps1 files when hosting the PowerShell SDK, for predictable behavior it is best to set the execution policy, for the current process only, as shown in this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

The most elegant solution would probably be to get the ExecutionPolicy registry key in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell. For this solution to work, your program needs to be running on the same architecture (x64 or x86) as the operating system it's running on or it won't be able to see the registry key. Code to do this would look something like this:

using Microsoft.Win32
...
string executionPolicy = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell", "ExecutionPolicy", null)?.ToString();

If for any reason you can't do the first solution, the second way I would recommend is by using the System.Management.Automation.PowerShell NuGet package. This method would look something like this:

using(var ps = PowerShell.Create()){
  ps.AddScript("Get-ExecutionPolicy");
  Collection<PSObject> output = ps.Invoke();
  Console.WriteLine($"Execution policy is {output[0]}")
}

If you really don't want to add an extra NuGet package to your project, there is another, but quite a bit messier way of doing this using System.Diagnostics.Process and it's output stream. It would look something like this:

var procInfo = new ProcessStartInfo("powershell.exe", "-Command \"Get-ExecutionPolicy\"")
{
  CreateNoWindow = true,
  UseShellExecute = false,
  RedirectStandardOutput = true
};

var proc = new Process
{
  StartInfo = procInfo
};
proc.OutputDataReceived += Proc_OutputDataReceived;

proc.Start();
proc.BeginOutputReadLine();
Console.ReadLine();

...

private static void Proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
  if (!string.IsNullOrWhiteSpace(e.Data))
    Console.WriteLine($"Execution policy is {e.Data}");
}
Jesse
  • 1,386
  • 3
  • 9
  • 23
  • In your fist solution, `System.Win32` doesn't exist. However, the NuGet package `Microsoft.Win32.Registry` does what you need it to. – Unknown Jun 16 '22 at 21:53
  • @Unknown Sorry I meant `Microsoft.Win32`. I'll fix it. – Jesse Jun 16 '22 at 21:54
  • Also you don't need a NuGet package for it. `Microsoft.Win32` is one of the default references. – Jesse Jun 16 '22 at 22:00
  • I'm still new to NuGet, do they put default references in NuGet? Not trying to be a wise guy, just curious. https://www.nuget.org/packages/Microsoft.Win32.Registry/ – Unknown Jun 16 '22 at 22:40
  • I mean as soon as you create a new project, it's already there. `Microsoft.Win32` is included in `System.dll` which is included in every project template. You don't need any NuGet packages, just put `using Microsoft.Win32` at the top. – Jesse Jun 16 '22 at 22:47
  • 1
    @SantiagoSquarzon Good point. I'm not sure why I did that. Lack of sleep I guess. I'll update it to use PowerShell directly instead of cmd. – Jesse Jun 16 '22 at 23:40
  • I'm not sure that reading the configuration from the registry is more elegant than just asking PowerShell what it is, particularly since it's relying on an implementation detail (though it is sorta documented in [an example for `Set-ExecutionPolicy`](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/set-executionpolicy#example-2-set-an-execution-policy-that-conflicts-with-a-group-policy)), but I suppose that depends on how much of a hindrance invoking a PowerShell session/process is considered to be. – Lance U. Matthews Jun 17 '22 at 01:57
  • 1
    A process can use [`OpenBaseKey()`](https://learn.microsoft.com/dotnet/api/microsoft.win32.registrykey.openbasekey) to read from the "other" architecture's registry, so something like `using (RegistryKey machineKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) using (RegistryKey powershellKey = machineKey.OpenSubKey(@"SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell")) return (string) powershellKey.GetValue("ExecutionPolicy");` will allow a 32-bit process to read the execution policy of 64-bit PowerShell. – Lance U. Matthews Jun 17 '22 at 01:57