windowspowershellcontextmenuexecutionpolicy

"Run with PowerShell" gives execution policy error but running directly in PowerShell window does not


I have a simple .ps1 script that basically just creates a directory. When I right-click on the script in Windows Explorer and select "Run with PowerShell", it gives the following error message:

Get-ExecutionPolicy : Windows PowerShell updated your execution policy successfully, but the setting is overridden by a policy defined at a more specific scope. Due to the override, your shell will retain its current effective execution policy of Unrestricted. Type "Get-ExecutionPolicy -List" to view your execution policy settings. For more information please see "Get-Help Set-ExecutionPolicy".

(I recorded my screen and typed all those above, as the window only flashed quickly. Also, if I run "powershell -NoExit C:\path\to\script.ps1", there is no error.

Interestingly, folder is still created.

However, if I open PowerShell myself and run the script like .\script.ps1, it does not have any error.

Here is the output of Get-ExecutionPolicy -List:

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

I think "Run with PowerShell" is trying to do something (like setting execution policy) before running the script, but I cannot see the full command that it invoked, and I don't know what scope it is trying to set execution policy for. Also, which of the above is more specific scope than which of the others?

I also don't have admin access to override this context menu item either. How should I get a clean execution?

Might be different from Unable to execute PowerShell Script using 'Run with Powershell' option as it seems my execution actually succeeded.

I expect to run the script cleanly from Windows Explorer, i.e., there should be no error outputs.


Solution

  • On Windows 10, the Windows PowerShell Run with PowerShell shortcut menu command (defined in the registry) attempts a process-specific execution policy override via the CLI, by calling Set-ExecutionPolicy -Scope Process Bypass as part of code passed to the -Command parameter.

    However, because your machine's execution policy is governed by a GPO (Group Policy Object), as indicated by the MachinePolicy output line having a value other than Undefined, neither overrides via the CLI's -ExecutionPolicy parameter nor via Set-ExecutionPolicy are effective.

    This is what the error message is trying to tell you; specifically, it means: I applied the change you requested, but it has no effect.

    The error itself does not stop execution, which continues with the GPO-controlled policy in effect.

    Given that the effective GPO policy is Unrestricted in your case (which should probably be RemoteSigned for better security), your scripts will still execute and you can ignore the error message.

    To make the error message go away, one option is to remove the Set-ExecutionPolicy call from the command definition in the registry.
    Its modification requires elevation, i.e. administrative privileges, due to being in the HKEY_LOCAL_MACHINE registry hive; however, it is possible to define user-specific equivalents in the HKEY_CURRENT_USER hive, which therefore do not require elevation - see below.

    The other option is to deactivate the relevant GPO, which - given that it is the MachinePolicy - at the very least requires elevation too, but is typically not under your control in a domain environment.


    Modifying / overriding the command to omit the Set-Execution call and therefore suppress the warning:

    On Windows 10, the following should work (I cannot personally verify any longer), based on the information in the bottom section of this answer, adapted to target whatever file type is currently registered for .ps1 files, which may differ from the default, notably if you have Visual Studio Code installed:

    # Determine the registry key path, based on the HKEY_CURRENT_USER
    # equivalent of the file-type key.
    $regKey = 'registry::HKEY_CURRENT_USER\Software\Classes\{0}\shell\Run with PowerShell\Command' -f (Get-ItemPropertyValue registry::HKEY_CLASSES_ROOT\.ps1 '(Default)')
    
    # Create the key, if necessary.
    if (-not (Test-Path $regKey)) { $null = New-Item -Force -ErrorAction Stop $regKey }
    
    # Define the command line, without Set-ExecutionPolicy and with -NoExit.
    Set-ItemProperty $regKey '(Default)' '"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoExit -File "%1"'
    

    This creates a HKEY_CURRENT_USER equivalent of the (potentially) HKEY_LOCAL_MACHINE-housed shortcut-menu command definition, which should override the latter, given that the HKEY_CLASSES_ROOT hive, through which the shortcut-menu definitions are loaded, is a composite view of the former two hives' Software\Classes paths, with the user-level definitions taking precedence.

    Also note that -NoExit was added to keep the session alive after script execution and therefore the window open.

    If you do have administrative privileges, you can replace HKEY_CURRENT_USER with HKEY_LOCAL_MACHINE in the code above and run it with elevation.


    On Windows 11, the problem no longer arises, because the Windows PowerShell CLI call configured there no longer tries to change the execution policy.

    However, you may still want to modify the call, namely to include the -NoExit switch too (to keep the session alive and the window open after script execution): see this answer.


    In PowerShell (Core) 7 - which is no longer supported on Windows 10 - the problem also doesn't arise: no attempt is made to set the execution policy.