1

I am trying to write a Powershell script to automate general tasks on a new computer including installing software. ExecutionPolicy has been the bane of my existence when it comes to blocking me from running automated scripts that I have been writing.

One of my PS scripts requires elevated Admin privileges, so I have a batch file where I am calling to launch PS as Administrator but I am still getting stuck with the script instantly closing/failing due to ExecutionPolicy. Ideally, I would like a way to bypass the ExecutionPolicy on a per script basis instead of completely changing it and then changing it back.

I have looked up different Set-ExecutionPolicy methods but they don't seem to work.

I need a generic command in a .bat file to launch a specified powershell script as Admin AND bypassing the current ExecutionPolicy.

7
  • 2
    Bypass is your answer. Either that, or sign your scripts. Unless you want to unrestrict all Commented Mar 4, 2022 at 1:38
  • 2
    You know there is a command line argument for the execution policy for the PowerShell executable, don't you? You may run PowerShell /? to read more about. ;-) Commented Mar 4, 2022 at 1:45
  • 1
    I'm curious what happens when you load the ps1 script as ScriptBlock and execute it there. Seems I read someplace there are fewer restrictions on code ran in a ScriptBlock. Commented Mar 4, 2022 at 2:39
  • 1
    @mklement0, I knew my comment had at least some validity independent of your confirmation, which is why I just let it slide. But I do appreciate you letting me know what you found out. The particular command I've been working on, and works so far in my situation, is powershell with RemoteSigned (If I hit a wall someday, I may have to switch to bypass). In the command there is prep of several variables, including flags indicating the batch is in pipe or called from GUI, and then a scriptblock wrapped around a scriptblock of a file with the batch parameter line. 437 chars not counting indent Commented Mar 4, 2022 at 15:16
  • 1
    @mklement0, to partly remedy "I don't fully understand", you need to understand the goal. Single design for a batch file that calls ps1 file, accepts pipeline input that is passed to ps1 file, can recognize it has either been double clicked or files dragged-N-dropped on it - and ps1 files can detect this, passes the command line as is for PowerShell to process, and doesn't have execution issues that ps1 file have. I think I achieved this goal about 2 weeks ago, with the possible exception of execution policy. I think I need to sit down and really get my head wrapped around it. Commented Mar 4, 2022 at 16:18

1 Answer 1

2

I need a generic command in a .bat file to launch a specified powershell script as Admin AND bypassing the current ExecutionPolicy.

The key is to use the -ExecutionPolicy CLI parameter (which only the inner powershell call below needs; the sole purpose of the outer one is to launch the target session with elevation (as admin), which itself doesn't involve execution of a script file):

  • Caveat: If your effective execution policy is controlled by GPOs (Group Policy Objects), it can not be overridden[1] - neither with the -ExecutionPolicy CLI parameter, nor in-session with Set-ExecutionPolicy - the solution below won't work. See this answer for details.

Also - unrelated to execution policies - additional work is required in order to preserve the caller's working directory, because elevated sessions default to the SYSTEM32 directory. Therefore, the command below incorporates an explicit Set-Location call to set the working directory. Note that in order to call a script located in that directory you need to prefix its name with .\ (e.g., .\script.ps1 instead of just script.ps1):

:: Run from cmd.exe / a batch file.
:: The target script file is '.\script.ps1' in this example, and
:: 'foo 1' and 'bar' are sample arguments to pass to it.
powershell -noprofile -c Start-Process -Verb RunAs powershell '-noexit -noprofile -ExecutionPolicy Bypass -c Set-Location -LiteralPath ''%CD:'=''''%''; ^& .\script.ps1 ''foo 1'' bar'

-noexit keeps the elevated session open after the specified .ps1 script terminates; remove it, if you want the session and thereby its window to close automatically.
-noprofile suppresses loading of the profile scripts; in the second powershell call, that isn't strictly necessary, but still advisable for a predictable execution environment.

Note:

  • In order to avoid "-related escaping hell, the above solution uses '...' strings only, as understood by PowerShell in the context of a -c (-Command) CLI call, which, however, assumes the following:

    • The script file name / path itself and the pass-through arguments mustn't contain ' chars. - if they do, they must be enclosed in ''....'' and the embedded ' must be escaped as '''' (sic).

      • For the Set-Location call above, this is handled automatically by using cmd.exe's string-replacement technique on its %CD% variable (%CD:'=''''%).
    • If the script file path or pass-through arguments contain spaces, there mustn't be runs of multiple spaces - if so (which would be very unusual in the case of paths), "-quoting would have to be used. Otherwise, values with spaces must be enclosed in ''...'', as shown with the foo 1 argument above.

    • Since the script file is invoked via -c (-Command) rather than via -f (-File), the interpretation of arguments passed to it may situationally differ - see this answer.


[1] There is a limited workaround: Execution policies only relate to script files, so reading a script file's content into memory and executing that - be it via constructing a script block first or by passing it directly to the usually-to-be-avoided Invoke-Expression - is a way to bypass the active execution policy. A simplified example:
powershell -noprofile -c "Invoke-Expression (Get-Content -Raw c:\path\to\foo.ps1)". That said, the technique won't work if the code executed this way calls other script files, which may also happen implicitly when modules are auto-imported.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.