Jump to content

UnArchive & CleanUp


Nologic

Recommended Posts

Nologic

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 by Nologic
  • Like 1
Link to comment
Share on other sites

Nologic

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...