1

I have a .NetCore application running in Windows 10 that is attempting to run some scripts with PowerShell.

I'm using the following Automation Library

System.Management.Automation, Version=7.3.3.0

I have the ExecutionPolicy set for LocalMachine set to Unrestricted by running the following command in the Powershell 7 app:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -scope LocalMachine

I check the ExecutionPolicy settings via:

Get-ExecutionPolicy -List

I see the following output:

      Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser       Undefined
 LocalMachine       Unrestricted

In my .NetCore application I run the following code snippet:

var psInstance = PowerShell.Create();
psInstance.AddScript("Get-ExecutionPolicy -List");
var output = psInstance.Invoke();

If I examine the output, I see the following:

[0] {@{Scope=MachinePolicy; ExecutionPolicy=Undefined}} System.Management.Automation.PSObject
[1] {@{Scope=UserPolicy; ExecutionPolicy=Undefined}}    System.Management.Automation.PSObject
[2] {@{Scope=Process; ExecutionPolicy=Undefined}}   System.Management.Automation.PSObject
[3] {@{Scope=CurrentUser; ExecutionPolicy=Undefined}}   System.Management.Automation.PSObject
[4] {@{Scope=LocalMachine; ExecutionPolicy=Undefined}}  System.Management.Automation.PSObject

It seems like the execution policies within my application are not in synch with those I set directly through Powershell.

Why don't the two sets of ExecutionPolicies match up?

Further more, if I attempt to run the following:

var psInstance = PowerShell.Create();
psInstance.AddScript("Get-WindowsCapability -Online -Name ""Language.TextToSpeech~~~fr-FR~0.0.1.0"" | Select-Object -ExpandProperty State";);
var output = psInstance.Invoke();

I get the following error:

The 'Get-WindowsCapability' command was found in the module 'Dism', but the module could not be loaded due to the following error: [File C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Dism\Dism.psm1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at https://go.microsoft.com/fwlink/?LinkID=135170.] For more information, run 'Import-Module Dism'.

If I run:

var script = "Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process -Force; Get-WindowsCapability -Online -Name ""Language.TextToSpeech~~~fr-FR~0.0.1.0"" | Select-Object -ExpandProperty State";
psInstance.AddScript(script);
var output = psInstance.Invoke();

The command works as expected.

We don't want to have to set the ExecutionPolicy each time we run a script. We want to leverage the execution polices on the local machine. Why I can't I get this to work as expected? Is there another way I should be setting ExecutionPolicy at the machine level?

JohnB
  • 3,921
  • 8
  • 49
  • 99

1 Answers1

2

PowerShell (Core) 7+ has analogous, but separate execution policy setting from Windows PowerShell:

  • Windows PowerShell uses the registry to store the execution policy settings (for both the Machine and CurrentUser scopes).

    • Since both powershell.exe and Windows PowerShell SDK-based projects consult these registry locations, the same effective policy applies to both environments.
  • By contrast, PowerShell (Core) 7+ uses powershell.config.json files.[1]

    • In the case of the machine-scope policy, that file is looked for in the directory of the host executable.

      • Therefore, when you use the PowerShell SDK in your own .NET application, your executable is the host executable - unlike in interactive sessions / CLI calls, where it is pwsh.exe.
    • It follows that .NET (Core) applications, which of necessity use the PowerShell (Core) SDK, do not see the machine-scope execution setting in effect for interactive sessions / pwsh CLI calls - though a user-scope setting - if defined - does apply.


Solution options:

  • Most robust: Set the execution policy in the process scope, every time your application runs, as part of your PowerShell SDK session initialization.

    • This overrides any persistently configured user- or machine-code settings (except if your execution policies are GPO-controlled, in which case modifying the GPOs is the only way to change the execution policy).

    • See this answer for sample code.

  • Set the execution policy persistently in the user scope:

    • Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

      • Note: RemoteSigned is a more secure choice.
      • This works, because the user-scope powershell.config.json file location is only related to the user's home directory, and therefore the same for interactive /CLI and SDK sessions.
    • Obviously, you'd have to do that for every user that should be able to run your application.

  • Bundle a powershell.config.json file with your application (place it alongside your executable); sample content:

    {
      "Microsoft.PowerShell:ExecutionPolicy": "RemoteSigned"
    }
    

[1] Given PowerShell (Core)'s cross-platform nature, using the Windows-only registry is no longer an option.

mklement0
  • 382,024
  • 64
  • 607
  • 775