Passing Unicode parameters to Windows .bat file when rerunning it

3.6k views Asked by At

My .bat file looks like this:

@echo off

CD /D "%~dp0"

if [%2]==[] (  
    set user=%USERNAME%
) else (
    set user=%2%
)

:getFile
if [%1]==[] (
    set /p file=Enter file name : 
) else (
    set file=%~f1
    echo File name: %~f1
)

:checkFile
for /f "useback tokens=*" %%a in ('%file%') do set file=%%~a

if not exist "%file%" (
    echo Error: Could not find file: %file%
    echo.
)

:: Check for admin permissions
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

if '%errorlevel%' == '0' (
    goto gotAdmin
)

:: Rerun this batch with admin rights
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "cmd", "/c """"%~f0"" ""%file%"" ""%user%""""", "%CD%", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
exit /B

:gotAdmin
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
pushd "%CD%"
CD /D "%~dp0"

echo.

:eof
pause
exit /B

I have these two test files:

  1. C:\Test\Folder\ファイル.txt
  2. C:\Test\フォルダ\File.txt

When I run the batch file above and drag 1 onto the cmd window I get:

enter image description here

, which is good.

When I do the same for 2, I get:

enter image description here

When I call UAC.ShellExecute, %file% isn't passed correctly.

How can I get around this problem?

3

There are 3 answers

2
roeland On BEST ANSWER

My preferred way of starting a batch file with administrator permissions is to create a shortcut, and then mark that shortcut as requiring administrator permissions.

First right-click foo.bat, then create a shortcut. Open the properties for that shortcut, click the Advanced… button and enable Run as administrator.

This has a downside: you can't drag file names onto the resulting command prompt window. But you can drag a file onto the shortcut.

But what if I don't want or can't use a shortcut?

You can avoid the need to write arbitrary Unicode characters to the file by passing your file name as an argument to your script. Even if the VBS file is in ANSI encoding, the script host always uses Unicode internally.

So here is how you write the VBS file and run it:

:: Rerun this batch with admin rights
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "cmd", "/c """"%~f0"" """ + Wscript.Arguments.Item(0) + """ ""%user%""""", "%CD%", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs" "%file%"
exit /B
0
Peter Brittain On

Your problem is that the way you create your temporary VBS file means it is not a valid unicode file and so Windows doesn't know how to interpret the unicode name you have passed in.

Following beercohol's advice to use code page 65001, I still found that I could not access a file in a unicode directory. However, if I tried to create the file by hand with a unicode editor (e.g. using notepad and saving as a unicode encoding) and invoke that manual script instead of the autogenerated VBS file, it all just worked.

I've re-worked your script to use iconv to create a utf-16 file instead. Note that this script needs to be run with code page 65001 in order to work.

@echo off

CD /D "%~dp0"

if [%2]==[] (  
    set user=%USERNAME%
) else (
    set user=%2
)

:getFile
if [%1]==[] (
    set /p file=Enter file name : 
) else (
    set file=%~f1
    echo File name: %~f1
)

:checkFile
for /f "useback tokens=*" %%a in ('%file%') do set file=%%~a

if not exist "%file%" (
    echo Error: Could not find file: %file%
    echo.
)

:: Check for admin permissions
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

if '%errorlevel%' == '0' (
    goto gotAdmin
)

:: Rerun this batch with admin rights
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "cmd", "/c """"%~f0"" ""%file%"" ""%user%""""", "%CD%", "runas", 1 >> "%temp%\getadmin.vbs"
iconv.exe -f utf-8 -t utf-16le "%temp%\getadmin.vbs" > "%temp%\getadmin2.vbs"
"%temp%\getadmin2.vbs"
exit /B

:gotAdmin
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
if exist "%temp%\getadmin2.vbs" ( del "%temp%\getadmin2.vbs" )
pushd "%CD%"
CD /D "%~dp0"

echo.

:eof
pause
exit /B
4
beercohol On

Try adding a CHCP (CHange Code Page) command to start of you batch file, using the UTF-8 code page 65001, e.g:

@echo off

chcp 65001
.
.
.

See here for a bit more info on code page identifiers: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx

EDIT: You MUST also use a unicode capable font such as Lucida Console for your command window. Without this the command processor chokes on the unicode characters, and will either not find the files, or may display a "system cannot write to the specified device" error.

Click the window icon at the top-left of the command window, choose Defaults on the menu, then on the Fonts tab choose Lucida Console.

UPDATE - Test batch file and output below.

Here's the batch file I'm using to test this:

@echo off

chcp 65001

CD /D "%~dp0"


:getFile
if [%1]==[] (
    set /p file=Enter file name : 
) else (
    set file=%~f1
    echo File name: %~f1
)

:checkFile
for /f "useback tokens=*" %%a in ('%file%') do set file=%%~a

if not exist "%file%" (
    echo Error: Could not find file: %file%
    echo.
) else (
    echo Found file "%file%"
)

Here is the output from my test, when I drag firstly "C:\temp\test\ファイル.txt" into the window, then secondly "C:\temp\test\フォルダ\file2.txt".

My system is Win 7 Pro x64 SP1, with English UK settings.

Sample output