Batch To Find All Drive Letters Of Specific Path Mapping - batch-file

We had a script push out to map a new drive, but net use R: /Delete was not used so the drive is still there and there are incorrect mappings to the next available letter for hundreds of users. I need to delete all incorrect mappings and was hoping there was a batch script that would scan for a specific mapping and then pipe the drive letter.
Set Path = \\Drive\Folder
Set DriveLetter = ?Scan all mapped drives for %Path%?
Net Use %DriveLetter% /Delete
Looking to fill in the blanks here.

Please do not use the PATH variable for your own purposes. It is a reserved variable, and using it for anything other than its intended use can wreak havoc on your batch session.
Here is a solution using WMIC that works. The backslashes must be escaped with another backslash when passed to WMIC. The check for a 2nd token is an artifact of how FOR /F treats the unicode output of WMIC.
#echo off
setlocal enableDelayedExpansion
set "remotePath=\\Drive\Folder"
for /f "usebackq skip=1 tokens=1,2" %%A in (
`wmic netuse where "RemotePath='!remotePath:\=\\!'" get localName 2^>nul`
) do if "%%B" neq "" <nul net use %%A /delete >nul 2>&1 || net use %%A /delete
I'm not sure what is going on, but the first attempt to delete the mapped drive fails with the following message: "There are open files and/or incomplete directory searches pending on the connection to n:.". The second attempt succeeds.

net use will show drive mappings (connected or not)
example output:
New connections will be remembered.
Status Local Remote Network
-------------------------------------------------------------------------------
Disconnected Q: \\Server1\Drive
Microsoft Windows Network
OK S: \\Server2\Drive2
Microsoft Windows Network
The command completed successfully.
looking at this output, the 2nd column, gives us the drive letter, and the 3rd gives us the path. putting this into a for /f loop to check the path, and if it matches delete the drive letter in the 2nd part
for /f "tokens=2,3" %%a in ('net use') do if .%%b==.\\Server\DriveCaseSensitive net use %%a /Delete
This means that it will also detect and remove mappings if the drive has been mapped multiple times

Related

Bat script which creates ISO from a CD/DVD drive

Stack community good day! Thank you in advance for your time
I would like to create a bat file in order to autocreate an iso file from the DVD drive. So the logic will be:
Find which is the CD/DVD drive (from many drives)
And use that result as a variable (of the drive: for example F:) which will be executed in the following command:
cdbxpcmd.exe --burn-data -folder:F:\ -iso:C:\donalds.iso -format:iso
So in the previous command, the F:\ will be the variable, lets say %input%:\ which the program cdbxpcmd will use in order to create an iso from that drive.
I have found the following script that finds the drive letter,
from here: https://itectec.com/superuser/windows-how-to-detect-dvd-drive-letter-via-batch-file-in-ms-windows-7/
#echo off
setlocal
for /f "skip=1 tokens=1,2" %%i in ('wmic logicaldisk get caption^, drivetype') do (
if [%%j]==[5] echo %%i
)
endlocal
Do you believe that we could combine them? And how? Any suggestions?
You could use cdbxpcmd.exe itself to locate your drive:
Two line batch-file example:
#Set "CDBXP=C:\Program Files\CDBurnerXP\cdbxpcmd.exe"
#For /F "Tokens=2 Delims=()" %%G In ('^""%CDBXP%" --list-drives^"') Do #"%CDBXP%" --burn-data -folder:%%G -iso:"C:\donalds.iso" -format:iso
Just change the location where you have your cdbxpcmd.exe command line utility between the = and the closing " on line 1.
Alternatively, you could still use WMI, but personally, I would not use Win32_LogicalDisk, I would instead use Win32_CDROMDrive, which could verify both that a CDROM disk is loaded, and that it contains readable data.
Single line batch-file example:
#For /F Tokens^=6^ Delims^=^" %%G In ('%SystemRoot%\System32\wbem\WMIC.exe Path Win32_CDROMDrive Where "MediaLoaded='True' And DriveIntegrity='True'" Get Drive /Format:MOF 2^>NUL') Do #"C:\Program Files\CDBurnerXP\cdbxpcmd.exe" --burn-data -folder:%%G\ -iso:"C:\donalds.iso" -format:iso
Just change the location where you have your cdbxpcmd.exe command line utility, remembering to leave the doublequotes in place for best practice.

How to fix appending a timestamp when moving a folder on a remote server to a new location on the remote server?

I am trying to run a batch script on my local machine that will take care of some log archiving on some servers. I can access the servers via file explorer "\SERVERNAME\C$\SOME FOLDER." When I attempt to xcopy from the source to the destination locally and append a timestamp its like the TIMESTAMP variable doesn't store my date/time concatenation.
This is for windows 2012r2 servers, I've tried to append just the date\time to the end which works fine, however, its not the desired format I am looking for and it starts nesting the directory with the date but no time and it looks like a mess. :(
I've also tried to use the wmic however this is the first time I am writing a batch file to automate some tasks so all this has been a great learning experience.
I've tried to echo %TIMESTAMP% and nothing returns? I've even tried to add the concatenation (%CUR_YYYY%%CUR_MM%%CUR_DD%-%CUR_HH%%CUR_NN%%CUR_SS%) directly to the file directory and its doesn't work :(
REM Check to see if a service on the machine is stopped (it is always stopped by the time it gets here) before we move the files from the logging directory to a new one.
for /F "tokens=3 delims=: " %%H in ('sc \\REMOTESERVER query "SOME SERVICE NAME" ^| findstr " STATE"') do (
if /I "%%H" == "STOPPED" (
REM substring the date and time and then concat it together at the end to make the desired timestamp variable
set CUR_YYYY = %date:~10,4%
set CUR_MM = %date:~4,2%
set CUR_DD = %date:~7,2%
set CUR_HH = %time:~0,2%
set CUR_NN = %time:~3,2%
set CUR_SS = %time:~6,2%
set CUR_MS = %time:~9,2%
set TIMESTAMP = %CUR_YYYY%%CUR_MM%%CUR_DD%-%CUR_HH%%CUR_NN%%CUR_SS%
REM copy files from the servers source directory and then move the files to a newly created logging folder with a timestamp appened at the end
echo d | xcopy /f /y "\\REMOTE SERVER\src" "\\REMOTE SERVER\dest\Logging_%TIMESTAMP%" /E /I
REM delete the contents of the servers source directory to keep things nice and clean
pushd \\REMOTE SERVER\src && del . /F /Q popd
)
)
The expected result would look like:
SourceFolder on the server will be there but empty
DestinationFolder will have a new Logging folder created Logging_20190325010101 and within the newly created logging folder all the contents from the SourceFolder should be there.
You need to get rid of the whitespace before and after your = in your set commands, also, You need delayedexpansion in the codeblock with changing variables, and there is a better way to get rid of the colons and comma.
#echo off
setlocal enabledelayedexpansion
REM Check to see if a service on the machine is stopped (it is always stopped by the time it gets here) before we move the files from the logging directory to a new one.
for /F "tokens=3 delims=: " %%H in ('sc \\REMOTESERVER query "SOME SERVICE NAME" ^| findstr " STATE"') do (
if /I "%%H" == "STOPPED" (
REM substring the date and time and then concat it together at the end to make the desired timestamp variable
set "CUR_YYYY=%date:~10,4%"
set "CUR_MM=%date:~4,2%"
set "CUR_DD=%date:~7,2%"
set "mytime=!time::=!"
set "mytime=!mytime:,=!"
set "TIMESTAMP=!CUR_YYYY!!CUR_MM!!CUR_DD!-!mytime!"
REM copy files from the servers source directory and then move the files to a newly created logging folder with a timestamp appened at the end
echo d | xcopy /f /y "\\REMOTE SERVER\src" "\\REMOTE SERVER\dest\Logging_!TIMESTAMP!" /E /I
REM delete the contents of the servers source directory to keep things nice and clean
pushd \\REMOTE SERVER\src && del . /F /Q popd
)
)
To explain your issue however, when you set a variable, the whitespace comes as part of the variable.. So:
set variable = value
Will result in a variable with a trailing space %variable % and a value with a leading space <space>value So we always get rid of the whitespace and best to use double quotes to eliminate possible whitespace after the value. for instance:
set "variable=value"
which will create %variable% and value
Within parenthetical code blocks you have to delay expansion when retrieving variable values in the same block in which they were set. For example:
(
set "test=1"
echo [%test%]
)
... would echo "[]" because %test% was retrieved within the same parenthetical code block in which it was set. At the time %test% is evaluated, it has no value. You must delay expansion either by using setlocal enabledelayedexpansion or by using call echo [%%test%%] (or cmd /c or similar). When using setlocal enabledelayedexpansion, you delay expansion by using ! instead of % to denote variables. See setlocal /? and set /? in a cmd console for more information -- particularly the section of set /? that begins "Finally, support for delayed environment variable expansion has been added."
Also, it's much simpler and more locale agnostic to compose your timestamp using wmic os get localdatetime. Example:
for /f "delims=." %%I in ('wmic os get localdatetime /value ^| find "="') do set "%%~I"
echo %localdatetime%
That should result in %localdatetime% containing the current numeric value of YYYYMMDDHHMMSS.

output net view (batch) into text then perform action against each computer

I have been trying to find away to search for the existence of my company's software on PC's by searching hostnames on the network \\computername\c$\Program Files\Foo, and if it finds it, copy over an updated config etc.
I've seen that net view will out put all the PC's on the network, something like this:
\\DISKSTATION
\\JWLAPTOP
\\TEST
\\XP
The command completed successfully.
I was wondering if there was a way to just get the computer names in a clean list (without "command completed" etc.):
\\DISKSTATION
\\JWLAPTOP
\\TEST
\\XP
Then run some commands against it, for everything in hostnames.txt, if exist:
\\JWLAPTOP\c$\Program Files\Foo --> do copy xyz to wherever
I can take care of the part \c$\Program Files\Foo as a variable to add after the computer names in the text file.
Hope that makes sense, thanks for any tips.
edit
Been re thinking this perhaps there is a more direct way to do this....
I need to see the list of PC's on customers network.....net view is a good way of getting this info so far, but I further need to see which ones are online. Any online, query for folder and update a *.CFG file, any offline, output to text for reference.
So at the minute....
FOR /F "tokens=1 delims= " %%G IN ('net view ^|findstr /L /B /C:"\\"')
this is working great, I then made it output to a text file..
FOR /F "tokens=1 delims= " %%G IN ('net view ^|findstr /L /B /C:"\\"') DO (echo %%G>>%~dp0netview.txt)
However, the %%G echo's back \somecomputer which means I am struggling to get a new line..
for /f %%G in (%~dp0netview.txt) DO (ping etc......
to ping because of the \ before the computer name. So was wonder if we can make the list 'just" have the PC name without the \ before it.
Also this is the content of the .cfg file I need to edit...
<?xml version="1.0" encoding="utf-8"?>
<ClientConfigurationFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ServerPath>**\\server\shared\data**</ServerPath>
<ApplicationMode>Workstation</ApplicationMode>
<VRPath />
<ServicePollingInterval>0</ServicePollingInterval>
</ClientConfigurationFile>
perhaps there is a way of editing a certain section of this directly once its existence is found. \server\shared\data...in bold is what I need to update often when clients have new servers and things and involves having to go round lots of rooms to update manually. This batch could save hours upon hours of unnecessary work.
over writing the existing .cfg file is still a good way of doing it if it's too tricky or not possible directly.
Hope it makes sense, thanks for the replies!!!
Assuming none of your computer names have spaces in them.
#echo off
FOR /F "tokens=1 delims= " %%G IN ('net view ^|findstr /L /B /C:"\\"') DO (
IF EXIST "%%~G\c$\Program Files\Foo" copy "C:\folder\xyz.txt" "C:\other folder\"
)
If you want the leading back slashes stripped then use it as a delimiter just like I am using the space as a delimiter to get rid of all the extraneous NET VIEW output.
#echo off
FOR /F "tokens=1 delims=\ " %%G IN ('net view ^|findstr /L /B /C:"\\"') DO (
PING %%G
IF EXIST "\\%%~G\c$\Program Files\Foo" copy "C:\folder\xyz.txt" "C:\other folder\"
)
You could do the following:
#echo off
setlocal EnableExtensions
set "TARGET=C$\Program Files\Foo"
for /F "eol=| delims=" %%C in ('
net view ^| find "\\"
') do (
pushd "%%C\%TARGET%"
if not ErrorLevel 1 (
rem do your operations here...
copy "\your\source\path\xyz" "."
popd
)
)
endlocal
The for /F loop walks through all host names returned by net view (supposing each one starts with \\ and there are only the host names).
Since the resulting path (for instance \\TEST\C$\Program Files\Foo) is a UNC path which is not supported by several commands, pushd is used, which is capable of connecting to the given resource by establishing a temporary drive letter like Z:, and changing the working directory to its root immediately (if the command extensions are on, which is the Windows default).
The query if not ErrorLevel 1 is used to skip over the remaining commands in case pushd could not connect to the resource for some reason.
After all your operations, popd ensures that the temporary drive created by pushd is unmounted and that the former working directory is restored.

Batch file read INI file from UNC path

So, I've been working on a batch file to collect specific system information, I've run into a road block with opening an INI file that's on the network installation. So obtaining the path is:
for /f "tokens=2*" %%a in ('REG Query "HKCU\SOFTWARE\Zephyr Associates, Inc." /v StyleDir 2^>nul') do set "StyleDir=%%~b"
for /f "tokens=2*" %%a in ('REG Query "HKLM\SOFTWARE\Zephyr Associates, Inc." /v StyleDir 2^>nul') do set "StyleDir=%%~b"
for /f "tokens=2*" %%a in ('REG Query "HKLM\SOFTWARE\Wow6432Node\Zephyr Associates, Inc." /v StyleDir 2^>nul') do set "StyleDir=%%~b"
cd %StyleDir%
So in this scenario, let's say %StyleDir% is //Server/StyleDir/
Later on in the script we read the Style.ini file with the following:
for /f "tokens=2 delims==" %%a in ('findstr SQLiteHome style.ini') do set SQLiteHome=%%a
for /f "tokens=2 delims==" %%a in ('findstr Server style.ini') do set SQL=%%a
for /f "tokens=2 delims==" %%a in ('findstr DataHome style.ini') do set DataHome=%%a
At this point I get an error saying we're unable to read the Style.ini. Within the Style.ini I have the following:
[Default]
DataHome=C:\ProgramData\Zephyr\Data\
SQLiteHome=C:\ProgramData\Zephyr\Data\
[DataBaseList]
Tons of other lines I don't need to read Right now....
Later I populate a txt file that records the information. That script is as follows:
::Output
echo StyleDir: %StyleDir% >> SystemInformation.txt
echo SQLiteHome: %SQLiteHome% >> SystemInformation.txt
echo SQL Server: %SQL% >> SystemInformation.txt
echo DataHome: %DataHome% >> SystemInformation.txt
So is there a special way that I could get this info recorded from the INI file? I've had thoughts about temporarily mapping a network drive, but the problem with that is knowing what network drives are already mapped so that I don't break what's already there. I'm not even 100% sure that this has to do with the UNC path at all, I just know that when the INI is locally on C:\ that it can be read, but on the network it cannot. Any suggestions for what to try?
Another thing I've noticed is that I can open the Style.ini from a batch file just fine, regardless of the location. I just can't Read it for some reason.
You said:
I just know that when the INI is locally on C:\ that it can be read,
but on the network it cannot.
That's not true. You can read ini files with UNCs like this:
\\ServerName\directory\any.ini
The error may be somewhere else, such as unmatched quotes, authentication or missing file. Knowing what the exact error message you get would help debug the precise reason.
Expanded in response to complete error msg:
CMD does not support UNC paths
Implies removing this line
cd %StyleDir%
in your batch file as you cannot cd unless you map to a drive letter first. Consult map /help for details. Or you can avoid cd'ing to that folder by fixing the findstr command to use the UNC directly, such as:
findstr stringToSearch \\full\UNC\path\to\file.ini
Which option you choose will depend on what is being done to the found strings. You mention you are populating those strings, but not where. If populating to a file on the remote server, use the drive map option. If populating locally, then use the UNC option.
I figured it out, all you have to do is use
pushd \\server\dir
instead of
cd \\server\dir
when pointing to the path. Figures it would be something easy. I still get an error, but it'll proceed past it, which is fine by me :-)

Store those filenames in a variable that were not copied to the destination using batch

I have created a batch file that is copying filese and sub folders from source to destination. I have suppressed all sorts of errors.
Following is the code which I am using currently:
Echo ****Copying...****
XCOPY "C:\Users\xxxxxx\Desktop\Source" "D:\xxxxx\Destination" /S /E /V /Y /R /C
Echo ****Files Copied Successfully...****
PAUSE
Now what I want to do is that once the file copying is complete it should display the list of all those files that were not copied to the destination due to some error.
Thanks in advance...
Redirect output and errors to one file with >logfile.txt 2>&1 and then postprocess the logfile.txt using for /F command:
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
set "source=d:\bat\*.txt"
set "target=d:\xxx\ddd"
xcopy "%source%" "%target%" /i /s /e /y /c>%temp%\xcopyall.txt 2>&1
set /A "goodfiles=-1"
set /A "bad_files=0"
set "filename=%source:~0,2%"
set "errdescr=%filename%"
for /f "tokens=* delims=)(" %%G in ('type "%temp%\xcopyall.txt"') do (
set "errdescr=%%G"
call :posterr
)
echo %bad_files% File[s] not copied
:::: %goodfiles% File[s] copied
#ENDLOCAL
goto :eof
:posterr
set "errdescr=%errdescr:(=[%"
set "errdescr=%errdescr:)=]%"
rem previous line == a filename?
if /i "%filename:~0,2%"=="%source:~0,2%" (
rem current line == a filename?
if /i "%errdescr:~0,2%"=="%source:~0,2%" (
set /A "goodfiles+=1"
) else (
rem rem current line == 'nnn File[s] copied'?
if /i "%errdescr:File[s] copied=%"=="%errdescr%" (
set /A "bad_files+=1"
echo %filename:&=^&% %errdescr:&=^&%
) else (
set /A "goodfiles+=1"
)
)
)
set "filename=%errdescr%"
goto :eof
Fixed:
attended end of logfile, i.e. nnn File(s) copied text
literal value "d:" replaced by dynamic "%source:~0,2%"
auxiliary counters for both (not)copied items with improved test logic (cf. comments in code)
tested for file names containing !, %, & (see output), by virtue of dbenham, thanks...
The script still might appear unsufficient, one could refine it for possible more complicated scenarios (tested for Access denied error at target side only).
Output:
d:\bat>vbserr2
D:\bat\CPs2\unicMacCE.txt Access denied
D:\bat\files\11per%cent.txt Access denied
D:\bat\files\12per%cent%.txt Access denied
D:\bat\files\13per%OS%cent.txt Access denied
D:\bat\files\14per%%OS%%cent.txt Access denied
D:\bat\files\15per%3cent.txt Access denied
D:\bat\files\16per%%3cent.txt Access denied
D:\bat\files\17per%Gcent.txt Access denied
D:\bat\files\18per%%Gcent.txt Access denied
D:\bat\files\1exclam!ation.txt Access denied
D:\bat\files\21ampers&nd.txt Access denied
D:\bat\files\22ampers&&nd.txt Access denied
D:\bat\files\2exc!lam!ation.txt Access denied
D:\bat\files\rand.txt Access denied
14 File[s] not copied
However, Xcopy has been deprecated already (although still available now). Use other tools (such as Robocopy) instead.
You can detect if a file is an error by looking for a line that is followed by another line that does not begin with a digit, and whose 2nd character is not a colon.
In order to do this programmatically, you must redirect stderr to stdout using 2>&1 to get all data in one stream.
JosefZ redirected everything to a file, and post-processed with a FOR /F loop to extract the error messages.
Below is a more efficient solution that pipes the output to JREPL.BAT - a hybrid JScript/batch utility that performs a regular expression search/replace on text. JREPL.BAT is pure script that runs natively on any Windows machine from XP onward.
xcopy "C:\Users\xxxxxx\Desktop\Source" "D:\xxxxx\Destination" /s /e /v /y /r /c /I 2>&1 | ^
jrepl "^(.+\n)(\D[^:][^\r\n]*)\r\n/^.*\n" "'***'+$3+': '+$2/stderr.Write($0);''" /m /j /t "/"
I used line continuation just to make the code a bit easier to read.
The /M option allows searches to span multiple lines.
The /J option treats the replacement value as JScript code
The /T option is similar to the unix tr command. Both search and replace arguments contain a like number of values, delimited by /. The first replace value is used if the first search term matches, else the 2nd replace value is used for the 2nd search term.
The first search term looks for a file name, followed by an error message. If found, then the two lines are replaced by a single line using the format ***eror message: filePath. Since this is a multi-line search, the result is not displayed until the entire search/replace is done.
The second search term (only used if first failed to match) simply matches the entire line. This line is immediately output to stderr before replacing the value with an empty string.
The end result is that successful files and the summary are first output to the console using stderr, followed by the error files with error message on stdout.
Below is a test sample output:
D:test.bat
D:test.js
D:test.log
D:test.txt
D:test.txt.bad
D:test.vbs
D:test2.bat
D:test3.bat
D:test\test(1).txt
D:test\test(10).txt
D:test\test(11).txt
D:test\test(2).txt
D:test\test(3).txt
D:test\test(5).txt
D:test\test(6).txt
D:test\test(7).txt
D:test\test(8).txt
D:test\test(9).txt
D:test\test.txt
19 File(s) copied
***Access denied: D:test.csv
***Access denied: D:test\test(4).txt
The output is bass-ackwards in that error messages are on stdout, and success messages are on stderr.
If desired, you can capture the entire result in log file by appending >xcopy.log 2>&1
Or you could separate the log into good and bad using >xcopy.err 2>xcopy.log.

Resources