How to set variable with the result of findstr - command-line

I am trying to write a batch file which searches for pdf files and finds how many pages they have and loop all pages.
I wrote the following. I can find the files, I can even find the pagecounts with a tool named pdftk. The results is as below.
C:\Users\test\Documents\fishes\Fish_1.pdf
NumberOfPages: 5
How can I set a variable which has the value of 5?
#ECHO off
for /R %%i IN (*.pdf) DO (
ECHO %%i
"C:\Program Files (x86)\PDF Labs\PDFtk Server\bin\pdftk.exe" %%i dump_data | findstr NumberOfPages
set pagecount = findstr NumberOfPages ???
FOR /L %%j IN (1,1,%pagecount%) DO (
ECHO "page " + %%j
)
)

You were already 90% there. Use the FOR /F command to process the results of a command. Type HELP FOR from the command prompt for more info.
for /f "tokens=2" %%A in (
'"C:\Program Files (x86)\PDF Labs\PDFtk Server\bin\pdftk.exe" %%i dump_data ^| findstr NumberOfPages'
) do set numberOfPages=%%A

Related

BAT/POWERSHELL copy (only)yesterday files

I'm trying to write some script to copy all files which have been created yesterday (only!)
/D parameter for xcopy means copy files changed on or after the specified date so its not what i'm searching for. Any ideas? ;/
I suggest you to use powershell. You can use Get-ChildItem and Where-Object to get the list of files created the day before
$yesterdayFiles = Get-ChildItem | Where-Object {$_.CreationTime.Date -eq ((Get-Date).AddDays(-1).Date)}
Then you can copy the files stored in $yesterdayFiles variable using Copy-Item cmdlets
I've tried with robocopy /minage:1 /maxage:1 but seems does not work.But work when I set the current date.Here's the script (you'll need to set your source and destination):
#echo off
set "source=C:\folder1"
set "dest=C:\folder2"
pushd "%temp%"
::get cirrent date
makecab /D RptFileName=~.rpt /D InfFileName=nul /f nul >nul
for /f "tokens=3-7" %%a in ('find /i "makecab"^<~.rpt') do (
set "year=%%e"
set "mon=%%b"
set "day=%%c"
)
del ~.*
popd
:: convert month to numeric string
for %%a in (
"Jan-01" "Feb-02" "Mar-03" "Apr-04" "May-05" "Jun-06" "Jul-07" "Aug-08" "Sep-09" "Oct-10" "Nov-11" "Dec-12"
) do (
for /f "tokens=1,2 delims=-" %%x in ("%%~a") do (
if "%mon%" equ "%%x" (
set "mon=%%y"
goto :skip
)
)
)
:skip
set "c_date=%year%%mon%%day%"
::echo %c_date%
:: is switch is for force overwriting
robocopy "%source%" "%dest%" * /maxage:1 /minage:%c_date% /is
robocopy is built-in every windows since Vista.If your are running under XP or Vista you'll need to download it from microsoft site.
This Batch file selects all files that were created on the same date before today. If you are sure that there are files created yesterday, then it solve your problem.
#echo off
setlocal EnableDelayedExpansion
set "yesterday="
for /F "skip=5 tokens=1,4*" %%a in ('dir /TC /O-D /A-D') do (
if "%%a" neq "%date%" (
if not defined yesterday set "yesterday=%%a"
if "%%a" equ "!yesterday!" (
echo Created yesterday: %%a "%%c"
) else (
goto break
)
)
)
:break

Windows script to delete everything but image file extensions

I want to create a script on Windows 7 to delete everything in a directory that is not a picture.
So
for all files in directory X
if file y does not have extension in (.png, .gif, .jpeg)
delete y
end
that's it
how can I find or create such a script
mind you, some pictures are important, so this script has to work correctly :) I don't think I should be experimenting here, and even if I tested my own script on a small directory with experimental files, I am not confident that I should try it.
I have this code as suggested:
::extensions are delimited with space // filename is del_stuff.bat
set "extensions_list=.png .gif .jpeg .bmp .jpg "
pushd "C:\Users\denman\Desktop\xxx\"
for /f "delims=" %%f in ('dir /b ^|findstr /i /e /v "%extensions_list%" ') do (
echo del /q /f "%%~f"
)
popd
But I get this error:
Using Powershell, you can get the list of files you need with something like this:
Get-ChildItem | where {!$_.PsIsContainer -and !(#(".png",".gif",".jpeg") -contains $_.Extension) }
I left the Delete command to you, make sure the list returns correct results before you do it.
#echo off
::extensions are delimited with space
set "extensions_list=.png .gif .jpeg "
pushd "C:\Directory_with_pictures" && (
for /f "delims=" %%f in ('dir /b /a-d ^|findstr /i /e /v "%extensions_list%" ') do (
echo del /q /f "%%~f"
)
popd
)
The 'echo' is to verify the result .remove the echo to activate deletion.And change "C:\Directory_with_pictures" with the actual path.
EDIT testing the script:
#echo off
md test_dir>nul 2>&1
echo #>test_dir\t1.png
echo #>test_dir\t1.txt
echo #>test_dir\t1.tst
echo #>test_dir\t1.jpg
echo #>test_dir\t1.gif
echo #>test_dir\t2.png
echo #>test_dir\t2.txt
echo #>test_dir\t2.tst
echo #>test_dir\t2.jpg
echo #>test_dir\t2.gif
echo -- before deleting--
dir /b .\test_dir\*
echo(
echo(
::extensions are delimited with space
set "extensions_list=.png .gif .jpeg .jpg"
pushd "test_dir"
for /f "delims=" %%f in ('dir /b ^|findstr /i /e /v "%extensions_list%" ') do (
del /q /f "%%~f"
)
popd
echo -- after deleting --
dir /b .\test_dir\*
Output:
-- before deleting--
t1.gif
t1.jpg
t1.png
t1.tst
t1.txt
t2.gif
t2.jpg
t2.png
t2.tst
t2.txt
-- after deleting --
t1.gif
t1.jpg
t1.png
t2.gif
t2.jpg
t2.png

Batch File to display file name and then certain lines in the files

I have a folder of .log files where the content of each file has multiple lines of the following format:
yyyy/mm/dd, hh:mm:ss, ComputerName, IPAddress, stuff, stuff
I would like to create a batch file to parse through the .log files and create the following output for any line in a file where ComputerName starts with "XPLT":
filename,yyyy/mm/dd,ComputerName,IPAddress
And preferably, I'd like to only look at files with a modified date within the last 30 days.
So far, I've only gotten the following code which doesn't even work and doesn't even include the file modified date and parsing by ComputerName. Looking for help because I've just not done this very much, and I can't find a good example online.
Echo EID,Date,PCName,IPAdd>CitrixLogs.csv
setlocal enabledelayedexpansion
for /f "tokens=1,3,4" %%i in ('dir /b "C:\LogFiles\*.log"') do (
echo %%i,%%j,%%k,%%l>>CitrixLogs.csv
)
I'd use a bit of FINDSTR magic:
set LOG_DIR=c:\logfiles
for /f "tokens=1-7 delims=:," %%L in ('%SystemRoot%\System32\findstr.exe /r /c:"^[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9],[0-9][0-9]:[0-9][0-9]:[0-9][0-9],xplt.*," %LOG_DIR%\*.log') do #echo %%L,%%M,%%N:%%O:%%P,%%Q,%%R,
`
REM
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "tokens=2-8delims=:, " %%a IN ('findstr /l /i /c:", XPLT" "%sourcedir%\*.log"') DO (
ECHO %%~nxa,%%b,%%c:%%d:%%e,%%f,%%g
)
GOTO :eof
redirect to your .csv as you will...
#echo off
setlocal enableextensions disabledelayedexpansion
:: configuration
set "logFolder=%cd%"
set "logFiles=*.log"
set "maxFileAge=30"
set "computerName=XPLT"
set "outputFile=CitrixLogs.csv"
:: adjust commands to execute according to configuration
set "ageFilter=robocopy "%logFolder%" "%logFolder%" "%logFiles%" /l /is /njh /njs /nc /ns /ndl /maxage:%maxFileAge%"
set "contentFilter=findstr /f:/ /i /r /c:"^^[^^,]*, [^^,]*, %computerName%" "
:: Generate output file
( echo(EID,Date,PCName,IPAdd
for /f "usebackq tokens=2,* delims=:" %%a in (
`cmd /q /c "for /f tokens^=* %%a in ('%ageFilter%') do echo(%%a" ^| %contentFilter% `
) do for /f "tokens=1,3,4 delims=," %%c in ("%%b") do echo(%%~nxa,%%c,%%d,%%e
) > "%outputFile%"
endlocal
This will use robocopy (or you can change it with forfiles) to search for files with a max age of 30 days in the indicated folder. Files will not be copied (/l) but the list will be echoed (the rest of the switch configure the output). This list of files is piped into findstr (/f:/) indicating where to search for the lines that match the indicated condition. This will generate an output with each line in the input file matching the condition, prefixed with the name (full name) of the file. This line is then splitted to output only the required fields.

Problems finding the value of registry keys

I'm attempting to make a batch script to uninstall various programs with little involvement from the user (Only saying I want to uninstall Group A (Say, Google Chrome and Microsoft Office)), Partially for work and partially for fun and practice. This itself isn't impossible, I can already do this by calling msiexec and pointing it to the uninstall location in the registry (msiexec /x {xxxxx-xxxxx-xxxxxx-xxxx}).
The only problem with this is that this means that whenever the program changes registry keys, as will often happen with updates, I have to find the path again. So, I'm trying to run a piece of code that will search through the HKLM\SOFTWARE\Mincrosoft\Windows\CurrentVersion\Uninstall registry location, and whenever the DisplayName returns a certain value, not necessarily exact (Say "Chrome"), it stores the registry location?(The part that would be put in {xxxxxxx-xxxxxxx-xxxxxxx-xxxxxx}).
This way, the program simply finds the programs and stores their locations so that they can be uninstalled with it as a variable. I have tried, but as far as I know using reg query requires the full location. using reg query HKLM /f returns no results. I've tried a whole range of different workarounds, but nothing seems to work.
Here is a basic version of my code (I am neglecting to post the full version because much of it is repeated. It's mostly just case where's and if then statements)
#echo off
:start
echo Hello
echo.
1: Uninstall Chrome
set /p choice="Enter Choice: "
if "%choice%"=="1" goto uninstall_chrome
:uninstall_chrome
reg query HKLM /f Chrome /t REG_SZ
::msiexec /x{uninstall location for the program}
Thanks.
::UPDATE::
I figured it out. By using some of Rob van der Woude's code, I am now able to do it. The code to do so is:
CALL :Uninstall "Program Name"
:Uninstall
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=* %%A IN ('REG QUERY HKLM\SOFWARE\Microsoft\Windows\CurrentVersion\Uninstall /F "%~1" /D /S 2^>NUL ^| FINDSTR /R /B /C:"HKEY_"') DO (
REG QUERY "%%~A" /F DisplayName /V /E | FINDSTR /R /I /C:" DisplayName .* .*%~1" >NUL 2>&1
FOR /F "tokens=2*" %%B IN ('REG QUERY "%%~A" /F DisplayName /V /E 2^>NUL ^| FIND /I " DisplayName "') DO ECHO Program Name = %%C
FOR /F "tokens=7 delims=\" %%B IN ("%%~A") DO ECHO Unique Identifier = %%B
FOR /F "tokens=2*" %%B IN ('REG QUERY "%%~A" /F UninstallString /V /E ^| FIND /I " UninstallString "') DO %%C /qb
)
ENDLOCAL
This will output the programs name and unique identifier, then uninstall the program, without user input ("Do you want to uninstall x?")
I figured it out. By using some of Rob van der Woude's code, I am now able to do it. The code to do so is:
CALL :Uninstall "Program Name"
:Uninstall
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=* %%A IN ('REG QUERY HKLM\SOFWARE\Microsoft\Windows\CurrentVersion\Uninstall /F "%~1" /D /S 2^>NUL ^| FINDSTR /R /B /C:"HKEY_"') DO (
REG QUERY "%%~A" /F DisplayName /V /E | FINDSTR /R /I /C:" DisplayName .* .*%~1" >NUL 2>&1
FOR /F "tokens=2*" %%B IN ('REG QUERY "%%~A" /F DisplayName /V /E 2^>NUL ^| FIND /I " DisplayName "') DO ECHO Program Name = %%C
FOR /F "tokens=7 delims=\" %%B IN ("%%~A") DO ECHO Unique Identifier = %%B
FOR /F "tokens=2*" %%B IN ('REG QUERY "%%~A" /F UninstallString /V /E ^| FIND /I " UninstallString "') DO %%C /qb
)
ENDLOCAL
This will output the programs name and unique identifier, then uninstall the program, without user input ("Do you want to uninstall x?")

How do I execute code on most directories except those listed in a file with a batch file?

So I am trying to execute code on most directories under another except for those that I list in a text file. So for example, if I wanted to run the code on all directories directly in C:\ but not say C:\avoidme\ I would add C:\avoidme as a line in exclusions.txt. But the code I have below does not seem to be working. Any ideas on how this could be done?
for /f %%d in ('dir /b C:\') do (
find /c "C:\%%d" exclusions.txt
if %errorlevel% equ 1 (
Do code here
)
#echo off
for /D %%d in (*) do (
%WINDIR%\system32\find "%%d" exclude.list >nul
if errorlevel 1 (
echo good %%d
) else (
echo bad %%d
)
)
The reason your code does not work is because the entire body of the FOR DO() clause is parsed at once prior to actually executing the FOR statement. But the value of %ERRORLEVEL% is expanded at parse time, so you never get to see the updated value at execution time.
You have additional issues
you should use the DIR /AD option to restrict the list to directories only
you aren't interested in seeing the output of your FIND command, so you should probably redirect the output to nul
gavendkoa has one solution that will work.
Another alternative is to use delayed expansion
setlocal enableDelayedExpansion
for /f %%d in ('dir /ad /b C:\') do (
find /c "C:\%%d" exclusions.txt >nul
if !errorlevel! equ 1 (
REM Do code here
)
)
This has a risk in that %%d will corrupt the value at expansion time if it contains !. This can be solved by toggling the delayed expansion within the loop.
Another alternative is to use the || operator, which means execute the following command if the previous command failed.
for /f %%d in ('dir /ad /b C:\') do (
find /c "C:\%%d" exclusions.txt >nul || (
REM Do code here
)
)
Perhaps the best option is to eliminate the need to worry about the errorlevel at all by piping the results of DIR directly to FINDSTR with the /V and /G: options to filter out values that appear in your exclude list.
The following is supposed to work
for /f %%d in ('dir /ad /b C:\ ^| findstr /l /v /g:"exclude.list"') do (
REM - Do code here
)
BUT - there is a nasty FINDSTR bug that can cause it to fail if you search for multiple literal strings of different lengths.
The fix is to force FINDSTR to use regular expressions instead, but then you need to escape any regular expression meta-characters that may appear in your exclusion list. For example, a directory named myName.ext would have to be escaped as myName\.ext.
for /f %%d in ('dir /ad /b C:\ ^| findstr /r /v /g:"exclude.list"') do (
REM - Do code here
)
Other characters that would need to be escaped within exclusion.list are \, ^, $, [, ]