Removing one ShadowCopy with a batch file - batch-file

I'm working on modifying a batch file used for backups. When it runs it creates a new shadowcopy, mounts it, backups what it should, and dismounts it. What I would like to do is have it delete the shadowcopy it created. I don't what to delete existing shadowcopys for forensic reasons. Here is the section of code I'm having and issue with.
:DeleteNewSCopy
REM : Locates then removes the last created shadowcopy.
SET ShadowID=
FOR /F "usebackq tokens=1,2* delims=:" %%A IN (`FINDSTR /I /C:"Shadow Copy ID:" %TempFile%`) DO SET ShadowID=%%B
IF NOT "%ShadowID%" == "" (
REM : Last ShadowCopy ID was found, Nuke it.
vssadmin delete shadows /Shadow=%ShadowID%
) ELSE (
ECHO No ShadowCopy ID found.
)
GOTO :EOF
The FOR line seems to be working correctly. When I ECHO out the %ShadowID% during run-time I get:
ShadowID: {4fcb026a-08fe-4a34-b198-da7560db57bf}
But the line to delete the shadowcopy fails with:
Error: Invalid option value.
In the command line I can set ShadowID to have the same string and run the command without issue, so I seems like it should work in the batch file.
Any assistance will be appreciated.

I found that the problem wasn't with the code it was with how I was pulling the variable ShadowID. It had a leading space that needed to be removed. I used a solution posted by Foumpie to get it fixed.
https://stackoverflow.com/a/12089079/8272143

Related

Copy "can't find file specified" in nested for loop

Copying works fine everywhere else in the program, only seems to mess up inside this nested for loop. Returning "The system cannot find the file specified." (I assume that is the first non-switch argument passed to copy)
Running windows 10,
delayedexpansion IS enabled
Further up in the program I am grabbing .pdf files from a scanning folder, creating a copy in both output and done directories. Later I realized that I needed some type of continuity check to make sure that the files in output were correct (Originally "done" was just used to not re-copy files I had already moved out of the "output" folder). Every pass of the program the "done" folder gets updated with the scanned files (sometimes a file is still getting loaded in from the scanner and gets partially copied).
Tried changing what I give copy in terms of file "%%~nxA" was one of them
SET useableDirectory="C:\Users\IoCalisto\Desktop\custom scan filter\output"
FOR /R "C:\Users\IoCalisto\Desktop\custom scan filter\done" %%A in (*.pdf) do (
IF EXIST "C:\Users\IoCalisto\Desktop\custom scan filter\output\%%~nxA" (
SET useableFile="C:\Users\IoCalisto\Desktop\custom scan filter\output\%%~nxA"
FOR %%B in (!useableFile!) do (
echo File: %%~zB check: %%~zA
IF %%~zA EQU %%~zB echo FILE SIZE CORRECT
IF %%~zA GTR %%~zB (
copy %%A %useableDirectory%
echo %%A
echo %%~nxA
echo !useableFile!
echo %useableDirectory%
)
IF %%~zA LSS %%~zB echo FILE SIZE ERROR, CORRECTING IN NEXT PASS?
echo.
)
)
)
This section of the program is a part of an integrity check to make sure files are complete. The "C:\Users\IoCalisto\Desktop\custom scan filter\done" directory has complete files, and I only want to copy over files that have fewer bits in the output directory. I would like to stay away from just copying everything over from the done folder, because I see this as a learning opportunity.
EDIT: the error happens if the "IF %%~zA GTR %%~zB" conditional is true. The first thing inside the body of the IF statement, is a copy command. The output from this command is in between two echo statements that both work as intended (first is outside the conditional and simply lists the file sizes).
(see attached)

Concatenated text file output from single ECHO command gets characters inserted into string printed a second time after expected output

I'm trying to create a batch file to insert a string from a .txt file at a specific place inside a string in 225 batch files - i.e., inserted into one line in the file at a specific place - but this question concerns the inserting part, and not the loop part, so I've left out the latter in my code example. It's also currently just displaying the text on-screen; not actually writing it to files.
The target files are a bunch of launch .bat files used for running a game server cluster using a tool, so I will have to leave each of them with the same names as they start with (Start XXYY.bat). They contain something along these lines:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit
Where the ServerX, ServerY, AltSaveDirectoryNamen and all three Port settings are unique to each server, so these will have to remain unchanged.
I need to add several more settings, from another .txt file in the final version, but for this example I will just put the additions (the word INSERT added after the ReservedPlayerSlots setting, while keeping each setting divided by question marks) directly into this script.
My code is actually doing exactly what I want it to, but unfortunately it doesn't stop at that point, and decides to append more text than I wanted; specifically, everything I add to the ECHO command which is not a variable name.
To clarify, I get the exact output that I want... Plus the unwanted addition of a bunch of question marks and the word INSERT, which apparently come from my ECHO command, but I just have no idea why they get re-added.
My knowledge of batch scripting is fairly limited, so there might well be something basic that I've overlooked.
I've tried replacing the question marks in the output (which are required to be questions marks in the final version) with normal letters instead, but it doesn't change the behaviour; they were still appended to the expected output, just like the question marks they replaced.
#ECHO OFF
SET FileNum=0000
REM I will have the code loop through 225 files (0000-1414) in the final version, but for test purposes I just set it to one single file number manually here.
SET FileName=Start %FileNum%.bat
REN "%FileName%" temp.txt
FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims=?" %%a IN (temp.txt) DO (
ECHO %%a?%%b?%%c?%%d?%%e?%%f?%%g?INSERT?%%h?%%i?%%j?%%k?%%l
)
REN temp.txt "%FileName%"
I expect this code to output this:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?INSERT?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit
But what I am getting is this:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?INSERT?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit???????INSERT?????
Which is the expected output, but with the unexpected re-addition of every symbol in the ECHO command which did not designate a variable at the end of the output (in this case ???????INSERT?????), just after the exit.
I'm stumped... I hope someone has an idea what I'm doing wrong here.
Okay, I applied the idea that aschipfl provided, and it seems to work now.
The IF NOT "%%b"=="" line seems to have done the trick, after I added the final line with the exit using another ECHO. My full script (including loop and write to file) is now like this:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "Insert=SettingOne=True?SettingTwo=False?SettingThree=1.000000"
FOR /l %%x IN (0, 1, 14) DO (
FOR /l %%y IN (0, 1, 14) DO (
IF %%x LSS 10 (SET XNum=0%%x) ELSE (SET XNum=%%x)
IF %%y LSS 10 (SET YNum=0%%y) ELSE (SET Ynum=%%y)
SET "FileNum=!XNum!!YNum!"
SET "FileName=Start !FileNum!.bat"
ECHO Filename: !FileName!
REN "!FileName!" temp.txt
(
FOR /F "tokens=1-12 delims=?" %%a IN (temp.txt) DO (
IF NOT "%%b"=="" (
ECHO %%a?%%b?%%c?%%d?%%e?%%f?%%g?%Insert%?%%h?%%i?%%j?%%k?%%l
ECHO exit
)
)
) >edited.txt
REN edited.txt "!FileName!"
DEL /q temp.txt
ECHO has been updated
)
)
This is now working exactly as intended.
It's quite possible that there is a more elegant way of doing this, and I am cartain that there is a way of making this more general and less hard-coded, but it's good enough for my purposes.
I thank you for your help!

Get registry key value and change accordingly from multiple PCs

First thank you for this great site! I've learned lots of batch scripting from here, but finally got stuck. I was tasked to write a script that will go out and check a specific registry keyword and change the ones that are not correct, on all PCs on the network.
#echo off
SetLocal EnableDelayedExpansion
FOR /F %%a in (C:\batchFiles\computers.txt) DO (
FOR /F "tokens=3" %%b in (reg query "\\%%a\HKLM\SOFTWARE\some\any" /v "Forms Path") do set "var=%%b"
if "%var%" == "\\server\folder\forms\path"
echo %%a was correct
pause
if "%var%" NEQ "\\server\folder\forms\path"
echo %%a was not correct
pause
)
My boss tasked me with this not to long ago and its a little above my head, so i'm trying to learn on the fly. I tried with %errorlevel% and couldn't get it to do what I wanted either.
I had all of my PC names listed in C:\batchFiles\computers.txt. The REG_SZ key from "Forms Path" is a folder located on a network drive. Right now it says that the syntax is incorrect.
If you can understand what i'm trying to do, and have a better suggestion, I'm all ears! Oh and I'd like to output ALL of the results to a text file so I know which PCs were changed, which ones had it correct, and which ones the script couldn't reach.
Thank you so much for your time!
You enabled delayed environment variable expansion, but do not use it. %var% must be written as !var! to make use of delayed expansion as required here.
The syntax used on both if conditions is also not correct.
The registry query output by reg.exe on my computer running Windows XP is:
! REG.EXE VERSION 3.0
HKEY_LOCAL_MACHINE\SOFTWARE\some\any
Forms Path REG_SZ \\server\folder\forms\path
There is first a blank line, next a line with version of reg.exe, one more blank line, a line with registry key and finally on fifth line the data of interest. Therefore I used in the batch code below skip=4 to speed it up. However, the inner loop would produce the right result also without skip=4 and therefore parsing all 5 lines.
Important is the last line. The inner loop separates by spaces. As the name of the registry value contains also a space character, the first two tokens are for Forms and Path. And the third token is REG_SZ.
The rest of the line after the spaces after REG_SZ is of real interest, but could contain also a space character. So I used in batch code below not tokens=4, but instead tokens=3* and ignored %b which holds REG_SZ. Instead %c is assigned to environment variable var resulting in getting really entire string value even if the string contains 1 or more spaces.
And the environment variable var is deleted before a new query on next computer is executed in case of a computer does not contain the registry value at all. The error message written by reg.exe to stderr is redirected to device nul for this case. The value of var would be unchanged from previous computer if not deleted before running the next query.
#echo off
setlocal EnableDelayedExpansion
for /F %%a in (C:\batchFiles\computers.txt) do (
set var=
for /F "skip=4 tokens=3*" %%b in ('%SystemRoot%\System32\reg.exe query "\\%%a\HKLM\SOFTWARE\some\any" /v "Forms Path" 2^>nul') do set "var=%%c"
if "!var!" == "\\server\folder\forms\path" (
echo %%a has correct value.
) else if "!var!" == "" (
echo %%a does not have the value at all.
) else (
echo %%a has wrong value.
)
pause
)
endlocal

Trying to write a calling batch file but keep getting "cannot find" error

I am trying to write a batch file that calls another which replaces two files in a directory. Here is my code:
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
call C:\%mmcIpath%\spc_we_replace_CED+CEDU.bat
Whenever I set the temporary environment variable, it says the directory cannot be found.
--ADDITIONAL INFO--
I run a Minecraft launcher called MultiMC5; it has a feature which runs commands - but only one command, for some reason. So I wanted it to call a batch file to run multiple commands.
My main batch file is in "C:...\MultiMC\instances", but I want the program to be able to call it. It cannot, as it works within a subdirectory called "CED (210 mods-)". So I placed another batch in the subdirectory to call the main one (I wanted to do the same for a second subdirectory called "CEDU (300+ mods-)"). I got this error: "The system cannot find the path specified.". It happened when I set the path.
I'm using Windows 8.1 and have searched for tips on how to use wildcards and on how to use FOR loops, but none of the wildcard methods have worked for me and I cannot understand FOR loops at all. I have also tried to remove and add things like quotation marks in an attempt to fix it, but that didn't work either.
My question:
Is the set command compatible with wildcards and if so, how do I get this to work?
It looks like your problem is that the main batch file can be on any drive and you want to call other batch files with a path relative to the location of main batch file. Is that correct?
You can get the drive with %~d0, path with %~p0 and drive + path with %~dp0. See the example below and execute this little batch file stored in several different directories:
#echo off
echo Batch is stored on drive %~d0
echo in the directory %~p0
echo resulting in path %~dp0
So you can use argument 0 referenced by %0 containing always name of batch file with full path using the syntax above explained in help of command FOR displayed with entering for /?in a command prompt window to call the other batch files with a path depending on path of the main batch file.
Now what we have here is a classic XY problem - being asked about a solution, not the underlying issue.
Here's a possible resolution:
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
I've left the original setting of mmcIpath in place, and replaced it with a form to suit my system.
The approach is to execute a dir/s/b/ad command (directory, basic format, with subdirectories, directory names only) and filter it using findstr. I chose switches /i (case-insensitive) /e (must end with string) /r regular-expression /c: (following is one string to be matched).
The regex is constructed according to findstr's rules - \ needs to be doubled if it is to be used as a literal; .* means 'any number of any character'
This should provide a list of literal directory names which get through the filter. Look in the directory found for the filename, call the target file if found. The required CALL commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO CALL to CALL to actually execute the files.
The following ECHO GOTO is there to show that the loop can be broken after finding the first target file, if desired. You havent't indicated whether you want to run only the first or run all of the targets found.
Here's my test source. I use U: for testing data. Your system would likely be different.
#ECHO OFF
SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
set "mmcIpath=\mmc-stable-win32\MultiMC\instances"
FOR /l %%a IN (1,1,4) DO MD u:\%%a%mmcIpath% 2>nul
FOR /l %%a IN (2,2,4) DO COPY NUL u:\%%a%mmcIpath%\spc_we_replace.bat 2>NUL >nul
ENDLOCAL
ENDLOCAL
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
Note that the first section is merely establishing u:\1\mmc-stable-win32\MultiMC\instances to u:\4\mmc-stable-win32\MultiMC\instances then creating a dummy file spc_we_replace.bat in u:\2\mmc-stable-win32\MultiMC\instances and u:\4\mmc-stable-win32\MultiMC\instances.
The string assigned to mmcIath in the second section is according to findstr's syntax rules - each \ is doubled, .* means "any number of any character". You would have to modify that string to suit your system. Note that "%mmcIpath:~0,3%" gratuitously takes the first 3 characters from the string. In my case, that would be U:\. YMMV

Removing lines from a txt file in batch

I need to check for certain processes (its a list of 20ish processes, so wont list them all), and record which ones are running. Then I need to kill them, run some other code, and finally reopen them... The code will only run successfully if all the processes have been ended.
I'd welcome any suggestions, or just someone to explain why my code doesn't work.
What I've been doing, is using tasklist to check for each process, and write the results to a file, then I'm trying to remove the lines of the file where the process is not running (i.e. I get an "INFO:..." message)
I know that I have done something similar before, where I've taken each line of a file one at a time (in a for loop), replaced a string of text within it, and sent the edited line to another file (which is probably not the most efficient way of doing it, but it worked).
For some reason, I can't replicate it now...
The code I've got (whch is failing) is
SETLOCAL ENABLEDELAYEDEXPANSION
cd\
for /f "tokens=* delims= " %%a in (somefile.txt) do (
set q=INFO: No tasks are running which match the specified criteria.
set r=%%a
set s=!r:%q%=!
echo %s% >>test.txt
)
If anyone knows of a better way to do what I need, I'm happy to change my plan, but it does need to be done through batch (CMD), or I'd be happy with some one fixing the above code at least.
Thanks
Try this code. Though I'm not sure if the output file matches the one you want. Make sure to surround the parameter with double quotes if it contains any space.
taskchk.cmd:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
if "%1" == "" (
echo Please specify criteria.
echo e.g.: taskchk myprocess.exe
goto :eof
)
cd\
type nul>test.txt
set found=0
for /f "tokens=*" %%a in ('tasklist /nh') do (
for /f "tokens=1" %%b in ("%%a") do (
if /i "%%b" == "%~1" (
set found=1
) else (
echo %%a>>test.txt
)
)
)
if %found% == 0 echo INFO: No tasks are running which match the specified criteria.>>test.txt

Resources