Nologic 30 Posted May 25, 2015 Share Posted May 25, 2015 (edited) Why: I acquire mult-part archive files from time to time, when I do it's normally in mass. This script allows me to well recursively unarchive and clean up afterwards. Note 1: Handles passwords as well...just create a text file called "Passwords.txt" and place each password to try on a new line in the file, and of course the file must be located where this script is saved. Note 2: This doesn't at present unarchive archives inside of an archive...you'll just have to run it again for now. Note 3: For extra ease of use, compile it & create a shortcut to the executable in your SendTo folder. Handles: *.rar *.part###.rar *.###.rar *.r### *.zip *.zipx *.zx### *.z### *.7z *.par2 Requirements: AutoIt PhPar2 7-Zip WinRar WinZip (Not recommended) [Warning! Adware/Malware in installer!] Instructions: Install AutoIt and set it to execute scripts when double clicked. Install one or more of the Archiver app's listed above. Create a folder somewhere...lets call it "UnArchive & CleanUp" just to be unimaginative. Now download and unarchive PhPar2 into "UnArchive & CleanUp". Now going into "UnArchive & CleanUp" folder Right Click on it's background and select "New\AutoIt v3 Script" from the context menu, and Rename it "UnArchive & CleanUp.au3" Now Right Click "UnArchive & CleanUp.au3" & select "Edit Script" from the context menu. Now paste the following code into: #Include <Array.au3> #Include <Constants.au3> #Include <File.au3> #Include <Process.au3> #Include <String.au3> #Include 'ProcessGetExitcode.au3' $s7zip = _7zip_RegRead() $sWinRAR = _WinRAR_RegRead() $sWinZip = _WinZip_RegRead() Global $Passwords _FileReadToArray( @ScriptDir & '\Passwords.txt' , $Passwords ) If NOT IsArray( $Passwords ) Then Global $Passwords[2] = [1,''] ; Select Archive Folder If $CmdLine[0] = 0 Then While 1 $sSourceFolder = FileSelectFolder( 'Select Source Folder.' , '' , 6 ) If @Error = 1 AND $sSourceFolder = '' Then MsgBox( 4096 , 'Exit:' , 'Ending Application' ) Exit ElseIf $sSourceFolder = '' Then MsgBox( 4096 , 'Error:' , 'Unable To Open Folder.' ) ElseIf NOT FileExists ( $sSourceFolder ) Then MsgBox( 4096 , 'Error:' , 'Invalid Folder.' ) Else If StringRight( $sSourceFolder , 1 ) <> '\' Then $sSourceFolder &= '\' $aAllFiles = _FileListToArrayRec( $sSourceFolder , '*.*' , 1 , 1 , 0 , 2 ) If NOT IsArray( $aAllFiles ) Then MsgBox( 4096 , 'Error:' , 'No Files Found.' ) Else _ArraySort( $aAllFiles , 0 , 1 ) ExitLoop EndIf EndIf WEnd _Main( $aAllFiles ) Else For $ii = 1 To $CmdLine[0] If StringInStr( FileGetAttrib( $CmdLine[$ii] ) , 'D' ) = 0 Then ContinueLoop $sSourceFolder = $CmdLine[$ii] If StringRight( $sSourceFolder , 1 ) <> '\' Then $sSourceFolder &= '\' $aAllFiles = _FileListToArrayRec( $sSourceFolder , '*.*' , 1 , 1 , 0 , 2 ) If NOT IsArray( $aAllFiles ) Then ContinueLoop _ArraySort( $aAllFiles , 0 , 1 ) _Main( $aAllFiles ) Next EndIf MsgBox( 0 , 'Complete:' , 'Batch UnArchive has been Completed.' ) Func _Main( ByRef $aArray ) ; Prune Files For $ii = $aArray[0] To 1 Step - 1 $Value = StringRegExp( $aArray[$ii] , '\.(part\d+\.rar|r(ar|\d+)|zipx|zx\d+|zip|z\d+|7z|\d+|par2)$' , 0 ) If $Value = 0 Then _ArrayDelete( $aArray , $ii ) $aArray[0] -= 1 EndIf Next ; PAR2 Repair If FileExists( @ScriptDir & '\phpar2.exe' ) Then $aFindAll = _ArrayFindAll( $aArray , '.par2' , 1 , 0 , 0 , 1 ) _ArraySort( $aFindAll , 1 ) For $ii = 0 To UBound( $aFindAll ) - 1 If StringRegExp( $aArray[$aFindAll[$ii]] , '\.vol\d+' , 0 ) = 0 Then RunWait( @ScriptDir & '\phpar2.exe r "' & $aArray[$aFindAll[$ii]] & '"' , '' , @SW_HIDE ) EndIf Next ; PAR2 Delete For $ii = 0 To UBound( $aFindAll ) - 1 ; Delete File FileDelete ( $aArray[$aFindAll[$ii]] ) ; Delete Array Listing _ArrayDelete( $aArray , $aFindAll[$ii] ) $aArray[0] -= 1 Next EndIf ; UnArchive Files & Clean Up $ii = 0 While $ii < $aArray[0] $ii += 1 ; New WinRAR archive format: <name>.part<number>.rar (all) $bRegExTest = StringRegExp( $aArray[$ii] , '\.part\d*\.rar$' , 0 ) If $bRegExTest = 1 AND $sWinRAR <> '' Then For $jj = 1 To $Passwords[0] $sCatch = _Extract( $aArray[$ii], $sWinRAR , ' x -kb -p"' & $Passwords[$jj] & '" -o+ ' , '' ) $ExitCode = Int( StringLeft( $sCatch , StringInStr( $sCatch , '|' ) - 1 )) $Data = StringTrimLeft( $sCatch , StringInStr( $sCatch , '|' )) If $ExitCode = 0 Then _CleanUp( $aArray[$ii] , $aArray , '(.+?)\.part\d*\.rar$' , '.part' ) $ii -= 1 ContinueLoop 2 EndIf Next EndIf ; Old WinRAR archive format: <name>.rar | <name>.r<number> (following) $bRegExTest = StringRegExp( $aArray[$ii] , '\.r(ar|\d+)$' , 0 ) If $bRegExTest = 1 AND $sWinRAR <> '' Then For $jj = 1 To $Passwords[0] $sCatch = _Extract( $aArray[$ii], $sWinRAR , ' x -kb -p"' & $Passwords[$jj] & '" -o+ ' , '' ) $ExitCode = Int( StringLeft( $sCatch , StringInStr( $sCatch , '|' ) - 1 )) $Data = StringTrimLeft( $sCatch , StringInStr( $sCatch , '|' )) If $ExitCode = 0 Then _CleanUp( $aArray[$ii] , $aArray , '(.+?)\.r(?:ar|\d+)$' , '.r' ) $ii -= 1 ContinueLoop 2 EndIf Next EndIf ; New WinZip archive format: <name>.zipx | <name>.zx<number> (following) $bRegExTest = StringRegExp( $aArray[$ii] , '\.zipx$' , 0 ) If $bRegExTest = 1 AND $sWinZip <> '' Then For $jj = 1 To $Passwords[0] $sCatch = _Extract( $aArray[$ii], $sWinZip , ' -d -o -s"' & $Passwords[$jj] & '" ' , '' ) $ExitCode = Int( StringLeft( $sCatch , StringInStr( $sCatch , '|' ) - 1 )) $Data = StringTrimLeft( $sCatch , StringInStr( $sCatch , '|' )) If $ExitCode = 0 Then _CleanUp( $aArray[$ii] , $aArray , '(.+?)\.(?:zipx|zx\d*)$' , '.' ) $ii -= 1 ContinueLoop 2 EndIf Next EndIf ; Old WinZip archive format: <name>.zip | <name>.z<number> (following) $bRegExTest = StringRegExp( $aArray[$ii] , '\.zip$' , 0 ) If $bRegExTest = 1 AND $sWinZip <> '' Then For $jj = 1 To $Passwords[0] $sCatch = _Extract( $aArray[$ii], $sWinZip , ' -d -o -s"' & $Passwords[$jj] & '" ' , '' ) $ExitCode = Int( StringLeft( $sCatch , StringInStr( $sCatch , '|' ) - 1 )) $Data = StringTrimLeft( $sCatch , StringInStr( $sCatch , '|' )) If $ExitCode = 0 Then _CleanUp( $aArray[$ii] , $aArray , '(.+?)\.(?:zip|z\d+)$' , '.' ) $ii -= 1 ContinueLoop 2 EndIf Next EndIf ; 7-Zip archive format: <name>.7z.<number> (all) $bRegExTest = StringRegExp( $aArray[$ii] , '\.(7z|\d+)$' , 0 ) If $bRegExTest = 1 AND $s7zip <> '' Then For $jj = 1 To $Passwords[0] $sCatch = _Extract( $aArray[$ii], $s7zip , ' x ' , '-p"' & $Passwords[$jj] & '" -aoa -o' ) $ExitCode = Int( StringLeft( $sCatch , StringInStr( $sCatch , '|' ) - 1 )) $Data = StringTrimLeft( $sCatch , StringInStr( $sCatch , '|' )) If $ExitCode = 0 Then _CleanUp( $aArray[$ii] , $aArray , '(.+?)\.(?:7z|\d+)$' , '.' ) $ii -= 1 ContinueLoop 2 EndIf Next EndIf WEnd EndFunc Func _Extract( $sInfile , $sApplication , $sCMDLine1 , $sCMDLine2 ) Local $Data , $ExitCode , $Handle_PID , $PID $sFileDir = StringLeft( $sInfile , StringInStr( $sInfile , '\' , 0 , -1 )) ; Extract File With Process Stdout Flag STDERR_MERGED $PID = Run( $sApplication & $sCMDLine1 & '"' & $sInfile & '" ' & $sCMDLine2 & '"' & $sFileDir & '"' , '' , Default , 8 ) ; Open Process Handle $Handle_PID = _ProcessOpenHandle( $PID ) ; Get Stdout Data Do Sleep( 10 ) $Data &= StdoutRead( $PID ) Until @Error ; Require Process To Be Closed Before Calling _ProcessGetExitCode() ProcessWaitClose( $PID ) ; Get Exitcode Of Process $ExitCode = _ProcessGetExitCode( $Handle_PID ) ; Close Process Handle _ProcessCloseHandle( $Handle_PID ) Return $ExitCode & '|' & $Data EndFunc Func _CleanUp( $sInfile , ByRef $aArray , $sRegEx , $sFind ) ; Perform CleanUp $sRegExName = StringRegExp( $sInfile , $sRegEx , 1 ) $aFindAll = _ArrayFindAll( $aArray , _ArrayToString( $sRegExName ) & $sFind , 1 , 0 , 0 , 1 ) _ArraySort( $aFindAll , 1 ) For $ii = 0 To UBound( $aFindAll ) - 1 ; Delete File FileDelete ( $aArray[$aFindAll[$ii]] ) ; Delete Array Listing _ArrayDelete( $aArray , $aFindAll[$ii] ) $aArray[0] -= 1 Next EndFunc Func _7zip_RegRead() $String = RegRead( 'HKLM\SOFTWARE\7-Zip' , 'Path' ) If $String = '' Then $String = RegRead( 'HKLM64\SOFTWARE\7-Zip' , 'Path' ) If $String <> '' Then If StringRight( $String , 1 ) <> '\' Then $String &= '\' If FileExists( $String & '7z.exe' ) Then Return $String & '7z.exe' Else Return '' EndIf Else Return '' EndIf EndFunc Func _WinRAR_RegRead() $String = RegRead( 'HKLM\SOFTWARE\WinRAR' , 'exe' ) If $String = '' Then $String = RegRead( 'HKLM64\SOFTWARE\WinRAR' , 'exe64' ) If $String <> '' Then $String = StringLeft( $String , StringInStr( $String , '\' , 0 , -1 )) If FileExists( $String & 'UnRAR.exe' ) Then Return $String & 'UnRAR.exe' Else Return '' EndIf Else Return '' EndIf EndFunc Func _WinZip_RegRead() $String = RegRead( 'HKLM\SOFTWARE\Nico Mak Computing\WinZip\Programs' , 'zip2exe' ) If $String = '' Then $String = RegRead( 'HKLM64\SOFTWARE\Nico Mak Computing\WinZip\Programs' , 'zip2exe' ) If $String <> '' Then $String = StringLeft( $String , StringInStr( $String , '\' , 0 , -1 )) If FileExists( $String & 'WZUnZip.Exe' ) Then Return $String & 'WZUnZip.Exe' Else Return '' EndIf Else Return '' EndIf EndFunc Now save the script. Right Click on the background again and select "New\AutoIt v3 Script" from the context menu, and Rename it "ProcessGetExitcode.au3" Now Right Click "ProcessGetExitcode.au3" & select "Edit Script" from the context menu. Now paste the following code into: #include-once ; #FUNCTION# ==================================================================================================================== ; Name...........: _ProcessOpenHandle ; Description ...: Get the process handle of a process to query ; Syntax.........: _ProcessOpenHandle($iPID) ; Parameters ....: $iPID - Process ID to get handle of to query ; Return values .: Success - Handle of the process ; Failure - 0 ; Author ........: Michael Heath (MHz) ; Modified.......: 2013-06-21 Changes made to make more compatible with _WinAPI* functions ; Remarks .......: Uses PROCESS_QUERY_INFORMATION to call the Dll function OpenProcess. Use _WinAPI_OpenProcess for advanced use. ; Related .......: _ProcessCloseHandle, _ProcessGetExitcode ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _ProcessOpenHandle($iPID) ; Get the process handle of the process to query\n Return: Success Handle as array. Failure 0 Local Const $PROCESS_QUERY_INFORMATION = 0x400 Local $hPID = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', $PROCESS_QUERY_INFORMATION, 'int', 0, 'int', $iPID) If @error Then Return SetError(@error, @extended, 0) Return $hPID[0] EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: _ProcessGetExitcode ; Description ...: Get exitcode of a process ; Syntax.........: _ProcessGetExitcode($hPID) ; Parameters ....: $hPID - Handle returned from _ProcessOpenHandle or handle returned from _WinAPI_OpenProcess ; Return values .: Success - Exitcode of the closed process ; Failure - 0 ; Author ........: Michael Heath (MHz) ; Modified.......: 2013-06-21 Changes made to make more compatible with _WinAPI* functions ; Remarks .......: Require process to be closed before calling this function ; Related .......: _ProcessOpenHandle, _ProcessCloseHandle ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _ProcessGetExitcode($hPID) ; Get exitcode of the closed process\n Return: Success Exitcode as integer. Failure 0 Local $vPlaceholder $hPID = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $hPID, 'int*', $vPlaceholder) If @error Then Return SetError(@error, @extended, 0) Return $hPID[2] EndFunc ; #FUNCTION# ==================================================================================================================== ; Name...........: _ProcessCloseHandle ; Description ...: Close the handle of a process ; Syntax.........: _ProcessCloseHandle($hPID) ; Parameters ....: $hPID - Handle returned from _ProcessOpenHandle or handle returned from _WinAPI_OpenProcess ; Return values .: Success - 1 ; Failure - 0 ; Author ........: Michael Heath (MHz) ; Modified.......: 2013-06-21 Changes made to make more compatible with _WinAPI* functions ; Remarks .......: Use _WinAPI_CloseHandle for advanced use with @error ; Related .......: _ProcessOpenHandle, _ProcessGetExitcode ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _ProcessCloseHandle($hPID) ; Close the handle of a process\n Return: Success 1. Failure 0 DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $hPID) If @error Then Return SetError(@error, @extended, 0) Return 1 EndFunc Now save the script. Now execute "UnArchive & CleanUp.au3" by double clicking it and then select the folder holding the archives that you wish to process. *Update* Added passing folders via command line. This is mostly aimed at adding SendTo context menu support. 1. Right Click on "UnArchive & CleanUp.au3" and select "Compile Script (x86)" from the context menu 2. Left Click + ALT on "UnArchive & CleanUp.exe" and Drag to create a shortcut...rename to remove ".exe" from the file name 3. Cut & Paste shortcut to your SendTo folder: %APPDATA%\Microsoft\Windows\SendTo\ Now you don't even need to hunt down the script when you need it. Edited May 26, 2015 by Nologic 1 Link to comment Share on other sites More sharing options...
Luke 36879 Posted May 25, 2015 Share Posted May 25, 2015 Great stuff! Link to comment Share on other sites More sharing options...
Nologic 30 Posted May 26, 2015 Author Share Posted May 26, 2015 Thanks Luke! Well I updated it...now supports multiple folders being set to it via command line. So compiling the script and then creating a shortcut in the SendTo folder makes it a bit more handy. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now