Can't execute a Powershell script file

54 views Asked by At

I am tryin to use JEnv on windows 10. But I got the following error.

C:\dev_tools\JEnv\src\jenv.ps1 is not digitally signed. You cannot run this script on the current system.

I tried run Set-ExecutionPolicy with different options but always got error about Set-ExecutionPolicy : Windows PowerShell updated your execution policy successfully, but the setting is overridden by a policy defined at a more specific scope. The Get-ExecutionPolicy -List print the following result

        Scope ExecutionPolicy 
        ----- --------------- 
MachinePolicy       AllSigned 
   UserPolicy       Undefined 
      Process          Bypass 
  CurrentUser    RemoteSigned 
 LocalMachine    Unrestricted 

I guess I can't do anything, since I can't edit any group policy

1

There are 1 answers

0
mklement0 On

Unfortunately, if your machine's script execution policy is controlled via GPOs (Group Policy Objects), you can NOT override it ad hoc - neither with Set-ExecutionPolicy -Scope Process Bypass -Force nor by passing -ExecutionPolicy Bypass to the PowerShell CLI (powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+).

To change the effective policy to suit your needs therefore requires modifying the relevant GPO.

Since it is the machine-level GPO in your case that enforces that all scripts be signed, you'll need administrative privileges to change it.

  • Note that Get-ExecutionPolicy -List lists the policies in order of precedence: The first policy that isn't Undefined is the effective one.
  • It is only if both MachinePolicy and UserPolicy are listed as Undefined that the ad hoc overrides listed at the top are possible; you'll then also be able to change the policy for your account persistently, with SetExecutionPolicy -Scope CurrentUser RemoteSigned, for instance.

If you cannot change the GPO-based policy to suit your needs, you can try the following - limited - workaround, based on reading your script file's content into memory with Get-Content, parsing it into a script block, and executing it via &, the call operator:

  • Note: Clearly, the administrators of your machine want you to execute signed scripts only. It is up to you to decide whether circumventing this limitation is appropriate or not.

If your script needs to modify the current session, such as setting environment variables, you must execute it in-session:

# !! This MAY or MAY NOT work.
# !! Will also exit the calling session if the script terminates with `exit`
# Pass arguments, if needed, as usual.
& ([scriptblock]::Create((Get-Content -Raw C:\dev_tools\JEnv\src\jenv.ps1)))
  • CAVEAT: If your script terminates with exit, the above will exit the current session as a whole, because that's what executing exit outside of a script file does.

  • The workaround is to call via a child process, as shown next, but that invariably prevents the code from modifying the caller's session.

If your script doesn't need to modify the current session, the following avoids the exit problem, by executing the code in a child process, via a PowerShell CLI call, but comes with additional limitations (beyond just the performance penalty):

# !! This MAY or MAY NOT work.
# powershell is for Windows PowerShell; use pwsh in PowerShell (Core) 7+
# See below for argument-passing and data type-fidelity limitations.
powershell ([scriptblock]::Create((Get-Content -Raw C:\dev_tools\JEnv\src\jenv.ps1)))

Limitations:

  • Fundamentally, in both cases:

    • This will only work if your script:

      • does NOT call other scripts.
      • does NOT (possibly implicitly) import modules whose loading involves execution of script (module) files (.ps1, .psm1) and/or formatting and type-extension files (.psm1xml).
    • Also, executing your script's code not via a file means that its code won't be able to reflect on its file-based identity; notably, the automatic $PSScriptRoot variable and the automatic $PSCommandPath variable will have no values.

  • Additionally, when calling via the PowerShell CLI (child process):

    • If arguments are to be passed to the script's code, they must be passed via the -args CLI parameter, ,-separated, and they are invariably treated as positional arguments (in other words: you cannot pass named arguments this way).[1]

    • Calling via a child process invariably entails limited data-type fidelity - which may or not may a problem. See this answer for details.


[1] A workaround is possible, but cumbersome; something along the lines of:
powershell { & ([scriptblock]::Create((Get-Content -Raw C:\dev_tools\JEnv\src\jenv.ps1))) -FooParam $args[0] -BarParam $args[1] } -args foo, bar