Search code examples
powershellbatch-file

PowerShell wont work as admin with double quotes


The problem is that the '-Verb RunAs' wont work with '\"' for some reason and I need the quotes for better handeling of paths

:: Check for admin privilage
openfiles > nul 2>&1
if !errorlevel! neq 0 (
    echo | set /p="The execution needs elevated privileges (y|n)"
    choice /n
    if !errorlevel! equ 1 (
        start /b /wait PowerShell -Command "Start-Process '%~f0' -ArgumentList '%res% -ico \"%icon%\" -dir \"%directory%\"' %style% -Verb RunAs"
        exit /b
    )
)

when I remove one of them the other works

::like this
start /b /wait PowerShell -Command "Start-Process '%~f0' -ArgumentList '%res% -ico \"%icon%\" -dir \"%directory%\"' %style%"

::or this
start /b /wait PowerShell -Command "Start-Process '%~f0' -ArgumentList '%res% -ico %icon% -dir %directory%' %style% -Verb RunAs"

Or when I convert it into an executable it works

I don't know why is that happening maybe a glitch or something I hope someone finds a solution


Solution

  • To spell it out: You're trying to create a self-elevating batch file, i.e. one that reinvokes itself with elevated (administrative) privileges while passing arguments through.

    You appear to have hit a bug where reinvoking a batch file with arguments that are enclosed in "..." syntactically breaks the invocation of the target process when elevation is requested via PowerShell's Start-Process -Verb RunAs. I don't know for sure, but I suspect that the bug is at a level below PowerShell.

    The workaround is to call the batch file via cmd.exe /C and to enclose the entire argument list passed to the latter in "..." overall, in addition to the "..." enclosure of individual arguments

    • To provide a simple example: the process command line that must ultimately be launched has to look something like this - note the - unescaped - outer "..." that encloses the double-quoted batch-file path and all pass-through arguments, which may be individually double-quoted:

      "C:\Windows\System32\cmd.exe" /c ""c:\path\to\my.cmd" -foo "bar""
      

    Here's a self-contained, streamlined demonstration of the workaround, incorporating incidental improvements suggested by Compo.

    @echo off & setlocal enabledelayedexpansion
    
    :: ...
    
    :: Check for admin privileges
    net sessions > nul 2>&1 || (
      choice /m "The execution needs elevated privileges"
      if !errorlevel! equ 1 (
            echo Relaunching with elevation and arguments and waiting for completion...
            start /b /wait "" PowerShell -NoProfile -Command "Start-Process -Wait -Verb RunAs cmd.exe -ArgumentList '/C \"\"%~f0\" %res% -ico \"%icon%\" -dir \"%directory%\"\"' %style%"
            exit /b
      ) else (
            echo Elevation request declined. >&2
            exit /b 1
      )
    )
    
    :: Getting here means that the batch file runs elevated.
    
    echo Running elevated; args given: [%*]
    
    pause