Get the last name of a directory path in batch - windows

I've been tasked with writing installation scripts for my company that will be able to install printer drivers on a users computer.
What I have done so far is I've made the script accept a parameter (the printer type brother, xerox, etc..) from there it will gather the relative path to the drivers, and run a forfiles command on the path outputting all the drivers, after that it will ask the user for the correct driver copy it from the network drive to the users desktop, and run it.
What I need to do is the running part, I need to copy the driver to the desktop and somehow get the last directory part (example: user\desktop\test.exe I need to gather the last part test.exe) how can I go about doing this in a functional way?
Basically I would need to split the path by \ and grab the last entry of that list, is this possible in batch?
#echo off
type banner.txt
if [%1]==[] goto usage
:verify_argv
IF '%1'=='canon' GOTO get_canon_path
IF '%1'=='xerox' GOTO get_xerox_path
IF '%1'=='hp' GOTO get_hp_path
IF '%1'=='dell' GOTO get_dell_path
IF '%1'=='brother' GOTO get_brother_path
goto :eof
:get_canon_path
set dir_path=\\mgtutils01\windows7apps\PRINTERS\Canon
goto :install_drivers
:get_xerox_path
set dir_path=\\mgtutils01\windows7apps\PRINTERS\Xerox
goto :install_drivers
:get_hp_path
set dir_path=\\mgtutils01\windows7apps\PRINTERS\HP
goto :install_drivers
:get_dell_path
set dir_path=\\mgtutils01\windows7apps\PRINTERS\Dell
goto :install_drivers
:get_brother_path
set dir_path=\\mgtutils01\windows7apps\Brother\Drivers
goto :install_drivers
:usage
#echo Usage: .\driver [PRINTER_TYPE]
exit /B 1
:install_drivers
#echo Finding drivers...
pushd "%dir_path%"
forfiles /s /m *.exe /c "cmd /c echo #relpath"
set /p to_install="Copy the path of the correct driver and paste here: "
#echo Copying file to %USERPROFILE%, please wait..
xcopy %to_install% "%USERPROFILE%\Desktop"
#echo Installing driver..
pushd "%USERPROFILE%\Desktop"

To get the last element of a file or directory path, you can:
either use a for loop and its ~ modifiers:
set "ITEM=user\desktop\test.exe"
for %%I in ("%ITEM%") do set "NAME=%%~nxI"
echo %NAME%
or call a sub-routine by the call command, pass the path as an argument and again use ~ modifiers:
set "ITEM=user\desktop\test.exe"
call :SUB "%ITEM%"
goto :EOF
:SUB
set "NAME=%~nx1"
goto :EOF
For both variants, the ~nx part extracts the base name (n) and the extension (x) from the last element of the path stored in the reference (%%I or %1). Type for /? and call /? into a command prompt window and read the help texts; you will find all the possible ~ modifiers of for variable references and argument references, respectively.

Related

Batch decrypt folders while keeping directory structure?

I have thousands of encrypted files in the directory D:\Data. They are of different file extensions. For example D:\Data\a.txt and D:\Data\Sub\b.jpg.
I also have a decrypt.exe. The usage is:
decrypt <input file> [output file=input] [option]
The option I use is -o.
Now I need to decrypt all the files to D:\Data_2 with the original folder structure.
Can someone tell me how this task could be done with a Windows batch file?
I know little about Windows batch file coding and therefore don't know where to start.
Here is a commented batch code for this task:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "SourcePath=D:\Data"
set "TargetPath=D:\Data_2"
rem If the batch file was started with a string as
rem parameter, interpret this string as source path.
if not "%~1" == "" set "SourcePath=%~1"
rem If the batch file was started with one more string
rem as parameter, interpret this string as target path.
if not "%~2" == "" set "TargetPath=%~2"
rem Remove backslash at end of source and target path
rem in case of being specified with a backslash at end.
if "%SourcePath:~-1%" == "\" set "SourcePath=%SourcePath:~0,-1%"
if "%TargetPath:~-1%" == "\" set "TargetPath=%TargetPath:~0,-1%"
rem Determine length of source path by finding out at which
rem position in source path there is no more character.
set "PathLength=1"
:GetPathLength
if not "!SourcePath:~%PathLength%,1!" == "" (
set /A PathLength+=1
goto GetPathLength
)
rem Process each file not having hidden or system attribute set and
rem decrypt it to the target path relative to source path. The relative
rem path is determined by removing from full path of current file the
rem first PathLength characters and the last character which is the
rem directory separator (backslash).
for /R "%SourcePath%" %%I in (*) do (
set "RelativePath=%%~dpI"
set "RelativePath=!RelativePath:~%PathLength%,-1!"
md "%TargetPath%!RelativePath!" 2>nul
decrypt.exe "%%I" "%TargetPath%!RelativePath!\%%~nxI" -o
)
endlocal
It is possible to test this batch file with a dry run by inserting left of md and decrypt.exe the command echo to just output the lines which really modify something on storage media.
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.
call /? ... for an explanation of %~1 and %~2.
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
rem /?
set /?
setlocal /?
And read also the Microsoft article about Using command redirection operators for an explanation of 2>nul used to redirect the error message output by command md to handle STDERR on directory already existing to the device NUL to suppress it.
See also Microsoft's command-line reference and SS64's A-Z Index of the Windows CMD command line.

Windows: start a file using a (non-default) shell verb like "edit" from .bat or command-line

How can I start a file with an associated non-default command (shell verb) like "edit", "print", ... from command-line or from a .bat script by using standard Windows means.
(Those extra actions which you get offered on top upon right-click on a file in the Windows Explorer.)
Thus getting the effect of
python -c "import os;os.startfile('somepic.png', 'edit')"
(ShellExecuteEx), but without using extra tools like python, powershell, or so.
The START command does not seem to offer that.
As learned from the comments and after further searching: there seems to be no direct command for that task in standard Windows indeed.
However using a VBScript snippet should be highly compatible and have lowest system requirements. (Works on all machines here directly - from XP - unlike JScript)
VBScript has been installed by default in every desktop release of
Microsoft Windows since Windows 98;1 in Windows Server since Windows
NT 4.0 Option Pack;[2] and optionally with Windows CE (depending on
the device it is installed on).
Example script shellexec.vbs :
' shellexec.vbs : starts a file using a (non-default) shell verb like "EDIT"
' Usage: shellexec.vbs FILE VERB
' Example: shellexec.vbs demo.png EDIT
fn = WScript.Arguments(0)
cmd = WScript.Arguments(1)
Wscript.Echo "ShellExecute """ + cmd + """ on " + fn
CreateObject("shell.application").ShellExecute fn, "", "", cmd, 1
Use from command-line or batch-file:
shellexec.vbs demo.png EDIT
or:
cscript.exe //Nologo shellexec.vbs demo.png EDIT
An example to show how to do it with an one-liner:
mshta vbscript:Execute("CreateObject(""shell.application"").ShellExecute""%SystemDrive%\autoexec.bat"","""","""",""edit"",1:close")
It will open the dummy autoexec.bat file with the application defined to edit .bat files (by default, Notepad).
It is possible to do with batch code what is done by command START for default action of opening a file with associated application.
In the commented batch code below the shell verb must be specified in third line being assigned to environment variable ActionCommand.
The name of the file to edit, printto, ... must be specified as first parameter of the batch file.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "ActionCommand=edit"
rem Check if batch file was started with name of an existing file.
if "%~1" == "" set "ErrMsg=No file name specified as argument on starting %~nx0" & goto OutputError
if exist "%~1\" set "ErrMsg="%~f1" is a directory and not a file" & goto OutputError
if not exist "%~f1" set "ErrMsg=A file "%~f1" does not exist" & goto OutputError
rem Check if specified file has a file extension. Files starting with . and
rem not containing at least a second . are also files with no file extension.
if "%~n1" == "" set "ErrMsg=File "%~f1" has no file extension" & goto OutputError
if "%~x1" == "" set "ErrMsg=File "%~f1" has no file extension" & goto OutputError
rem On Windows Vista and later REG.EXE outputs without version info for example:
rem HKEY_CLASSES_ROOT\.txt
rem (Default) REG_SZ txtfile
rem There are only spaces used to separate value name, value type and value string.
rem But REG.EXE version 3.0 outputs on Windows XP with version info for example:
rem ! REG.EXE VERSION 3.0
rem
rem HKEY_CLASSES_ROOT\.txt
rem <NO NAME> REG_SZ txtfile
rem NOTE: There are 4 indent spaces and 2 separating tabs in REG 3.0 output line.
rem So either token 2 or token 3 contains value type REG_SZ
rem used to identify the line with the wanted information.
set "TypeToken=2"
rem Get name of registry key associated with extension of specified file.
:GetAssociatedKey
for /F "skip=1 tokens=%TypeToken%*" %%A in ('%SystemRoot%\System32\reg.exe query "HKCR\%~x1" /ve 2^>nul') do (
if "%%A" == "REG_SZ" set "KeyName=%%B" & goto GetCommand
if "%%A" == "NAME>" set "TypeToken=3" & goto GetAssociatedKey
)
set "ErrMsg=No file assocation found for %~x1 in registry" & goto OutputError
:GetCommand
for /F "skip=1 tokens=%TypeToken%*" %%A in ('%SystemRoot%\System32\reg.exe query "HKCR\!KeyName!\shell\%ActionCommand%\command" /ve 2^>nul') do (
if "%%A" == "REG_SZ" set "ActionCommand=%%B" & goto PrepareCommand
if "%%A" == "REG_EXPAND_SZ" set "ActionCommand=%%B" & goto PrepareCommand
)
set "ErrMsg=No edit command found for %~x1 in registry" & goto OutputError
rem Replace "%1" or %1 by full name of specified file in double quotes or
rem append a space and full name of specified file if the command string
rem does not contain "%1" or %1 at all. Then expand the command string.
:PrepareCommand
set "ActionCommand=!ActionCommand:"%%1"="%~f1"!"
set "ActionCommand=!ActionCommand:%%1="%~f1"!"
if "!ActionCommand:%~f1=!" == "!ActionCommand!" set "ActionCommand=!ActionCommand! "%~f1""
call set "ActionCommand=%ActionCommand%"
rem Run the command with current directory set for the application to folder
rem of specified file without checking if the executable file exists at all.
rem Command start displays an error message box which must be confirmed by
rem the user by a click on button OK and outputs the error message also to
rem console if the executable to start could not be found.
start "" /D"%~dp1" %ActionCommand%
endlocal
goto :EOF
:OutputError
echo %~f0
echo.
echo Error: !ErrMsg!.
echo.
echo Press any key to exit batch processing ...
endlocal
pause >nul
This batch file might not work for all possible action commands, but it should work for 99.5% of all edit, printto, ... commands.
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.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
reg query /?
rem /?
set /?
setlocal /?
start /?
Not sure if this is what you are looking for, but using the START command opens the file I want to edit in the default program.
START "" "Mypdf.pdf"
START "" "Myfile.txt"
START "" "Myjpg.jpg"
ETCETERA ETCETERA........

How to check the result of an overwrite file request in Windows CMD?

I have searched online for this, but can't seem to find an answer. I have code that creates a text file after asking one what name he/she would like to give the text file. The file is then opened after being created. However, if I choose N (No) to an overwrite request, I don't want the file to open. I would instead want to be asked again to specify another file name after saying N (No) to the overwrite request.
I however have no idea as to how to check the answer given to the overwrite request.
Also, I would need the entire code to be in one line.
This is what I have without the extras that I am mentioned above:
cmd /c #ECHO OFF & SET /P filename=What File name: & cmd /v /c copy /-y NUL !filename!.txt & cmd start /v /c start notepad !filename!.txt & Exit
Later Added:
I am working on the following and keep getting the error message "( was unexpected at this time." after the filename is echoed. If I edit the file by commenting parts out so that it works, and then continue to edit it to what I currently have, it still works. However, if I exit the cmd box, and then start it again, then it doesn't work and I get an error message. This is the code thus far:
#echo off
SET /P filename=What File name?
echo %filename%
::loop
if exist !filename!.txt (
echo File Exists
SET /P overwrite=Overwrite File?
echo overwrite is %overwrite%
If %overwrite%==Y (
echo "Yes, Y"
)
)
echo finish
If I put single quotes around %overwrite% in If '%overwrite%'==Y I no longer get the unexpected error message. The problem I still face though is when exiting the session / the cmd box, I can't get the line above to echo the value of overwrite. It just says "overwrite is" (without quotes and with no value after it). If I continue in the same session running the batch file over again, I get a value for overwrite.
Solution to unable to echo value of %overwrite% (user input) from if statement can be found here.
edited to adapt to comments
cmd /v:on /q /c "for /l %a in (0 0 1) do (set /p "file=file? " & if exist "!file!" ( set "q=" & set /p "q=overwrite? " & if /i "!q!"=="y" ( type nul > "!file!" & start "" notepad "!file!" & exit ) ) else ( type nul > "!file!" & start "" notepad "!file!" & exit ))"
As requested, in one line. To include it inside a batch file, replace %a with %%a
edited one line, with input validations and error checks added on file operations, and shortened (variables length reduced, unneeded spaces removed, file creation code deduplicated, ...) to fit into windows "Run" dialog
edited added initial cd /d "%userprofile%" to ensure the working folder is writeable. Why? Because from windows 7, including the /v:on (or off) in the call to cmd from the windows Run dialog (the OP reason for a one liner), the active directory for the command is c:\windows\system32 (or wherever the system is). Without the /v switch, the active directory is the user profile folder.
cmd /v:on /q /c "cd/d "%userprofile%"&for /l %a in () do ((set/p"f=file? "||set "f=")&(if defined f if exist "!f!" ((set/p"q=overwrite? "||set "q=0")&if /i not "!q!"=="y" (set "f=")))&if defined f (type nul>"!f!" &&(start "" notepad "!f!" &exit)))"
edited After a lot of tests i make it fail in XP. The previous code will fail if the machine is configured with command extensions disabled. Also, the problem with Ctrl-C can be anoying. This should handle the first problem and minimize the second.
cmd /v:on /e:on /q /c "cd/d "%userprofile%"&for /l %a in ()do ((set/p"f=file? "||(set f=&cd.))&(if defined f if exist "!f!" ((set/p"q=overwrite? "||(set q=&cd.))&if /i not "!q!"=="y" (set f=)))&if defined f (cd.>"!f!"&&(start "" notepad "!f!" &exit)))"
It is better to avoid overwriting by copy in this case (because it's ERRORLEVEL ignores overwriting status). You can do everything on your side:
You can check existance of file (IF EXISTS !filename!.txt),
If file exists, you can ask user what to do (SET /P userInput=Overwrite? (Yes/No/All)),
After it you can analyzed %userInput% to decide what to do (delete existent file and create empty one with the same name + open editor or ask file name again).
If %overwrite%==Y : if %overwrite% is empty, this is executed as If ==Y - obviously a syntax error.
With the singlequoutes you mentioned: If '%overwrite%'==Y is executed as If ''==Y - this is proper syntax, so your code doesn' fail (but is not running as intended)
The reason why %overwrite% is empty: you are using it inside a block (between if ( and the corresponding ), so for parsing reason it' easy (search for delayed expansion).
You can easily avoid that:
#echo off
SET /P filename=What File name?
echo %filename%
:loop
if not exist %filename%.txt goto finish
echo File Exists
SET /P overwrite=Overwrite File?
echo overwrite is %overwrite%
If "%overwrite%"=="Y" ( echo "Yes, Y" ) else ( goto loop )
this line is never reached
:finish
echo finish
When using a single line you can't loop back to the start - but this will only create the file AND start notepad with the file, if the file does not exist.
If the file exists it will just exit and NOT start notepad so you know that you have to try again.
cmd /c #ECHO OFF & SET /P filename=What File name: & cmd /v /c "if not exist !filename!.txt copy NUL !filename!.txt & start "" notepad !filename!.txt" & Exit

How to get attributes of a file using batch file

I am trying to make a batch file to delete malicious files from pendrive. I know that these malicious files uses hidden,read only and system attributes mainly to hide itself from users. Currently i am deleting these files using cmd by removing malicious files attributes then deleting it. Now I am thinking to make a small batch file which can be used to remove these files just by entering the drive letter.
I have found this code in a website to find attributes of a file. But after entering the name of the file the batch file just exits without showing any results.
#echo off
setlocal enabledelayedexpansion
color 0a
title Find Attributes in Files
:start
set /p atname=Name of the file:
if not exist %atname% (
cls
echo No file of that name exists!
echo.
echo Press any key to go back
pause>nul
goto start
)
for /f %%i in (%atname%) do set attribs=%%~ai
set attrib1=!attribs:~0,1!
set attrib2=!attribs:~1,1!
set attrib3=!attribs:~2,1!
set attrib4=!attribs:~3,1!
set attrib5=!attribs:~4,1!
set attrib6=!attribs:~5,1!
set attrib7=!attribs:~6,1!
set attrib8=!attribs:~7,1!
set attrib9=!attribs:~8,1!
cls
if %attrib1% equ d echo Directory
if %attrib2% equ r echo Read Only
if %attrib3% equ a echo Archived
if %attrib4% equ h echo Hidden
if %attrib5% equ s echo System File
if %attrib6% equ c echo Compressed File
if %attrib7% equ o echo Offline File
if %attrib8% equ t echo Temporary File
if %attrib9% equ l echo Reparse point
echo.
echo.
echo Press any key to go back
pause>nul
goto start
can you tell me why this batch file is exiting without showing any results. Or can you give any better batch script for getting attributes of a file.
EDIT
I was able to work the above code only for a single file. As my purpose of my batch file is to remove malicious files by entering the drive letter. How can i use it to find what kind of attributes files are using in a particular drive.
For example:
In cmd we can use this command to find the file attributes of a given drive
attrib *.*
Advance thanks for your help
I tried the bat file (without inspecting the details) and it seems to work fine for me. What I noticed is that it closes instantly if you don't enclose file path with quotation marks - e.g. "file". Example:
Name of the file: path\file.txt // this will close immediately
Name of the file: "path\file.txt" // now it will stay open and display the result
This hopefully solves your problem.
As far as your question in EDIT is concerned, a simple option is to iterate a list of files and execute the batch on each one.
batch1.bat: (%1 refers to the first command-line parameter)
#echo off
setlocal enabledelayedexpansion
echo %1
set atname=%1
for %%i in ("%atname%") do set attribs=%%~ai
set attrib1=!attribs:~0,1!
set attrib2=!attribs:~1,1!
set attrib3=!attribs:~2,1!
set attrib4=!attribs:~3,1!
set attrib5=!attribs:~4,1!
set attrib6=!attribs:~5,1!
set attrib7=!attribs:~6,1!
set attrib8=!attribs:~7,1!
set attrib9=!attribs:~8,1!
cls
if %attrib1% equ d echo Directory
if %attrib2% equ r echo Read Only
if %attrib3% equ a echo Archived
if %attrib4% equ h echo Hidden
if %attrib5% equ s echo System File
if %attrib6% equ c echo Compressed File
if %attrib7% equ o echo Offline File
if %attrib8% equ t echo Temporary File
if %attrib9% equ l echo Reparse point
echo.
echo.
Next, generate a list of all files within a given path (say 'folder' including all subfolders):
dir /s /b folder > ListOfFiles.txt
main.bat (read ListOfFiles.txt line-by-line and pass each line to batch1.bat as a command line parameter):
#echo off
for /f "tokens=*" %%l in (ListOfFiles.txt) do (batch1.bat %%l)
Then, from cmd:
main.bat >> output.txt
The last step generates an output file with complete results. Granted, this can be done in a more polished (and probably shorter) way, but that's one obvious direction you could take.
You're using a for /f loop here, which isn't necessary (and may yield undesired results if the filename contains spaces). Change this:
for /f %%i in (%atname%) do set attribs=%%~ai
into this:
for %%i in ("%atname%") do set attribs=%%~ai
This is dangerous code - but it'll delete read only, hidden and system files.
It should fail to run on c: drive but I haven't tested it. Note that some Windows installs are on drives other than c:
#echo off
echo "%cd%"|find /i "c:\" >nul || (
del *.??? /ar /s /f
del *.??? /ah /s
del *.??? /as /s
)

Print request upon new file in folder

I've got the following problem:
I need to make something that checks to see whether a file has been added to a specific folder, ifso this file needs to be printed. I heard Windows maybe has something similar built in?
*Program constantly checks whether a file has been added*
File has been added
File gets printed immediately
I have found solutions, but you need to pay for them.
UPDATE
"Code supplied by Vik"
:start
set SECONDS=60
SET FILENAME=*.jpg
IF EXIST %FILENAME% MSPAINT /p %FILENAME%
choice /C a /T %SECONDS% /D a
DEL /Q %FILENAME%
goto :start
"Edits: COPY *.JPG file to a different folder (E.G. ImageHistory)"
"Edits: DELETE local *.JPG file leaving the monitor folder empty"
Any tips or help are welcome!
This batch file will check if the file printme.jpg exists every 60 seconds. If it exists, it will use the built-in MSPAINT program to print it. Feel free to configure SECONDS and FILENAME to suit your environment.
:start
set SECONDS=60
SET FILENAME=printme.jpg
IF EXIST %FILENAME% MSPAINT /p %FILENAME%
choice /C a /T %SECONDS% /D a
goto :start
Additional mods you may want to make:
If you are using an older version of Windows like XP, you may not have the CHOICE command. In that case, use ping to simulate sleeping: PING 1.1.1.1 -n 1 -w 60000 >NUL
You can add a line to delete the file after it's printed: DEL /Q %FILENAME%
EDIT (Below): Added multi-file, move and delete capability
set SECONDS=20
set FILEFOLDER=C:\dropfolder
set TEMPFOLDER=%FILEFOLDER%\TEMPFOLDER
set FILEWILDCARD=*.jpg
if not exist "%FILEFOLDER%" ECHO %FILEFOLDER% NOT FOUND ... CTRL-C TO EXIT && PAUSE
if not exist "%TEMPFOLDER%" ECHO %TEMPFOLDER% NOT FOUND ... CTRL-C TO EXIT && PAUSE
:start
cd "%FILEFOLDER%"
dir /b "%FILEWILDCARD%" > filelist.txt
for %%A in (filelist.txt) do if not %%~zA==0 goto printfiles
choice /C a /T %SECONDS% /D a
goto :start
:printfiles
echo FILE(s) FOUND!
del /q "%TEMPFOLDER%\%FILEWILDCARD%"
move "%FILEWILDCARD%" "%TEMPFOLDER%"
cd "%TEMPFOLDER%"
for %%A in ("%FILEWILDCARD%") do MSPAINT /p "%%A"
goto :start
Run a VB.Net in Background and use a FileSystemWatcher to get events for each change in that folder. Upon receiving an event, check the file / action and print the file using whatever App that can print them. A Batch file will likely not work here.

Resources