2

Based on How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required? I'm trying to make an RunElevated.bat (see code below) that accepts a command-line (batch file name and parameters) as arguments.

The RunElevated.bat works fine when the target batch file path has no spaces in them. But it fails as soon as that path has spaces: no matter how I quote things, either PowerShell barfs, or the parameters are not passed correctly from PowerShell to the batch file.

I tried:

  1. escaping with "" (as suggested by many sources)
  2. escaping with \" (as suggested by Escaping quotes in powershell.exe -command via command prompt)
  3. adding --% (as suggested by PowerShell and external commands done right and Easier Reuse of Command Lines From Cmd.exe)
  4. surrounding with ' (as suggested by CB.). So:

    • Is what I want to do possible at all?
    • If so: how?

RunElevated.bat:

:checkParameters
  echo [%*]
  if [%1]==[] ( goto :help ) else ( goto :checkPrivileges )

:help
  echo Syntax:
  echo   %0 CmdLine
  echo Where CmdLine is executed with UAC privileges.
  goto :exit

:checkPrivileges 
  net file 1>nul 2>nul
  if '%errorlevel%' == '0' ( goto :gotPrivileges ) else ( goto :getPrivileges )

:getPrivileges
  PowerShell "Start-Process -FilePath \"%0\" -Verb RunAs -ArgumentList \"%*\""
  goto :exit

:gotPrivileges
  %*
  pause

:exit
  pause
  exit /b 

echo-cd.bat which I stored in both D:\tools\echo-cd.bat and "D:\to ols\echo-cd.bat":

echo Current Directory: [%CD%]
echo Parameters: [%*]
pause

This runs fine:

D:\tools\RunElevated.bat D:\tools\echo-cd.bat foo

These fail:

D:\tools\RunElevated.bat "D:\to ols\echo-cd.bat" foo

First failure is at the %*:

C:\Windows\system32>D:\to ols\echo-cd.bat foo
'D:\to' is not recognized as an internal or external command,
operable program or batch file.

This is because PowerShell removed the quotes around the batch file name:

C:\Windows\system32>echo [D:\to ols\echo-cd.bat foo]
[D:\to ols\echo-cd.bat foo]

I expected D:\to ols\echo-cd.bat to have double quotes around it, and foo not.

D:\tools\RunElevated.bat \"D:\to ols\echo-cd.bat\" foo

Second failure is at the PowerShell level:

D:\>PowerShell "Start-Process -FilePath \"D:\tools\RunElevated.bat\" -Verb RunAs -ArgumentList \"\"D:\to ols\echo-cd.bat\" foo\""
Start-Process : Cannot validate argument on parameter 'ArgumentList'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
At line:1 char:77
+ Start-Process -FilePath "D:\tools\RunElevated.bat" -Verb RunAs -ArgumentList <<<<  ""D:\to ols\echo-cd.bat" foo"

This is because escaping twice will end up with an empty string for ArgumentList.

D:\tools\RunElevated.bat --% "D:\to ols\echo-cd.bat" foo

Third failure is also at the %*:

C:\Windows\system32>--% D:\to ols\echo-cd.bat foo
'--%' is not recognized as an internal or external command,
operable program or batch file.

This too is because PowerShell removed the quotes around the batch file name:

C:\Windows\system32>echo [--% D:\to ols\echo-cd.bat foo]
[--% D:\to ols\echo-cd.bat foo]

I expected --% to be absent, D:\to ols\echo-cd.bat to have double quotes around it, and foo not.

D:\tools\RunElevated.bat '"D:\to ols\echo-cd.bat"' foo

Again a failure is at the %*:

C:\Windows\system32>'D:\to ols\echo-cd.bat' foo
The filename, directory name, or volume label syntax is incorrect.

This is because PowerShell removed the double quotes (and left the single quotes) around the batch file name:

C:\Windows\system32>echo ['D:\to ols\echo-cd.bat' foo]
['D:\to ols\echo-cd.bat' foo]

C:\Windows\system32>if ['D:\to] == [] (goto :help  )  else (goto :checkPrivileges  )
4
  • what about: D:\tools\RunElevated.bat "'D:\to ols\echo-cd.bat\'" foo? Commented Jul 14, 2014 at 12:46
  • @CB. that results in this error: C:\Windows\system32>'D:\to ols\echo-cd.bat\' foo The filename, directory name, or volume label syntax is incorrect.. With the last backslash removed, I get C:\Windows\system32>'D:\to ols\echo-cd.bat' foo The filename, directory name, or volume label syntax is incorrect. Commented Jul 14, 2014 at 13:14
  • Yes sure... the last backslash was'nt would, forgot to delete it! Anyway try: D:\tools\RunElevated.bat '"D:\to ols\echo-cd.bat"' foo Commented Jul 14, 2014 at 13:20
  • @CB. that's the second error message in my above comment: it fails too (: I've added your suggestion to the list in my question for future readers. Commented Jul 14, 2014 at 14:56

3 Answers 3

1

I recall using the following approach for this:

start "" %systemroot%\System32\windowspowerShell\v1.0\powershell.exe -exec bypass -noprofile -command "&{ start-process powershell -verb RunAs -ArgumentList '-noprofile -exec bypass -file \"c:\temp\test folder\elevatedpowershell.ps1\"'}"

You can replace \"c:\temp\test folder\elevatedpowershell.ps1\" with \"$0\" like you did there. I also found the solution from Keith Hill on self elevating PowerShell to be useful if I need the person to be admin. I do not have the link now but it goes like this:

function IsAdministrator
{
    $Identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $Principal = New-Object System.Security.Principal.WindowsPrincipal($Identity)
    $Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}


function IsUacEnabled
{
    (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System).EnableLua -ne 0
}

if (!(IsAdministrator))
{
    if (IsUacEnabled)
    {
        [string[]]$argList = @('-NoProfile', '-File', ('"' + $MyInvocation.MyCommand.Path + '"'))        
        $argList += $MyInvocation.BoundParameters.GetEnumerator() | Foreach {"-$($_.Key)", "$($_.Value)"}        
        $argList += $MyInvocation.UnboundArguments        
        Start-Process "$env:Windir\System32\WindowsPowerShell\v1.0\PowerShell.exe" -Verb Runas -WorkingDirectory $pwd -WindowStyle Hidden -ArgumentList $argList                        
        return
    }
    else
    {
        throw "You must be administrator to run this script"
    }
}

Assuming, you want to have elevated PowerShell script, you can have that at the top of your PowerShell script.

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

1 Comment

I'll try to test these somewhere later. For now I've just removed an special characters from the directory trees I inherited to maintain.
0

Ugly but it can do the job.

Use single quotes (or any character of your choice) and insert this in your code:

:gotPrivileges
  cd "%~p0"
  set arg=%*
  set arg=%arg:'="%
  %arg%

::  %*
  pause

1 Comment

Thanks. It means loosing the single quote for other means, so I might do this with another character.
0

If you have 8.3 file names enabled you can try this:

:getPrivileges
  setlocal enabledelayedexpansion
  set Args=%*
  for %%a in (%*) do if exist %%a (
            set Args=!Args:%%a="%%~sa"!
            )
  PowerShell "Start-Process -FilePath \"%0\" -Verb RunAs -ArgumentList \"%Args%\"" 2>nul
  goto :exit

However, if you pass an argument that happens to be the name of a file or folder (that exists relative to RunElevated.bat) it can get altered.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.