Search code examples
powershellbatch-fileelevated-privileges

Bat File fails to start powershell script without hard-coded directory


My plan is as follows:

  1. Open .bat file
  2. File then opens a PS window with script execution allowed and as admin(!)
  3. Directory must be variable for it to run on any PC in that folder.
  4. Install Chocolatey and Winget for it to install apps.
  5. Must be without user input.

My .ps1 File is named Start.ps1 and the batch file is named Start.bat.

In the current batch configuration, it won't execute the PS window as admin, or with script execution allowed.

PowerShell -NoProfile -ExecutionPolicy Unrestricted -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Unrestricted -File ""C:\Users\user\Desktop\Install\StartNew.ps1""' -Verb RunAs}"

It does work when directory is 1:1, but on different machine it doesn't start the install of chocolatey and winget.


Solution

    • Place your Start.bat and Start.ps1 files in the same directory.

    • Use the following in Start.bat:

    @echo off & setlocal
    
    :: Determine the full path to the companion .ps1 file (Start.ps1)
    :: based on the full path of this batch file (Start.bat)
    set "PS1File=%~dpn0.ps1"
    
    :: Now reference %PS1File% as part of the PowerShell command.
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -Verb RunAs PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"%PS1File%\"'"
    

    Note:

    • You'll still get a UAC prompt to authorize creation of an elevated process (which you could only avoid if you deactivated UAC, which is strongly advised against).

    • As Compo notes, the elevated process will see C:\Windows\System32 as its working directory; if your .ps1 script needs a different one (and doesn't itself change to it), you'll need to switch to a nested -File to a nested -Command call that invokes Set-Location before calling the script.

      • As an aside: If you were to call pwsh.exe, the PowerShell (Core) CLI, instead, the caller's working directory would be preserved (even if you happen to call from Windows PowerShell; see this answer).
    • To fully deactivate the execution policy, use -ExecutionPolicy Bypass rather than -ExecutionPolicy Unrestricted, as shown above. (It typically won't make a difference in practice, but the latter will prompt for scripts that were downloaded from the web).

    • There's no reason to use "& { ... }" in order to invoke code passed to PowerShell's CLI via the -Command (-c) parameter - just use "..." directly, as in the code above. Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.