10

I'm trying to create bat script that can start PowerShell script named the same as bat file in proper working directotry.

This is what I got:

@ECHO OFF
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -WorkingDirectory '%~dp0' -Verb RunAs}"
PAUSE

Passing working directory this way does not work.

How to make script that will pass proper working directroy and also command line arguments?

Hooch
  • 28,817
  • 29
  • 102
  • 161
  • It works for me but in the case `'%~dp0'` evaluates to a directory with a space in it, it won't. For this situation you need to triple double quote the working directory: `"""%~dp0"""` – iRon May 31 '17 at 13:44
  • 1
    You can't set an initial working directory for the process when elevating - it will default to `System32` (or `SysWOW64` for 32-bit process). This is by design. – Bill_Stewart May 31 '17 at 14:49
  • 1
    What about using `Set-Location (Split-Path $MyInvocation.MyCommand.Path)` as the first command in `%~dpn0.ps1` ? –  May 31 '17 at 15:06
  • 1
    Correct - that would be the workaround. Setting a working directory when starting an elevated process has no effect. – Bill_Stewart May 31 '17 at 15:17
  • @LotPings - If you can make answer from you comments I'll accept it. – Hooch Jun 01 '17 at 09:55
  • As an aside: If you were to start PowerShell _Core_'s executable, `pwsh.exe`, `-WorkingDirectory` _would_ be respected. Note that there's never a need for `& { ... }` inside a command string passed to `-Command` (the docs _mistakenly_ used to suggest that that's necessary). – mklement0 Jul 31 '19 at 15:34

2 Answers2

9

The -WorkingDirectory parameter doesn't work when using -Verb RunAs. Instead, you have to set the working directory by calling cd within a -Command string.

This is what I use: (cmd/batch-file command)

powershell -command "   Start-Process PowerShell -Verb RunAs \""-Command `\""cd '%cd%'; & 'PathToPS1File';`\""\""   "

If you want to make a "Run script as admin" right-click command in Windows Explorer, create a new registry key at HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\Run with PowerShell (Admin)\Command, and set its value to the command above -- except replacing %cd% with %W, and PathToPS1File with %1 (if you want it to execute the right-clicked file).

Result: (Windows Explorer context-menu shell command)

powershell -command "   Start-Process PowerShell -Verb RunAs \""-Command `\""cd '%W'; & '%1';`\""\""   "

EDIT: There's an alternative way to have the script be run as admin from Explorer, by using the "runas" sub-key: https://winaero.com/blog/run-as-administrator-context-menu-for-power-shell-ps1-files


If you want to run your script as admin from an existing powershell, remove the outer powershell call, replace %W with $pwd, replace %1 with the ps1 file-path, and replace each \"" with just ".

Note: The \""'s are just escaped quotes, for when calling from the Windows shell/command-line (it's quote-handling is terrible). In this particular case, just \" should also work, but I use the more robust \"" for easier extension.

See here for more info: https://stackoverflow.com/a/31413730/2441655

Result: (PowerShell command)

Start-Process PowerShell -Verb RunAs "-Command `"cd '$pwd'; & 'PathToPS1File';`""

Important note: The commands above are assuming that your computer has already been configured to allow script execution. If that's not the case, you may need to add -ExecutionPolicy Bypass to your powershell flags. (you may also want -NoProfile to avoid running profile scripts)

Venryx
  • 15,624
  • 10
  • 70
  • 96
  • 3
    Nice; however, it's problematic to use `'` for quoting filesystem paths, given that `'` is a legal filename character - better to use `"`. In the case of your last command this means: `Start-Process PowerShell -Verb RunAs "-Command cd \\`"$pwd\\`"; & \\`"PathToPS1File\\`""` – mklement0 Jul 31 '19 at 15:46
  • 1
    Is it possible to pass parameters to the .ps1 file to be executed with PathToPS1File? – Michael Villani Nov 27 '19 at 07:57
  • Also trying to figure this out. I need arguments to be passed in to the script. – fmotion1 Oct 08 '21 at 20:42
5

A workaround is to let the PowerShell script change the directory to it's own origin with:

Set-Location (Split-Path $MyInvocation.MyCommand.Path) 

as the first command.

As per mklement0s hint: In PSv3+ use the simpler:

Set-Location -LiteralPath $PSScriptRoot

Or use this directory to open adjacent files.

$MyDir = Split-Path $MyInvocation.MyCommand.Path
$Content = Get-Content (Join-Path $MyDir OtherFile.txt)