This question already has answers here:
Set the value of a variable with the result of a command in a Windows batch file [duplicate]
(6 answers)
Assign command output to variable in batch file [duplicate]
(5 answers)
Closed 3 years ago.
I am trying to write a small batch script to install an app from a thumb drive. The problem is the drive letter changes when plugged into different machines depending on the available drive letters. I have the script to run the installation but would like to add a script to the beginning that would detect the assigned drive letter of my inserted thumb drive and store it in a variable that I could then substitute in the rest of the script for the drive letter to complete the installation.
I got the command to identify the assigned drive letter of the thumb drive which works on its own.
wmic logicaldisk where volumename="StacelandFlash" get name
Result: D: (correct)
But I can't seem to assign it to a variable.
set X=wmic logicaldisk where volumename="StacelandFlash" get name
echo X
Result: X
set X=wmic logicaldisk where volumename="StacelandFlash" get name
echo %X%
Result: wmic logicaldisk where volumename="StacelandFlash" get name
Firstly, to capture the output of a command to a variable use for /F. See for /? in a cmd console for full details. Example:
for /f "tokens=2 delims=:" %%I in ('find /c /v "" "notes.txt"') do (
set /a "linecount=%%I"
)
rem // %linecount% now contains the number of lines in notes.txt
Now, there are a couple of complications unique to capturing WMI query results. Firstly, your wmic command includes an equals sign, which will break a for /f. That part's easy enough to fix: either escape the = with a caret (e.g. ^=), or just surround the equation in quotation marks.
The next hurdle is a bit trickier. WMI results are encoded in a non-ANSI encoding (UCS-2 LE). Capturing the output of wmic also captures the output's encoding, resulting in the last character being moved to the beginning of the line or other unexpected behavior. The workaround for that is to use a second nested for /f to sanitize the value.
With all that in mind, I think this is what you're looking for:
#echo off
setlocal
for /f "tokens=2 delims==" %%I in (
'wmic logicaldisk where "volumename='StacelandFlash'" get name /value'
) do for /f "delims=" %%# in ("%%I") do set "driveletter=%%~#"
echo %driveletter%
Note: credit #Dave Benham for discovering this workaround.
You need to run the command within a For Loop.
#Echo Off
For /F "Skip=1 Delims=" %%A In ('
"WMIC LogicalDisk Where (VolumeName='StacelandFlash') Get Name"
') Do For %%B In (%%A) Do Set "USB=%%B"
Echo(%USB%
Timeout -1
I suppose the batch file executed is stored on the thumb drive. And this batch file is executed with a double click. Therefore all you need is:
set "DriveLetter=%~d0"
%~d0 references the drive of argument 0 which is the batch file name. Run in a command prompt window call /? for details on how to reference arguments of a batch file. %~d0 expands to D:, E:, ...
Related
This question already has answers here:
Parse WMIC output to set returned value as a variable (windows batch)
(1 answer)
cmd: save wmic output to variable
(3 answers)
Batch - FOR Loop to Turn WMIC Output Into Variable Not Working
(2 answers)
Batch file get command's output stored in a variable
(2 answers)
Get product name from WMIC for a variable in batch
(1 answer)
Closed 2 years ago.
I need to run the command wmic csproduct get name and transfer the second line to a variable so I can append it to another variable. Most of the results I've found suggest using the below code but it seems like it relies on there being an external text file or batch script to run. Is there a way to run the command within my batch script without the need for another file?
for /f %%i in ('command') do set RESULT=%%i
echo %RESULT%
The for loop does not process a file or external batch, it processes the Command
An example is the Choice command.
You can use this method to return the actual keypress of the command:
For /F "Delims=" %%K in ('CHOICE /N /C:YN') Do Set "Key=%%K"
Which will return a value of either Y or N in the Variable Key
The typical methods of converting command output are:
For /F "Delims=" %%O in ('command') Do Set "Result=%%O"
Or
For /F "UsebackQ Tokens=* Delims=" %%O in (`"command"`) Do Set "Result=%%O"
With the method used differing depending on whether you need to isolate a specific token from the output / need to process a command with quotes.
In your particular instance, you can set the value directly to the value variable with the /format:value switch
For /F "Delims=" %%a in ('"wmic csproduct get name /format:value"') Do (Set %%a>Nul)
Echo(%name%
The >nul component is required as this would otherwise have the result of outputting all environmental variables by enacting Set
I need to backup an existing folder with date-time stamp and replace it (delete and recreate) with new content inside the folder.
Does anyone have a script to do this?
I tried the following code, where %ApplicationDeploymentFolderPath% = \\servername\foldername
IF EXIST %ApplicationDeploymentFolderPath%\Release (
REM Get current date time
#echo off
For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%b_%%a)
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set mytime=%%a%%b)
set backup_folder=%mydate%_%mytime%
MD %ApplicationDeploymentFolderPath%\%backup_folder%
REM Copy current folder to backup folder
Copy %ApplicationDeploymentFolderPath%\Release %ApplicationDeploymentFolderPath%\%backup_folder%
REM Delete Existing Release folder
RD %ApplicationDeploymentFolderPath%\Release /S /Q
)
MD %ApplicationDeploymentFolderPath%\Release
The command date with parameter /T outputs the current date in format defined by configured country for current user account. Exactly the same date string can be accessed by referencing dynamic environment variable DATE for example with %DATE%.
The command time with parameter /T outputs the current time in format defined by configured country for current user account. Exactly the same time string can be accessed by referencing dynamic environment variable TIME for example with %TIME%.
What happens on execution of this command line?
For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%b_%%a)
for respectively cmd.exe processing the batch file starts in background one more command process using %ComSpec% /c with the command line between '. So executed in background is following with Windows installed in C:\Windows:
C:\Windows\System32\cmd.exe /c date /t
The output of command date to handle STDOUT of this command process in background is captured by FOR respectively Windows command processor instance executing the batch file.
The captured line is split up into three substrings using / as string delimiter assigned to the loop variables a, b and c which are concatenated together in reverse order with underscore as delimiter.
This task can be done much faster by replacing 'date /t' by "%DATE%". In this case FOR processes the date string expanded by already running cmd.exe on parsing this command line before executing FOR. So there is no starting of one more cmd.exe in background and capturing its output just to process the same date string which makes batch file execution a bit faster.
The same is true for 'time /t' which can be replaced by "%TIME%".
But the two FOR loops could be completely optimized away by using string substitution as described for example by answer on What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean? and region dependent date and time format is well known for example by running in a command prompt window:
echo %DATE% %TIME%
This command outputs on my computer with German date/time format according to configured country:
24.07.2019 20:15:29,90
It can be seen on this output that the original code would not work on my Windows computer with my account because of date string contains . and not / and time string contains a comma.
So better would be using a region independent solution as explained very detailed in answer on Why does %date% produce a different result in batch file executed as scheduled task? The disadvantage is that execution of wmic.exe takes much longer than cmd.exe needs to reformat date and time string to yyyy_MM_dd_HHmm. However, the batch file is executed most likely not very often per day, and so it does not really matter if execution to get date/time in this format takes some milliseconds or about one second.
Copying the entire folder is not really necessary in this case. It should be enough to rename it with:
ren "%ApplicationDeploymentFolderPath%\release" "%backup_folder%"
The command move could be also used if command ren cannot be used for unknown reasons.
However, the main problem is missing knowledge about how and when to use delayed expansion. Open a command prompt, run set /? and read the output help explaining on an IF and a FOR example delayed environment variable expansion.
The issue here is that backup_folder is not defined on executing the command lines referencing it with %backup_folder% because of all occurrences of %variable% are replaced by Windows command processor already on parsing entire command block starting here with ( on IF condition at top by current value of the referenced environment variable before executing the command IF.
So executed on existing release folder is:
set backup_folder=
MD \\servername\foldername\
REM Copy current folder to backup folder
Copy \\servername\foldername\Release \\servername\foldername\
REM Delete Existing Release folder
RD \\servername\foldername\Release /S /Q
This can be seen by debugging the batch file.
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
The solution is here avoiding the command block by changing the first IF condition.
Fast region dependent solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ApplicationDeploymentFolderPath=\\servername\foldername"
if not exist "%ApplicationDeploymentFolderPath%\Release\" goto CreateFolder
ren "%ApplicationDeploymentFolderPath%\Release" "%DATE:~-4%_%DATE:~-7,2%_%DATE:~-10,2%_%TIME:~0,2%%TIME:~3,2%"
:CreateFolder
md "%ApplicationDeploymentFolderPath%\Release"
endlocal
Slower region independent solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ApplicationDeploymentFolderPath=\\servername\foldername"
if not exist "%ApplicationDeploymentFolderPath%\Release\" goto CreateFolder
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "BackupDateTime=%%I"
set "BackupDateTime=%BackupDateTime:~0,4%_%BackupDateTime:~4,2%_%BackupDateTime:~6,2%_%BackupDateTime:~8,4%"
ren "%ApplicationDeploymentFolderPath%\Release" "%BackupDateTime%"
:CreateFolder
md "%ApplicationDeploymentFolderPath%\Release"
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
ren /?
set /?
setlocal /?
wmic /?
wmic os /?
wmic os get /?
wmic os get localdatetime /?
I have a batch file which copies some local files up to a google storage area using the gsutil tool. The gsutil tool produces a nice log file showing the details of the files that were uploaded and if it was OK or not.
Source,Destination,Start,End,Md5,UploadId,Source Size,Bytes Transferred,Result,Description
file://C:\TEMP\file_1.xlsx,gs://app1/backups/file_1.xlsx,2018-12-04T15:25:48.428000Z,2018-12-04T15:25:48.804000Z,CPHHZfdlt6AePAPz6JO2KQ==,,18753,18753,OK,
file://C:\TEMP\file_2.xlsx,gs://app1/backups/file_2.xlsx,2018-12-04T15:25:48.428000Z,2018-12-04T15:25:48.813000Z,aTKCOQSPVwDycM9+NGO28Q==,,18753,18753,OK,
What I would like to do is to
check the status result in column 8 (OK or FAIL)
If the status is OK then move the source file to another folder (so that it is not uploaded again).
The problem is that the source filename is appended with "file://" which I can't seem to remove, example
file://C:\TEMP\file_1.xlsx
needs to be changed into this
C:\TEMP\file_1.xlsx
I am using a for /f loop and I am not sure if the manipulation of the variables %%A is different within a for /f loop.
#echo off
rem copy the gsutil log file into a temp file and remove the header row using the 'more' command.
more +1 raw_results.log > .\upload_results.log
rem get the source file name (column 1) and the upload result (OK) from column 8
for /f "tokens=1,8 delims=," %%A in (.\upload_results.log) do (
echo The source file is %%A , the upload status was %%B
set line=%%A
set line=!line:file://:=! >> output2.txt echo !line!
echo !line!
)
The output is like this.
The source file is file://C:\TEMP\file_1.xlsx , the upload status was OK
The source file is file://C:\TEMP\file_2.xlsx , the upload status was OK
I'm expecting it to dump the altered values out into a new file but it is not producing anything at the moment.
Normally I would extract from a specific character to the end of the string with something like this but it doesn't work with my For/f loop.
%var:~7%
Any pointers or a different way of doing it greatly appreciated.
Since the part to remove seems fixed it is easier to use substrings.
Also using for /f "skip=1" evades he neccessity of the external command more +1 and another intermediate file.
#echo off & setlocal EnableDelayedExpansion
type NUL>output2.txt
for /f "skip=1 eol=| tokens=1,8 delims=," %%A in (.\upload_results.log) do (
echo The source file is %%A , the upload status was %%B
set "line=%%A"
set "line=!line:~7!"
echo(!line!>>output2.txt
echo(!line!
)
File names and paths can contain also one or more exclamation marks. The line set line=%%A is parsed by Windows command processor a second time before execution with enabled delayed expansion. See How does the Windows Command Interpreter (CMD.EXE) parse scripts? Every ! inside the string assigned to loop variable A is on this line interpreted as begin or end of a delayed expanded environment variable reference. So the string of loop variable A is assigned to environment variable line with an unwanted modification if file path/name contains one or more exclamation marks.
For that reason it is best to avoid usage of delayed expansion. The fastest solution is for this task using a second FOR to get file:// removed from string assigned to loop variable A.
#echo off
del output2.txt 2>nul
for /F "skip=1 tokens=1,8 delims=," %%A in (upload_results.log) do (
echo The source file is %%A , the upload status was %%B.
for /F "tokens=1* delims=/" %%C in ("%%~A") do echo %%D>>output2.txt
)
Even faster would be without the first echo command line inside the loop:
#echo off
(for /F "skip=1 delims=," %%A in (upload_results.log) do (
for /F "tokens=1* delims=/" %%B in ("%%~A") do echo %%C
))>output2.txt
The second solution can be written also as single command line:
#(for /F "skip=1 delims=," %%A in (upload_results.log) do #for /F "tokens=1* delims=/" %%B in ("%%~A") do #echo %%C)>output2.txt
All solutions do following:
The outer FOR processes ANSI (fixed one byte per character) or UTF-8 (one to four bytes per character) encoded text file upload_results.log line by line with skipping the first line and ignoring always empty lines and lines starting with a semicolon which do not occur here.
The line is split up on every occurrence of one or more commas into substrings (tokens) with assigning first comma delimited string to specified loop variable A. The first solution additionally assigns eighth comma delimited string to next loop variable B according to ASCII table.
The inner FOR processes the string assigned to loop variable A with using / as string delimiter to get assigned to specified loop variable file: and to next loop variable according to ASCII table the rest of the string after first sequence of forward slashes which is the full qualified file name.
The full qualified file name is output with command echo and appended either directly to file output2.txt (first solution) or first to a memory buffer which is finally at once written into file output2.txt overwriting a perhaps already existing file with that file name in current directory.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
for /?
See also the Microsoft article about Using command redirection operators for an explanation of the redirections >, >> and 2>nul
I am writing a batch script in which I have to get the currently connected usb devices to the windows. I used this command
C:\Users\Virima>wmic path win32_usbcontrollerdevice get Dependent /format:list
its Output is
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\ROOT_HUB20\4&2851D18A&0""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_8087&PID_0020\5&15BBD570&0&1""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_0781&PID_5567\4C530001030509109324""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USBSTOR\DISK&VEN_SANDISK&PROD_CRUZER_BLADE&REV_1.00\4C530001030509109324&0""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\ROOT_HUB20\4&1C1548F&0""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_8087&PID_0020\5&29432BF7&0&1""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_147E&PID_2016\6&32FEB3AB&0&3""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_0A5C&PID_217F\70F3953D7812""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="BTH\MS_RFCOMM\7&1FB43662&0&0""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="BTH\MS_BTHBRB\7&1FB43662&0&1""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="BTH\MS_BTHPAN\7&1FB43662&0&2""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_04CA&PID_0061\6&32FEB3AB&0&2""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_04CA&PID_0061\7&B449ECA&0&0000""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_046D&PID_C534\6&32FEB3AB&0&1""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_046D&PID_C534&MI_00\7&1501E46C&0&0000""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_046D&PID_C534&MI_00\8&F640D64&0&0000""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="USB\VID_046D&PID_C534&MI_01\7&1501E46C&0&0001""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_046D&PID_C534&MI_01&COL01\8&1473305E&0&0000""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_046D&PID_C534&MI_01&COL02\8&1473305E&0&0001""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_046D&PID_C534&MI_01&COL03\8&1473305E&0&0002""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_046D&PID_C534&MI_01&COL04\8&1473305E&0&0003""
Dependent="\\VIRIMA-009\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_046D&PID_C534&MI_01&COL05\8&1473305E&0&0004""
I want to extract only DeviceID from ouput and use in the registry search.
I am planning to do
`REG QUERY HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\$DeviceID`
Any help will be appreciated.
TL;DR:
for /f tokens^=2^ delims^=^" %A in ('wmic path win32_usbcontrollerdevice get Dependent') do #REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\%A"
Details:
The WMIC.exe command can get what you want.
wmic path win32_usbcontrollerdevice get Dependent
The real challenge here is how to tell FOR to delimit at the dbl-quote character, when the delims argument is already encapsulated with dbl-quotes.
FOR expects the second argument passed to it to contain any 'delims', 'tokens', and 'skip' instructions, surrounded with double-quotes, effectively making all three a single argument. We can create the same effect without dbl-quotes by escaping every space and special character in the set - the escape character is the caret (the {^} character). With escapes in place, and telling for to chop/delimit the line at dbl-quotes, we're ready to chop the WMIC.exe output.
for /f tokens^=2^ delims^=^" %A in ('wmic path win32_usbcontrollerdevice get Dependent') do #echo %A
Now just mix in the 'HKLM' info, along with the REG QUERY command you mentioned, and we have a fully functioning call.
for /f tokens^=2^ delims^=^" %A in ('wmic path win32_usbcontrollerdevice get Dependent') do #REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\%A"
In my BAT file, i want to read these data from .txt file and need to set each data into one variable
SQLUserName=MFiles
WrapperSQLServerName=usa.com
WrapperDatabase=Wrapper
WrapperAssemblyLocation=D:\Assembly
MFilesNetworkAddress=USA-S1
MFilesVaultName=MF2
MFilesUsername=User
MFilesPassword=
MFilesVaultGUID={26F30-E120-408C-8035-04D85D6}
MFilesWebServerURL=www.WebServer.com
SQLMailProfileName=NoReply
WrapperSupportEmail=thejus#WebServer.com
I tried with this code
FOR /F "tokens=2 delims==" %%a IN ('find "WrapperSupportEmail" ^<config.txt') DO SET SupportEmail=%%a
But it throws error
find is not recognized as an internal or external command operable program or batch file
Please help me
Thejus T V
If the schema of your input file is fixed (keyword=value) and you want to assign all values to an environment variabel named keyword it is very, very easy. try this:
for /f "tokens=1,2 delims==" %i in (config.txt) do set %i=%j
remember to change %i and %j to %%i and %%j if you want to put this call into a cmd-file.
when two members with high reputation tell you it works, then it shouldn't be the worst of all ideas to at least try it.
rem #echo off
for /f "delims=" %%i in (config.txt) do set _%%i
pause
set _
I REMd the #echo off, so you can watch, how every single line get's processed.
(Your original error find is not recognized ... is probably because you messed up your %path%-variable, but you don't need find for this task.)
My code is correct one only. Only issue is windows cant locate find.exe. I included the .exe on same location and after that everything works fine.
Its working fine in Win 7 and Win 10 without adding Find.exe