I need help with copying a folder, but doesn't copy sub-folders with the names that are specified in a text file. The text file is located:
U:\Directory\Directory\Textfile.txt
I need to copy folders that are specified in the text file, but here's the catch, after
U:\Directory\Directory\ the folders have random names, which is why they are stored in the text file. Example of what the directory tree looks like:
U:\Directory\Directory\"12345"\Pickle <--- Pickle is the folder I want.
U:\Directory\Directory\"22345"\Pickle
^
|
This is a random name specified in the text file.
They all have the folder Pickle inside, which is what I'm after. Inside the text file are names of all the folders that are after: U:\Directory\Directory\. The text file looks like this:
1335232 <--- This is the name of the random folders.
1242334 <--- They all are located:
2342312 <--- U:\Directory\Directory\~HERE~
(etc...)
The folders should be copied from U:\Directory\Directory\"12345"\Pickle to U:\Output\
The names for all folders are numbers if this helps. Thank you Peter for trying to help me, I'm sorry if I was unclear. I hope this clears things up!
#ECHO OFF
SETLOCAL
SET relroot=u:\directory
SET subdir=randomsubfoldername
::
FOR /f %%i IN (
'dir /b /ad %relroot%\%subdir% ^|findstr /b /e /v /g:textfile.txt '
) DO ECHO %relroot%\%subdir%\%%i
The DIR command lists the directorynames (/ad) in basic form (.b) - that is, name-only. The findstr finds lines that do not (/v) begin (/b) and end (/e) with the lines in the file filename (/g:filename)
With the revised information, and noting that the original information clearly showed the penultimate directory name was the same and selection occurring on the leaf, and the single example now provided...
#ECHO OFF
SETLOCAL
ECHO Here is a test structure
ECHO -----------------------------
DIR /s /b /ad u:\directory
ECHO ------Here is the textfile---------
TYPE u:\directory\textfile.txt
ECHO ====Method 1==============
FOR /f %%i IN (u:\directory\textfile.txt) DO (
DIR /s /b /ad u:\directory | FINDSTR /r ".*\\%%i\\.*" | FINDSTR /v /r ".*\\%%i\\.*\\.*"
)
ECHO ====Method 2==============
FOR /f %%i IN (u:\directory\textfile.txt) DO (
FOR /f %%s IN (
'DIR /s /b /ad u:\directory ^| FINDSTR /r ".*\\%%i\\.*" ^| FINDSTR /v /r ".*\\%%i\\.*\\.*"'
) DO ECHO selected : %%s
)
ECHO ====Method 3 - to ignore ...\target\subdir that has any subdir ==============
FOR /f %%i IN (u:\directory\textfile.txt) DO (
FOR /f %%s IN (
'DIR /s /b /ad u:\directory ^| FINDSTR /r ".*\\%%i\\.*" ^| FINDSTR /v /r ".*\\%%i\\.*\\.*"'
) DO (
FOR /f %%c IN ( 'DIR /a:d %%s ^|FIND /c "<" ' ) DO IF %%c==2 ECHO SELECTED : %%s
)
)
Here's the run results:
Here is a test structure
-----------------------------
u:\directory\another
u:\directory\yetanother
u:\directory\572
u:\directory\another\yetanother
u:\directory\another\yetanother\572
u:\directory\another\yetanother\1572
u:\directory\another\yetanother\5722
u:\directory\another\yetanother\572\wantthis
u:\directory\another\yetanother\572\andthis
u:\directory\another\yetanother\572\maywantthisidontknow
u:\directory\another\yetanother\572\572
u:\directory\another\yetanother\572\maywantthisidontknow\ignore
u:\directory\another\yetanother\1572\ignorethis
u:\directory\another\yetanother\5722\ignorethis
u:\directory\yetanother\572
u:\directory\yetanother\572\wantthis
u:\directory\572\wantthis
------Here is the textfile---------
23
753309
572
====Method 1==============
u:\directory\another\yetanother\572\wantthis
u:\directory\another\yetanother\572\andthis
u:\directory\another\yetanother\572\maywantthisidontknow
u:\directory\another\yetanother\572\572
u:\directory\yetanother\572\wantthis
u:\directory\572\wantthis
====Method 2==============
selected : u:\directory\another\yetanother\572\wantthis
selected : u:\directory\another\yetanother\572\andthis
selected : u:\directory\another\yetanother\572\maywantthisidontknow
selected : u:\directory\another\yetanother\572\572
selected : u:\directory\yetanother\572\wantthis
selected : u:\directory\572\wantthis
====Method 3 - to ignore ...\target\subdir that has any subdir ==============
SELECTED : u:\directory\another\yetanother\572\wantthis
SELECTED : u:\directory\another\yetanother\572\andthis
SELECTED : u:\directory\another\yetanother\572\572
SELECTED : u:\directory\yetanother\572\wantthis
SELECTED : u:\directory\572\wantthis
The two FINDSTR regex structures are
FINDSTR /r ".*\\%%i\\.*"
Any number of any characters, \, the target string, \, any number of any characters
FINDSTR /v /r ".*\\%%i\\.*\\.*"
Any number of any characters, \, the target string, \, any number of any characters,\, any number of any characters
BUT - the /v on FINDSTR means except lines matching...
I can make little sense of copy the sub-folder from a parent folder with a random name.
If the requirement is to copy into the selected directory from that directory's parent directory, then after verifying that the target directories being displayed by ECHO SELECTED : %%s replace ECHO SELECTED : %%s with
(
pushd %%s
xcopy ..\* . >nul
popd
)
The >nul suppresses xcopy reports
If it means something else, more information is required.
Related
Typically, asking the user to supply a file name to a batch script is a messy affair, requiring no misspellings, quotes around paths with spaces, and so forth. Unfortunately, users aren't well-known for accuracy. In situations where input file location is not known until runtime, using a GUI for file selection input reduces the likelihood of user error.
Is there a way to invoke a File... Open style gui file chooser or folder chooser from a Windows batch script?
If the script user has PowerShell or .NET installed, it is possible. See the answer below.
I'm also interested to see what other solutions anyone else can offer.
File Browser
Update 2016.3.20:
Since PowerShell is a native component of pretty much all modern Windows installations nowadays, I'm declaring the C# fallback as no longer necessary. If you still need it for Vista or XP compatibility, I moved it to a new answer. Starting with this edit, I'm rewriting the script as a Batch + PowerShell hybrid and incorporating the ability to perform multi-select. It's profoundly easier to read and to tweak as needed.
<# : chooser.bat
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
:: https://stackoverflow.com/a/15885133/1683264
#echo off
setlocal
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
echo You chose %%~I
)
goto :EOF
: end Batch portion / begin PowerShell hybrid chimera #>
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }
This results in a file chooser dialog.
The result of a selection outputs You chose C:\Users\me\Desktop\tmp.txt to the console. If you want to force single file selection, just change the $f.Multiselect property to $false.
(PowerShell command mercilessly leeched from the Just Tinkering Blog.) See the OpenFileDialog Class documentation for other properties you can set, such as Title and InitialDirectory.
Folder Browser
Update 2015.08.10:
Since there is already a COM method for invoking a folder chooser, it's pretty easy to build a PowerShell one-liner that can open the folder chooser and output the path.
:: fchooser.bat
:: launches a folder chooser and outputs choice to the console
:: https://stackoverflow.com/a/15885133/1683264
#echo off
setlocal
set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please choose a folder.',0,0).self.path""
for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"
setlocal enabledelayedexpansion
echo You chose !folder!
endlocal
In the BrowseForFolder() method, the fourth argument specifies the root of the hierarchy. See ShellSpecialFolderConstants for a list of valid values.
This results in a folder chooser dialog.
The result of a selection outputs You chose C:\Users\me\Desktop to the console.
See the FolderBrowserDialog class documentation for other properties you can set, such as RootFolder. My original .NET System.Windows.Forms PowerShell and C# solutions can be found in revision 4 of this answer if needed, but this COM method is much easier to read and maintain.
This should work from XP upwards and does'nt require an hibrid file, it just runs mshta with a long command line:
#echo off
set dialog="about:<input type=file id=FILE><script>FILE.click();new ActiveXObject
set dialog=%dialog%('Scripting.FileSystemObject').GetStandardStream(1).WriteLine(FILE.value);
set dialog=%dialog%close();resizeTo(0,0);</script>"
for /f "tokens=* delims=" %%p in ('mshta.exe %dialog%') do set "file=%%p"
echo selected file is : "%file%"
pause
Windows Script Host
File Selection
Windows XP had a mysterious UserAccounts.CommonDialog WSH object which allowed VBScript and JScript to launch the file selection prompt. Apparently, that was deemed a security risk and removed in Vista.
Folder Selection
However, the WSH Shell.Application object BrowseForFolder method will still allow the creation of a folder selection dialog. Here's a hybrid batch + JScript example. Save it with a .bat extension.
#if (#a==#b) #end /*
:: fchooser2.bat
:: batch portion
#echo off
setlocal
for /f "delims=" %%I in ('cscript /nologo /e:jscript "%~f0"') do (
echo You chose %%I
)
goto :EOF
:: JScript portion */
var shl = new ActiveXObject("Shell.Application");
var folder = shl.BrowseForFolder(0, "Please choose a folder.", 0, 0x00);
WSH.Echo(folder ? folder.self.path : '');
In the BrowseForFolder() method, the fourth argument specifies the root of the hierarchy. See ShellSpecialFolderConstants for a list of valid values.
A file / folder selection may be done with pure Batch, as shown below. Of course, the feel and look is not as pleasant as a GUI, but it works very well and in my opinion it is easier to use than the GUI version. The selection method is based on CHOICE command, so it would require to download it in the Windows versions that don't include it and slightly modify its parameters. Of course, the code may be easily modified in order to use SET /P instead of CHOICE, but this change would eliminate the very simple and fast selection method that only requires one keypress to navigate and select.
#echo off
setlocal
rem Select a file or folder browsing a directory tree
rem Antonio Perez Ayala
rem Usage examples of SelectFileOrFolder subroutine:
call :SelectFileOrFolder file=
echo/
echo Selected file from *.* = "%file%"
pause
call :SelectFileOrFolder file=*.bat
echo/
echo Selected Batch file = "%file%"
pause
call :SelectFileOrFolder folder=/F
echo/
echo Selected folder = "%folder%"
pause
goto :EOF
:SelectFileOrFolder resultVar [ "list of wildcards" | /F ]
setlocal EnableDelayedExpansion
rem Process parameters
set "files=*.*"
if "%~2" neq "" (
if /I "%~2" equ "/F" (set "files=") else set "files=%~2"
)
rem Set the number of lines per page, max 34
set "pageSize=30"
set "char=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
rem Load current directory contents
set "name[1]=<DIR> .."
:ProcessThisDir
set "numNames=1"
for /D %%a in (*) do (
set /A numNames+=1
set "name[!numNames!]=<DIR> %%a"
)
for %%a in (%files%) do (
set /A numNames+=1
set "name[!numNames!]= %%a"
)
set /A numPages=(numNames-1)/pageSize+1
rem Show directory contents, one page at a time
set start=1
:ShowPage
set /A page=(start-1)/pageSize+1, end=start+pageSize-1
if %end% gtr %numNames% set end=%numNames%
cls
echo Page %page%/%numPages% of %CD%
echo/
if %start% equ 1 (set base=0) else set "base=1"
set /A lastOpt=pageSize+base, j=base
for /L %%i in (%start%,1,%end%) do (
for %%j in (!j!) do echo !char:~%%j,1! - !name[%%i]!
set /A j+=1
)
echo/
rem Assemble the get option message
if %start% equ 1 (set "mssg=: ") else (set "mssg= (0=Previous page")
if %end% lss %numNames% (
if "%mssg%" equ ": " (set "mssg= (") else set "mssg=%mssg%, "
set "mssg=!mssg!Z=Next page"
)
if "%mssg%" neq ": " set "mssg=%mssg%): "
:GetOption
choice /C "%char%" /N /M "Select desired item%mssg%"
if %errorlevel% equ 1 (
rem "0": Previous page or Parent directory
if %start% gtr 1 (
set /A start-=pageSize
goto ShowPage
) else (
cd ..
goto ProcessThisDir
)
)
if %errorlevel% equ 36 (
rem "Z": Next page, if any
if %end% lss %numNames% (
set /A start+=pageSize
goto ShowPage
) else (
goto GetOption
)
)
if %errorlevel% gtr %lastOpt% goto GetOption
set /A option=start+%errorlevel%-1-base
if %option% gtr %numNames% goto GetOption
if defined files (
if "!name[%option%]:~0,5!" neq "<DIR>" goto endSelect
) else (
choice /C OS /M "Open or Select '!name[%option%]:~7!' folder"
if errorlevel 2 goto endSelect
)
cd "!name[%option%]:~7!"
goto ProcessThisDir
:endSelect
rem Return selected file/folder
for %%a in ("!name[%option%]:~7!") do set "result=%%~Fa"
endlocal & set "%~1=%result%
exit /B
Other solution with direct run PowerShell command in Batch
rem preparation command
set pwshcmd=powershell -noprofile -command "&{[System.Reflection.Assembly]::LoadWithPartialName('System.windows.forms') | Out-Null;$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog; $OpenFileDialog.ShowDialog()|out-null; $OpenFileDialog.FileName}"
rem exec commands powershell and get result in FileName variable
for /f "delims=" %%I in ('%pwshcmd%') do set "FileName=%%I"
echo %FileName%
Batch + PowerShell + C# polyglot solution
This is the same solution as the Batch + PowerShell hybrid, but with the C# fallback stuff re-added for XP and Vista compatibility. Multiple file selection has been added at xNightmare67x's request.
<# : chooser_XP_Vista.bat
:: // launches a File... Open sort of file chooser and outputs choice(s) to the console
:: // https://stackoverflow.com/a/36156326/1683264
#echo off
setlocal enabledelayedexpansion
rem // Does powershell.exe exist within %PATH%?
for %%I in ("powershell.exe") do if "%%~$PATH:I" neq "" (
set chooser=powershell -noprofile "iex (${%~f0} | out-string)"
) else (
rem // If not, compose and link C# application to open file browser dialog
set "chooser=%temp%\chooser.exe"
>"%temp%\c.cs" (
echo using System;
echo using System.Windows.Forms;
echo class dummy {
echo public static void Main^(^) {
echo OpenFileDialog f = new OpenFileDialog^(^);
echo f.InitialDirectory = Environment.CurrentDirectory;
echo f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
echo f.ShowHelp = true;
echo f.Multiselect = true;
echo f.ShowDialog^(^);
echo foreach ^(String filename in f.FileNames^) {
echo Console.WriteLine^(filename^);
echo }
echo }
echo }
)
for /f "delims=" %%I in ('dir /b /s "%windir%\microsoft.net\*csc.exe"') do (
if not exist "!chooser!" "%%I" /nologo /out:"!chooser!" "%temp%\c.cs" 2>NUL
)
del "%temp%\c.cs"
if not exist "!chooser!" (
echo Error: Please install .NET 2.0 or newer, or install PowerShell.
goto :EOF
)
)
rem // Do something with the chosen file(s)
for /f "delims=" %%I in ('%chooser%') do (
echo You chose %%~I
)
rem // comment this out to keep chooser.exe in %temp% for faster subsequent runs
del "%temp%\chooser.exe" >NUL 2>NUL
goto :EOF
:: // end Batch portion / begin PowerShell hybrid chimera #>
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }
For a folder chooser for XP or Vista, use either the WSH solution or npocmaka's HTA solution.
Two more ways.
1.Using a hybrid .bat/hta (must be saved as a bat) script .It can use vbscript or javascript but the example is with javascrtipt.Does not create temp files.Selecting folder is not so easy and will require an external javascript libraries , but selecting file is easy
<!-- : starting html comment
:: FileSelector.bat
#echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
set "file=%%~fp"
)
echo/
if not "%file%" == "" (
echo selected file is : %file%
)
echo/
exit /b
-->
<Title>== FILE SELECTOR==</Title>
<body>
<script language='javascript'>
function pipeFile() {
var file=document.getElementById('file').value;
var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
close(fso.Write(file));
}
</script>
<input type='file' name='file' size='30'>
</input><hr><button onclick='pipeFile()'>Submit</button>
</body>
1.1 - without submit form proposed by rojo (see comments):
<!-- : starting html comment
:: FileSelector.bat
#echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
set "file=%%~fp"
)
echo/
if not "%file%" == "" (
echo selected file is : "%file%"
)
echo/
exit /b
-->
<Title>== FILE SELECTOR==</Title>
<body>
<script language='javascript'>
function pipeFile() {
var file=document.getElementById('file').value;
var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
close(fso.Write(file));
}
</script>
<input id='file' type='file' name='file' size='30' onchange='pipeFile()' >
</input>
<hr>
<button onclick='pipeFile()'>Submit</button>
<script>document.getElementById('file').click();</script>
</body>
2.As you already using powershell/net you can create selfcompiled jscript.net hybrid.It will not require temp cs file for compilation and will directly use the built-in jscrript.net compiler.There's no need of powershell too and the code is far more readable:
#if (#X)==(#Y) #end /* JScript comment
#echo off
:: FolderSelectorJS.bat
setlocal
for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
set "jsc=%%v"
)
if not exist "%~n0.exe" (
"%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)
for /f "tokens=* delims=" %%p in ('"%~n0.exe"') do (
set "folder=%%p"
)
if not "%folder%" == "" (
echo selected folder is %folder%
)
endlocal & exit /b %errorlevel%
*/
import System;
import System.Windows.Forms;
var f=new FolderBrowserDialog();
f.SelectedPath=System.Environment.CurrentDirectory;
f.Description="Please choose a folder.";
f.ShowNewFolderButton=true;
if( f.ShowDialog() == DialogResult.OK ){
Console.Write(f.SelectedPath);
}
I will leave an 'echo' even to verify that multiple choice works in this code
echo off
set cmd=Add-Type -AssemblyName System.Windows.Forms;$f=new-object Windows.Forms.OpenFileDialog;$f.InitialDirectory= [environment]::GetFolderPath('Desktop');$f.Filter='Text Files(*.txt)^|*.txt^|All Files(*.*)^|*.*';$f.Multiselect=$true;[void]$f.ShowDialog();if($f.Multiselect) {$f.FileNames}else{$f.FileName}
set pwshcmd=powershell -noprofile -command "&{%cmd%}"
for /f "tokens=* delims=" %%I in ('%pwshcmd%') do call :sum "%%I" ret
echo =========
echo --%ret%--
pause
exit /B
:sum [mud] [ret]
echo "%~1"
set FileName=%FileName% "%~1"
set ret=%FileName%
exit /B
I has been wrote my own portable solution:
https://github.com/andry81/contools/tree/HEAD/Utilities/src/_gui/wxFileDialog/
You can download executable from here:
https://github.com/andry81/contools/tree/HEAD/Utilities/bin/contools/wxFileDialog.exe
The utility has dependency on wxWidgets 3.1.x, so you can actually build it for other operating systems.
I searched for any way to query a process hash.
assuming I was able to retrive the ExecutablePath using Win32_Process,
I would like to query the file's hash.
I'm trying to avoid using powershell but to achieve the same functiallity of "Get-FileHash".
Thank You!
edit:
I have tried to use win32_filespecification that supplied md5checksum, the problem was i could not find the relevant files (such as notepad.exe).
Here is a batch file to test :
#echo off
Title Get Notepad Hash
Set "App_Path=%windir%\system32\notepad.exe"
echo "%App_Path%"
#for /f "tokens=2 skip=3 delims= " %%a in ('Powershell Get-FileHash "%App_Path%"') do echo SHA256=%%a
Pause & Exit
EDIT :
Get Process File Hash using WMIC and Certutil in command line
You can give a try for the second batch file :
#echo off
cls & color 9E & Mode 95,5
Title Get Process File Hash using WMIC and Certutil in command line
Set "TmpFile=%~dpn0_Tmp.txt"
Set "LogPathExe=%~dpn0_PathExe.txt"
Set "Hashes=%~dpn0_Hashes.txt"
echo(
echo( ===========================================================
echo( Please wait a while ... Working is in progress....
echo( ===========================================================
Setlocal EnableDelayedExpansion
> "!TmpFile!" (
#for /f "delims=" %%a in ('wmic process get ExecutablePath /format:list') do (
#For /F "tokens=2 delims==" %%b in ("%%a") do (
set "Exe=%%b"
If not defined Exe Set !Exe!
echo "!Exe!"
)
)
)
Call :RemoveDuplicateEntry "!TmpFile!" "!LogPathExe!"
Del "!TmpFile!"
> "!Hashes!" (
#for /f "delims=" %%a in ('Type "!LogPathExe!"') do (
#for /f "skip=1 delims=" %%H in ('CertUtil -hashfile "%%~a" SHA256 ^| findstr /i /v "CertUtil"') do set "H=%%H"
echo %%a=!H: =!
)
)
)
If Exist "!Hashes!" Start "" "!Hashes!" & Exit
::----------------------------------------------------
:RemoveDuplicateEntry <InputFile> <OutPutFile>
Powershell ^
$Contents=Get-Content '%1'; ^
$LowerContents=$Contents.ToLower(^); ^
$LowerContents ^| select -unique ^| Out-File '%2'
Exit /b
::----------------------------------------------------
The third batch script to check hashes on virustotal :
#echo off
cls & color 9E & Mode 95,5
Title Get Process File Hash using WMIC and Certutil in command line
Set "TmpFile=%~dpn0_Tmp.txt"
Set "LogPathExe=%~dpn0_PathExe.txt"
Set "Hashes=%~dpn0_Hashes.txt"
Set "Hash2Check_VirusTotal=%~dpn0_Hash2Check_VirusTotal.txt"
If Exist "%Hash2Check_VirusTotal%" Del "%Hash2Check_VirusTotal%"
echo(
echo( ===========================================================
echo( Please wait a while ... Working is in progress....
echo( ===========================================================
Setlocal EnableDelayedExpansion
> "!TmpFile!" (
#for /f "delims=" %%a in ('wmic process get ExecutablePath /format:list') do (
#For /F "tokens=2 delims==" %%b in ("%%a") do (
set "ExecutablePath=%%b"
If not defined ExecutablePath Set !ExecutablePath!
echo "!ExecutablePath!"
)
)
)
Call :RemoveDuplicateEntry "!TmpFile!" "!LogPathExe!"
Del "!TmpFile!"
> "!Hashes!" (
#for /f "delims=" %%a in ('Type "!LogPathExe!"') do (
#for /f "skip=1 delims=" %%H in ('CertUtil -hashfile "%%~a" SHA256 ^| findstr /i /v "CertUtil"') do set "H=%%H"
echo %%a=!H: =!
>> "!Hash2Check_VirusTotal!" echo https://www.virustotal.com/old-browsers/file/!H: =!
)
)
)
cls
Echo(
Echo( Did you want to check the executable on Virustotal ? Just Type "Y" Or any key to Quit !
Set /p "Check="
If /I [!check!] EQU [Y] (
#for /f "delims=" %%a in ('Type "!Hash2Check_VirusTotal!"') do ( Start "Chek SHA256 on VIRUSTOTAL" %%a & Timeout /T 10 /nobreak>nul)
) else (
If Exist "!Hashes!" Start "" "!Hashes!" & Exit
)
Exit
::----------------------------------------------------
:RemoveDuplicateEntry <InputFile> <OutPutFile>
Powershell ^
$Contents=Get-Content '%1'; ^
$LowerContents=$Contents.ToLower(^); ^
$LowerContents ^| select -unique ^| Out-File '%2'
Exit /b
::----------------------------------------------------
The aim is to search multiple files with the extension of .rej, So i have a file that can easily display that information.
So I went in a completely different direction and uses CSV's because the info I needed is only 3 strings on every line.
#echo off
setlocal enabledelayedexpansion
For %%I in (*.rej) do (
(for /f "delims==" %%A in (%%I) do set string=%%A & echo !string::=,!) >> %%~nI_Tempout.tmp
(for /f "delims==" %%A in (%%~nI_Tempout.tmp) do set string=%%A & echo !string:[=,!) >> %%~nI_Tempout1.tmp
(for /f "delims=" %%A in (%%~nI_Tempout1.tmp) do Call :Split %%A ) > %%~nI_New.csv)
goto :Eof
:Split
#echo(%1,%9,%11
del *.tmp
File.rej
12.13.14 [-] [20190304][ VBTS 0 ] REJECTED:IM:2q1231231123124:II:123123123123:TM:1278391237912379128379:CAUSES:
12.13.16 [-] [20190304][ VBTS 0 ] REJECTED:IM:2q1231231123124:II:123123123123:TM:1278391237912379128379:CAUSES:
12.13.20 [-] [20190304][ VBTS 0 ] REJECTED:IM:2q1231231123124:II:123123123123:TM:1278391237912379128379:CAUSES:
However at the end the %11 prints %1 the 1,
I can only assume it detects %1 the echos the next 1
output
12.13.14,2q1231231123124,12.13.141
12.13.16,2q1231231123124,12.13.161
12.13.20,2q1231231123124,12.13.201
FINAL CODE
#echo off
setlocal enabledelayedexpansion
For %%I in (*.rej) do (
(for /f "delims==" %%A in (%%I) do set string=%%A & echo !string::=,!) >> %%~nI_Tempout.tmp
(for /f "delims==" %%A in (%%~nI_Tempout.tmp) do set string=%%A & echo !string:[=,!) >> %%~nI_Tempout1.tmp
(for /f "tokens=1,8,10 delims=," %%A in (%%~nI_Tempout1.tmp) do Call :Split %%A %%B %%C ) > %%~nI_New.csv)
goto :Eof
:Split
#echo(%1,%2,%3
del *.tmp
You parse your data to a temp file, parse that a second time to a second temp file and parse that a third time. That is inefficient. You can do it all with a single for /f loop, when you choose your tokens and delims wisely:
(for /f "tokens=1,7,11 delims=[-]: " %%A in ('type *.rej 2^>nul') do echo %%A,%%B,%%C)>file_New.csv
I'm not quite sure, if the tokens are right, because you didn't show your expected output, but you can easily adapt them to your needs.
Using Windows command line (not powershell), I want to hash all files within the directory and then remove files that match a particular hash set contained within a text file.
I've considered using md5deep, but I'm unsure if the output of matched files can then be redirected into a delete command.
Any help gratefully received, thank you!
To add some detail; the files are in a directory called 'images'
md5deep.exe -r -b -x irrelevant_hashes.txt c:\images
This gives me a list of the files that I need to keep. Is it possible to redirect the output from MD5deep to move the 'good' files to another directory?
For a single md5 key in cmd line it is as easy as:
(Here using the 64bit variant).
set "KillMD5=00112233445566778899aabbccddeeff"
for /f "tokens=1*" %A in ('md5deep64.exe *.* 2^>mul') do #if %A==%KillMD5% #Echo del "%B"
For testing the del command is only echoed.
In a batch file double the % percent signs %%A/%%B
This use pure batch file, take use of CertUtil from windows, so no 3rd software need.
You only need provide the value for 2 variables:
set _nOp=irrelevant_hashes.txt :: file text with md5 data for files to delete
set "_path_gen=c:\images" :: path to files that will be delete.
In additional, put the txt file with md5 (in this code case irrelevant_hashes.txt) in the same folder of the files that you want to delete.
For generate a new md5 from files, and usin certUtil on command line:
type nul >"%temp%\MD5_to_del.txt" & cd /d "c:\images" & for /f "tokens=* delims= " %i in ('^<nul dir /o-d /on /b "c:\images\*.*"') do for /f "tokens=* delims= " %M in ('certutil -hashfile "%i" md5 ^| find /v ":"') do echo/%M>>"%temp%\MD5_to_del.txt"
For generate a new md5 from files, and using certUtil on a file.bat:
type nul >"%temp%\MD5_to_del.txt" & cd /d "c:\images" & for /f "tokens=* delims= " %%i in ('^<nul dir /o-d /on /b "c:\images\*.*"') do for /f "tokens=* delims= " %%M in ('certutil -hashfile "%%i" md5 ^| find /v ":"') do echo/%%M>>"%temp%\MD5_to_del.txt"
#echo off & setlocal EnableExtensions EnableDelayedExpansion
cls && mode con cols=120 lines=7 & cd /d "%~dp0"
set "'=^|"
set "_spc= "
set /a _cnt_left= 1 - 1
set /a _cnt_treated= 1 - 1
set /a _cnt_deleted= 1 - 1
set /a _cnt_keeped_= 1 - 1
set _type_hash=md5
set _show=0000000
set "_path_gen=c:\images"
cd /d !_path_gen! || set "_erro=!_path_gen! not exist?"&& goto :_error_:
set _n_deleted=%temp%\md5_not_deleted_.txt
set _y_deleted=%temp%\md5_was_deleted_.txt
(
if exist "!_n_deleted!" del /q /f "!_n_deleted!"
if exist "!_y_deleted!" del /q /f "!_y_deleted!"
) 2>nul >nul
if exist ".\irrelevant_hashes.txt" (
set _nOp=irrelevant_hashes.txt
) else (
set "_error= File irrelevant_hashes.txt not found"
goto :_error_:
)
set _hash_data=%temp%\hash_db\date_db.txt
if exist "!_hash_data!" (
del /q /f "!_hash_data!"
copy /y "!_nOp!" "!_hash_data!" 2>nul >nul || set _error=Copy !_nOp! to !_hash_data!
) else (
dir /ad "%temp%\hash_db\" 2>nul >nul | findstr /c:".." || mkdir "%temp%\hash_db"
copy /v "!_nOp!" "!_hash_data!" 2>nul >nul || set _error=Copy !_nOp! to !_hash_data!
)
for /f "delims= " %%T in ('forFiles /p "." /m "%~nx0" /c "cmd /c echo(0x09"') do set "_tab=%%T"
call set "_tab=%_tab:~0,1%"
for /f "tokens=* delims=^ " %%i in ('^<nul dir /o-d /on /b "!_path_gen!\*.*" 2^> nul ^| find "" /v /c ') do set _cnt_file=%%i
for /f "tokens=* delims= " %%f in ('dir /o-d /on /b "*.*" ^| findstr /i /v "!_nOp! %0" ') do (
for %%S in (cnt_treated cnt_deleted cnt_keeped_ cnt_left) do set _show_%%S=!_show!!_%%S!
set _file=%%~nxf
set "_file_hash=%%~dpnxf"
set /a _cnt_treated=!_cnt_treated! + 1
call :_get_hash_:
title Total files: !_show_cnt_treated:~-5! ^| Delete: !_show_cnt_deleted:~-5! ^| Keeped: !_show_cnt_keeped_:~-5! ^| File left: !_show_cnt_left:~-5!
)
(
if exist "!_n_deleted!" copy /y "!_n_deleted!" .
if exist "!_y_deleted!" del /y "!_y_deleted!" .
) 2>nul >nul
echo/ Total file treated: !_show_cnt_treated:~-5!
echo/ Total file deleted: !_show_cnt_deleted:~-5!
echo/ Total file keeped: !_show_cnt_keeped_:~-5!
goto :_end_of_file_:
:_get_hash_:
for /f "tokens=* delims= " %%i in ('certutil -hashfile "!_file_hash!" !_type_hash! ^| find /v ":"') do (
set "_hash=%%i"
call set "_hash=!_hash: =!"
call set _hash=!_hash!
for /f "tokens=* delims=" %%I in ('echo/%_tab%') do call set _file_hash=!_hash:%%I=!
call set _hash=!_hash!
for /f "tokens=* delims= " %%e in ('type "!_hash_data!" ^| findstr /i /l /c:"!_hash!"') do set _hash_db=%%e
if "!_hash_db!" equ "" set "_hash_db=- So, no found^!! not "
echo/ & echo/ File hash md5 from: "!_file!" & echo/
echo/!_spc!Hash !_type_hash!: !_hash!
echo/ Data hash md5 ^(db^): !_hash_db! equals?
call :_delete_md5_:
call set /a _cnt_left=!_cnt_file! - 1 - !_cnt_keeped_!
)
timeout /t 10 2>nul >nul
)
)
for %%C in (file_hash hash strn_hash strn_hash hash_nul hash_db) do set _%%C=
exit /b
:_delete_md5_:
if /i "!_hash_db!" equ "!_hash!" del /q /f "!_path_gen!\!_file!"
if not exist "!_path_gen!\!_file!" (
echo/!_file! !_strn_hash!>>"!_y_deleted!"
echo/!_spc!!_spc:~-10!!_hash! "!_file!" file was deleted^^!
call set /a _cnt_file=!_cnt_file! - 1
call set /a _cnt_deleted=!_cnt_deleted! + 1
exit /b
) else (
echo/!_file! !_strn_hash!>>"!_n_deleted!"
echo/!_spc!!_spc:~-10!!_hash! "!_file!" file not was deleted^^!
call set /a _cnt_keeped_=!_cnt_keeped_! + 1
exit /b
)
:_error_:
echo/ & echo/ & echo/ !_error!
goto :_end_of_file_:
:_end_of_file_:
I have semicolon delimited CSV file. Some numerical values are stored with decimal point, for other data manipulation I need to use numbers with decimal comma. This should run for each file in the same folder on any Win machine. Any ideas?
I have tried PowerShell successfully on single file using this script
(Get-Content VER_ZdnSort201608-20160908210028original.csv) | ForEach-Object { $_ -replace "\.", "," } | VER_ZdnSort201608-20160908210028new.csv
But I can't seem to get it work with multiple files, also without replacing content without creating new files.
The data looks like this:
520100;2016-08-31;3197.90;N0401
520200;2016-08-31;6406.66;N0401
520430;2016-08-31;536.40;N0401
520800;2016-08-31;1547.70;N0401
...
Output should be like this:
520100;2016-08-31;3197,90;N0401
520200;2016-08-31;6406,66;N0401
520430;2016-08-31;536,40;N0401
520800;2016-08-31;1547,70;N0401
...
The following will search in a given folder for .csv files. It will then replace any . with , in all .csv files found, overwriting the new text to the same file.
Get-ChildItem -Path C:\Folder -Filter '*.csv' | ForEach-Object {
(Get-Content $_.FullName).Replace('.',',') | Out-File $_.FullName
}
The following script constitutes a pure batch-file solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%F in (%*) do (
for /F delims^=^ eol^= %%L in ('
type "%%~F" ^& ^> "%%~F" rem/
') do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
>> "%%~F" echo(!LINE:.=,!
endlocal
)
)
endlocal
exit /B
Provide the paths to your CSV files as command line arguments. Supposing the script is named convert-decimal-point.bat and your CSV files are located in D:\Data, use this command line:
convert-decimal-point.bat "D:\Data\*.csv"
Here is a comprehensive solution that does not blindly replace every . by , but checks each field whether it truly contains a fractional number (an optional sign +/-, followed by any number of decimal digits, followed by ., followed by any number of decimal digits; for example 1.2, -.73, +12.584) or an exponential number (a fractional number, followed by E/e, followed by a sign +/-, followed by one or more decimal digits; for example, 1.2E-02, -.73e+5). This is the batch-file code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SEARCH=." & rem // (decimal point to search for)
set "_REPLAC=," & rem // (decimal point for replacing)
set "_SEPCHR=;" & rem // (field separator character)
rem // Predefine global variables here:
set "$HEADER=" & rem // (set to something to ignore first line)
for %%F in (%*) do (
for /F delims^=^ eol^= %%L in ('
type "%%~F" ^& ^> "%%~F" rem/
') do (
set "COLL=%_SEPCHR%" & set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LINE=!LINE:"=""!^"
if "!LINE:**=!"=="!LINE!" (
if "!LINE:?=!"=="!LINE!" (
for %%I in ("!LINE:%_SEPCHR%=" "!") do (
endlocal
set "ITEM=%%~I"
call :PROCESS ITEM ITEM
setlocal EnableDelayedExpansion
for /F "delims=" %%C in (^""!COLL!!ITEM!%_SEPCHR%"^") do (
endlocal
set "COLL=%%~C"
setlocal EnableDelayedExpansion
)
)
) else set "COLL=%_SEPCHR%!LINE!%_SEPCHR%"
) else set "COLL=%_SEPCHR%!LINE!%_SEPCHR%"
set "COLL=!COLL:""="!^"
>> "%%~F" echo(!COLL:~1,-1!
endlocal
set "$HEADER="
)
)
endlocal
exit /B
:PROCESS rtn_string ref_string
setlocal EnableDelayedExpansion
set "#RET=%~1"
set "STR=!%~2!"
if not defined $HEADER (
if defined STR (
if "!STR:%_REPLAC%=!"=="!STR!" (
set "CHK=!STR:*%_SEARCH%=!%_SEARCH%"
set "CHK=!CHK:*%_SEARCH%=!"
if not defined CHK (
rem // Adapt regular expressions as needed:
(echo("!STR!" | > nul findstr /R ^
/C:"^\"[0-9]*\%_SEARCH%[0-9]*\" $" ^
/C:"^\"[+-][0-9]*\%_SEARCH%[0-9]*\" $" ^
/C:"^\"[0-9]*\%_SEARCH%[0-9]*[Ee][+-][0-9][0-9]*\" $" ^
/C:"^\"[+-][0-9]*\%_SEARCH%[0-9]*[Ee][+-][0-9][0-9]*\" $" ^
) && (
set "STR=!STR:%_SEARCH%=%_REPLAC%!"
)
)
)
)
)
for /F "delims=" %%S in (^""!STR!"^") do (
endlocal
set "%#RET%=%%~S"
)
exit /B
you can use this command :
$file = Get-Content c:\somewhere\file.csv |Out-String
$file.Replace(".",",") |Out-File c:\somewhere\file.csv