Zend certified PHP/Magento developer

How to Escape & (Ampersand) or @ (At Sign) in Batch File Name when Passing File Name to PowerShell via a For Loop in cmd on Windows 10

We are using a .cmd batch script in cmd on Windows 10 and Windows Server 2016/2019 with a “header” that

  • copies the file to the %Temp% folder location and then
  • requests administrative privileges via a UAC elevation prompt. After the batch file runs from the %Temp% folder, it
  • deletes itself from the %Temp% folder while keeping the original file.

This all works fine unless there are files with

  • & (ampersand) in the file name or
  • @ (at sign) with at least one space in the file name.
    However, without spaces, @s don’t bother the script.

I have successfully escaped the following characters that would stop the script from working otherwise, e.g.

  • (
  • )
  • ,
  • ;

Here is the code for the script:

@echo off
Title %~n0
GoTo Begin
:End

::"Self-destruction" part that deletes batch file copy in %Temp% folder and confirms whether file was actually deleted.

Start /min cmd /c (@echo off^&Title "%~nx0" Temp Batch File Deletion^&echo [93mDeleting file "%Temp%%~nx0" . . . [39m^&TimeOut 5 /NoBreak ^>nul 2^>^&1^&Del /a "%Temp%%~nx0"^&ClS^&If Exist "%Temp%%~nx0" ^(echo [91mFile "%Temp%%~nx0" could not be deleted![39m^&Pause ^>nul 2^>^&1^) else ^(echo [92mFile "%Temp%%~nx0" deleted successfully![39m^&TimeOut 5 /NoBreak ^>nul 2^>^&1^))
If NOT Defined Elev (@TimeOut 5 /NoBreak >nul 2>&1)
GoTo :EoF

:Begin

::Setting variable %_nx0% derived from %~nx0 with several characters escaped for copying file to %Temp% folder

Set "_nx0=%~nx0"
Set "_nx0=%_nx0:(=^(%"
Set "_nx0=%_nx0:)=^)%"
Set "_nx0=%_nx0:,=^,%"
Set "_nx0=%_nx0:;=^;%"
Set "_nx0=%_nx0:&=^&%"
Set "_nx0=%_nx0:@=^@%"
Set "_nx0=%_nx0: =^ %"

::Setting variable %_dpnx0% derived from %~dpnx0 with several characters escaped for passing file name to PowerShell

Set "_dpnx0=%~dpnx0"
Set "_dpnx0=%_dpnx0:)=^)%"
Set "_dpnx0=%_dpnx0:,=^,%"
Set "_dpnx0=%_dpnx0:;=^;%"
::How to escape & and @ for passing to PowerShell's "Start-Process" in when in a cmd "For" loop?
Set "_dpnx0=%_dpnx0:&=^^^&%"
Set "_dpnx0=%_dpnx0:@=^^^@%"
Set "_dpnx0=%_dpnx0: =^ %"

::Just a test line to debug new variables
::echo %_nx0%&echo %_dpnx0%&TimeOut 3 >nul

::Commands to confirm whether file is in %Temp% folder and to copy it there if it isn't

If NOT "%~dp0" == "%Temp%" (Copy /y "%~dpnx0" "%Temp%" >nul 2>&1&&Start cmd /c "%Temp%%_nx0%"&&exit /b)

::Commands to confirm via PowerShell command whether file is run with admin privileges and to request them by restarting script via PowerShell's "-Verb RunAs" command if file is run without admin privileges
::a "For" loop is used to set variable %Elev% to pass elevation confirmation from PowerShell's "$?" command back to cmd as "True" or "False"
::If file is run with admin privileges run :Main part below and end script with :End self-destruction command above
::If File is run without admin privileges end script via ":EoF" command

net file >nul 2>&1
If %ErrorLevel%==0 (Call :Main&GoTo End) Else (
    For /f "Tokens=* UseBackQ" %%f in (`PowerShell -NoLogo -Command "& { Start-Process "%_dpnx0%" -Verb RunAs;$? }"`) Do (Set "Elev=%%f"))
If %Elev%==False (GoTo End) else (GoTo :EoF)
:Main

::Main part of script after header

echo [38;5;202mTesting the batch header . . . [39
TimeOut /t 5 >nul

This script includes ANSI escape sequence Select Graphic Rendition (SGR) parameters to color the text echoed by the script.
The character before [ (opening square bracket) is “” (ASCII escape character without quotes).
It doesn’t show up on all screens, therefore, I have inluded a copy of this script here.

If the batch files have the following file names, the script runs fine:

  • FileName12345.cmd (just numbers and/or letters)
  • File Name 12345.cmd (numbers and/or letters with spaces)
  • (File), ; . Name 12345.cmd (numbers and/or letters with spaces and the working characters from above)
  • File@Name12345.cmd (numbers and/or letters and at least one @ sign without any spaces)

These file names create problems:

  • File&Name12345.cmd (at least one & sign in the file name)
  • File @ Name12345.cmd (at least one @ sign with at least one space)

Does anyone know how to escape these and any other characters correctly in the script above?

There may be easier ways of creating such a script, however, the higher-ups only greenlight the usage of this script using cmd and PowerShell for whatever reasons. They also don’t want to bother with changing the input file names probably for ad-hoc cost reasons.

Thanks for any help with this.