Private/Invoke-7zInterop.ps1
function Invoke-7zInterop { [CmdletBinding()] #This (internal) function does the hard work: it calls 7-Zip with the appropriate arguments Param( # The operation to perform [Parameter(Mandatory)] [ValidateSet("New", "Add", "Update", "List", "Extract", "Test")] [string]$Operation, [ValidateSet('7z','zip','gzip','bzip2','tar','iso','udf')] [Alias("Type")] [string] $ArchiveType = '7z', # The path of the archive [Parameter(Mandatory)] [Alias("Path")] [string]$ArchivePath, # A list of file names or patterns to include [Parameter(Mandatory)] [AllowEmptyCollection()] [string[]]$Include, # A list of file names or patterns to exclude [Parameter(Mandatory=$false)] [AllowEmptyCollection()] [string[]]$Exclude, # Apply include patterns recursively [Parameter(Mandatory=$false)] [switch]$Recurse, # If given this will encrypt and secure the archive [Parameter(Mandatory=$false)] [SecureString]$Password, #during add operations Force overwrite of archive and start from empty file #during update operations overwrite individual files within archive [Parameter(Mandatory=$false)] [switch]$Force, # Additional switches for 7z [Parameter(Mandatory=$false)] [AllowEmptyString()] [string]$Switches, # Throw if the output does not contain "Everything is OK" [Parameter(Mandatory=$false)] [bool]$CheckOK = $true ) $Arguments = [System.Collections.ArrayList]@() $fileMode = [System.Collections.ArrayList]@() switch ($Operation) { "New" { # New means the archive file will be recreated $verb = "Adding to new" $fileMode += "-mx9" # -mx9: Ultra compression } "Add" { $verb = "Adding to" $fileMode += "-mx9" # -mx9: Ultra compression } "Update" { $verb = "Updating" $fileMode += "-mx9" # -mx9: Ultra compression } "Extract" { $verb = "Extracting" if ( $PSBoundParameters.ContainsKey('Force') ) { $fileMode += "-aoa" #-aoa: Overwrite All existing files without prompt } } "List" { $verb = "Listing" } "Test" { $verb = "Testing" } } #Add the operation command to the switches $Arguments += $verb.Substring(0,1).ToLower() #Add the archive type to the switches $Arguments += '-t{0}' -f $ArchiveType #here is a quick fix for some the archive path that might be #double quoted too many times. This might not be needed. $Arguments += ('"{0}"' -f $ArchivePath).Replace('""','"') # Set up switches to use. #These two switches are for unattended scenarios $Arguments += "-bd", "-y" # -bd: no percentage indicator; -y: Yes to all prompts Write-Debug -Message ('ParameterKey Recurse: {0}' -f $PSBoundParameters.ContainsKey('Recurse')) if ( $PSBoundParameters.ContainsKey('Recurse') ) { $Arguments += "-r" } # -r: recurse parameter present Write-Debug -Message ('ParameterKey Password: {0}' -f $PSBoundParameters.ContainsKey('Password')) if ( $PSBoundParameters.ContainsKey('Password') ) { # -p: Password parameter present $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password) $pString = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) $Arguments += '"-p{0}"' -f $pString $pString = $null $fileMode += "-mhe" #Encrypt file headers in archive } #These are the file handler switches that manage what 7zip should do in #the event of filename conflicts. These switches need to go after the mode #and initial switches in the arguments array. #May need to research this switch for duplicate filenames in different folders #$fileMode += "-spf" # -spf : Use fully qualified filenames $Arguments += $fileMode # Add excludes to the switches if ( $PSBoundParameters.ContainsKey('Exclude') -and $Exclude.Count -gt 0) { # Exclude file list parameter present $Arguments += $Exclude | ForEach-Object { '"-x!{0}"' -f $_ } } # Add includes to the switches $Arguments += $Include | ForEach-Object { '"-i!{0}"' -f $_ } #Add any explicitly passed parameters to the switches $Arguments += $Switches -split '\s+' | ForEach-Object { '{0}' -f $_ } #Spin up sub thread to run 7zip executable $pinfo = New-object System.Diagnostics.ProcessStartInfo $pinfo.CreateNoWindow = $true $pinfo.UseShellExecute = $false $pinfo.RedirectStandardOutput = $true $pinfo.RedirectStandardError = $true $pinfo.FileName = $7zSettings.Path7zEXE $pinfo.Arguments = $Arguments $process = New-Object System.Diagnostics.Process $process.StartInfo = $pinfo [void]$process.Start() $stdout = $process.StandardOutput.ReadToEnd() $stderr = $process.StandardError.ReadToEnd() $process.WaitForExit() Write-Debug -Message "============================================" Write-Debug -Message ('Standard Output: {0}' -f $stdout ) Write-Debug -Message "============================================" Write-Debug -Message ('Error Output: {0}' -f $stderr ) Write-Debug -Message "============================================" Write-Debug -Message ( "Exit Code: " + $process.ExitCode ) Write-Debug -Message ( '7zip exe: {0}' -f ($7zSettings.Path7zEXE) ) Write-Debug -Message 'Arguments: ' $Arguments | ForEach-Object { Write-Debug -Message ('{0}' -f $_ )} Write-Debug -Message "============================================" # Check result if ($CheckOK) { $Err = "System ERROR: " $isBAD = ([string]$stdout).Contains($Err) $isOK = ([string]$stdout).Contains("Everything is Ok") if (-not $isOK ) { [string]$errorMessage = '{0} archive failed.' -f $verb if ($isBAD) { $errorMessage = $stdout.Substring($stdout.IndexOf($Err) + 14 ) } Debug-ThrowException ` -Message $errorMessage ` -Verb $verb ` -Path $ArchivePath ` -Output ($stdout + "`r`n" + $stderr) ` -LineNumber Get-CurrentLineNumber ` -Filename Get-CurrentFileName ` -Executable $7zSettings.Path7zEXE ` -Exception ([System.InvalidOperationException]::new($errorMessage)) } } # No error: return the 7-Zip output Write-Output $stdout } |