Should be able to sort this but I'm going round in circles. I know this has to do with setlocal EnableDelayedExpansion, but I'm missing something.
Goal: Execute a windows (cleanmgr.exe) script on a remote machine, wait till Cleanmgr.exe closes then have the initiating script "type" the resultant log file (generated via cleanup script) from the remote system in the CMD window.
What's working: The script running on the remote machine runs fine, it echo's C: free drive space into a log file, then cleans up the PC, and then re runs the disk space report and echo's result into same log file, so the user can see (/have transparency of) the reclaimed space via the before & after results.
What's Broken: The WMIC command to check for Cleanmgr.exe on the target PC, only works once, when it waits to retry the variable containing the Hostname has been wiped out. I can see the behavior by echoing the variable back.
Fix Attempts: I have a hunch this has to do with the variable being lost once the if statement is ran within the Parentheses. I have tried lots of options but they all behave the same. I have tried jumping the process out to loop outside the original code using %1 instead of %%i but just cant quite get there.
Thanks for any improvements.
@echo off
pushd %~dp0
color 1e
setlocal EnableDelayedExpansion
title HDD Space Checker...
for /f %%i in (hostnames.txt) do (
xcopy /y cleanupwindows-sfd.bat \\%%i\C$\IT
WMIC /node:"%%i" process call create "C:\IT\cleanupwindows-sfd.bat"
echo Waiting For Processes...
timeout -t 10 /nobreak >nul
:loop
WMIC /node:"%%i" process where name="cleanmgr.exe" get name |find "cleanmgr.exe">nul
IF "!errorlevel!"=="0" set running=var
IF "!running!"=="var" timeout -t 4 >nul & echo Still Running & goto :loop
IF "!running!"=="" timeout -t 4 >nul & type \\%%i\C$\IT\%%i_HHD_Space.log
)
pause
exit
There is at least two points to see.
running
variable, once set, is never reset, triggering an infinite loopgoto
statement inside the enclosing parenthesis drives the command interpreter (cmd.exe) to stop evaluating the block, thus your script loose the %%i
and leave the for loop, thus when terminating the :loop
cycle your script will leave the for loop without cycling to other values in hostnames.txt
.To address that, put your process code in a subroutine called with CALL
and reset the running
variable at each :loop
cycle :
@echo off
pushd %~dp0
color 1e
setlocal EnableDelayedExpansion
title HDD Space Checker...
for /f %%i in (hostnames.txt) do (
CALL:Process "%%i"
)
pause
exit
:Process
xcopy /y cleanupwindows-sfd.bat \\%~1\C$\IT
WMIC /node:"%~1" process call create "C:\IT\cleanupwindows-sfd.bat"
echo Waiting For Processes...
timeout -t 10 /nobreak >nul
:loop
set "running="
WMIC /node:"%~1" process where name="cleanmgr.exe" get name |find "cleanmgr.exe">nul
IF "!errorlevel!"=="0" set "running=var"
IF "!running!"=="var" timeout -t 4 >nul & echo Still Running & goto :loop
IF "!running!"=="" timeout -t 4 >nul & type \\%~1\C$\IT\%~1_HHD_Space.log
GOTO:EOF
Explanations: The CALL
statement implies that the command interpreter will store the current executed line of your script and its state before executing the associated subprocess/command/etc.. When the subprocess/command/etc.. finishes, the command interpreter resumes its execution of the script to the next line with a restored context. This avoids then the loose of the for loop context.