简体   繁体   中英

Batch: How to store command output with spaces in variable?

I want to make a Batch file to create windows firewall rules for an executable (for example, python). To do this, I have the following script:

REM ~ Open ports. Run with elevated administrator rights.
CALL :OPEN "python"
GOTO :EOF

:OPEN
IF ERRORLEVEL 1 (
  GOTO :EOF
)
FOR /F %%i IN ('where %1') DO CALL :OPEN_PROGRAM "%1" %%i && GOTO :EOF
GOTO :EOF

:OPEN_PROGRAM
FOR %%j IN (TCP UDP) DO CALL :OPEN_PROGRAM_PORT %1 %2 "%%j"
GOTO :EOF

:OPEN_PROGRAM_PORT
netsh advfirewall firewall add rule name=%1 description=%1 dir=in action=allow edge=deferuser     profile=private program=%2 protocol=%3
GOTO :EOF

This works fine as long as there are no spaces in the path to the executable.

If there are spaces in the path, then only the part up to the spaces is put in the %%i variable. I tried using 'where /F %1' , but then it still cuts the output on the space.

Is there a way to store the full output of where %1 in a variable? (Preferably without writing it to a file)

I would first advise you not to pass an filename without an extension. Doing so relies upon each of the extensions listed under %PATHEXT% , and you could have files named python.com , python.bat , python.cmd , python.vbs , python.vbe , python.js , python.jse , python.wsf , python.wsh , and python.msc , as well as python.exe . I'm sure you wouldn't want to unknowingly create firewall rules for all of those.

I would also advise that you do not use the where command for this. The reason being that it could return more than a single item. For example, try this, where notepad.exe and if memory serves, you'll probably see, C:\\WINDOWS\\System32\\notepad.exe , followed by C:\\WINDOWS\\notepad.exe . That is because where.exe searches each location in %PATH% in order of their listing, and returns each, as the first two entries under %PATH% should by default be C:\\WINDOWS\\system32;C:\\WINDOWS; .

My suggestion therefore would be to use another method, which returns the first item found under %PATH% as opposed to all, and this should, if you've used the variable properly, return the default, (most used) item. The method is the %~$PATH variable expansion, and is documented under the help information for the for command, ie entering for /? at the Command Prompt.

Example Script:

@Echo Off
SetLocal EnableExtensions
Rem ~ Open ports. Run with elevated administrator rights.
"%__AppDir__%reg.exe" Query HKU\S-1-5-19 1>NUL 2>&1 || (
 Echo This script must be run elevated.
 Echo Please use 'Run as administrator'
 "%__AppDir__%timeout.exe" /T 3 /NoBreak 1>NUL
 GoTo :EOF)
Call :OpenPorts "python.exe"
Pause
GoTo :EOF
 
:OpenPorts
For %%G In ("%~1") Do For %%H In (TCP UDP) Do (
 "%__AppDir__%netsh.exe" AdvFirewall Firewall Add Rule^
 Name="%~n1" Description="%~1" Dir=in Action=allow^
 Edge=deferuser Profile=private Program="%%~$Path:G"^
 Protocol=%%H)
Exit /B

I have removed all of the unnecessary Call commands, (using just the one) , and deliberately used carets to split up your super long line, for readability; (which also allows you to include the localport= and/or remoteport= option, which I'd assume by your 'Open Ports' name you're going to want to include as a modification to the above later) . I also took the liberty of including some code, to determine if the script was being run elevated, and display a message before closing, if it isn't.

Write the output of where.exe to a file, then read the file one line at a time. There is a way to do it without a temp file after the "===" line.

@ECHO OFF
SET "XTOFIND=%~1"
SET "TEMPFILE=%TEMP%\wherelist.tmp"
IF EXIST "%TEMPFILE%" (DEL "%TEMPFILE%")

"%__appdir__%where.exe" "%XTOFIND%" >"%TEMPFILE%"

FOR /F "tokens=*" %%A IN ('TYPE "%TEMPFILE%"') DO (
    ECHO CALL :OPEN_PROGRAM "%%~A" %2 "%%J"
)

IF EXIST "%TEMPFILE%" (DEL "%TEMPFILE%")

ECHO ============

SET "XTOFIND=%~1"
FOR /F "tokens=*" %%A IN ('"%__appdir__%where.exe" "%XTOFIND%"') DO (
    ECHO %%~A
    ECHO CALL :OPEN_PROGRAM "%%~A" %2 "%%J"
)
EXIT /B 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM