Home > Back-end >  Powershell does not recognize command -PassThru
Powershell does not recognize command -PassThru

Time:10-22

I am using the Expand-Archive command to unzip some .zip files. I want this process to generate a log and I am trying to use the parameter -PassThru.

Expand-Archive D:\Users\user1\Desktop\Zip\de23.zip -DestinationPath D:\Users\user1\Desktop\result -Force -PassThru

Result:

Expand-Archive : A parameter cannot be found that matches parameter name 'PassThru'.

Reference: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/expand-archive?view=powershell-7.2

CodePudding user response:

As mentioned in the comments, the documentation you're referencing is for the latest version of PowerShell. For the last version of Windows PowerShell (version 5.1), the -PassThru switch is not present.

To work around this you can use the underlying .NET API to "manually" unpack the archive:

Add-Type -AssemblyName System.IO.Compression

$destination = "C:\destination\folder"

# Define log file name
$logFileName = "unpack-archive.log"

# Locate zip file
$zipFile = Get-Item C:\path\to\file.zip

"[$(Get-Date -F o)][INFO] Opening '$($zipFile.FullName)' to expand" |Add-Content $logFileName

# Open a read-only file stream
$zipFileStream = $zipFile.OpenRead()

# Instantiate ZipArchive
$zipArchive = [System.IO.Compression.ZipArchive]::new($zipFileStream)

# Iterate over all entries and pick the ones you like
foreach($entry in $zipArchive.Entries){
    try {
        "[$(Get-Date -F o)][INFO] Attempting to create '$($entry.Name)' in '${destination}'" |Add-Content $logFileName

        # Create new file on disk, open writable stream
        $targetFileStream = $(
            New-Item -Path $destination -Name $entry.Name -ItemType File
        ).OpenWrite()

        "[$(Get-Date -F o)][INFO] Attempting to copy '$($entry.Name)' to target file" |Add-Content $logFileName
        # Open stream to compressed file, copy to new file stream
        $entryStream = $entry.Open()
        $entryStream.BaseStream.CopyTo($targetFileStream)
    }
    catch {
        "[$(Get-Date -F o)][ERROR] Failed to unpack '$($entry.Name)': ${_}" |Add-Content $logFileName
    }
    finally {
        # Clean up
        $targetFileStream,$entryStream |ForEach-Object Dispose
    }
}

# Clean up
$zipArchive,$zipFileStream |ForEach-Object Dispose

CodePudding user response:

Complementing Mathias's helpful answer, here is a solution that uses the -Verbose switch to generate a log and then parses the file paths from this log to achieve the same output as with -PassThru on newer PowerShell versions:

Expand-Archive ZipFile.zip -DestinationPath C:\ExtractDir -Force -Verbose 4>&1 | 
    Select-String -Pattern "Created '(. )'" | 
    Get-Item -Path { $_.Matches.Groups[1].Value }
  • 4>&1 redirects (merges) the verbose stream (created by -Verbose) into the success (standard output) stream, so we can process it by pipeline commands. See About Output Streams.
  • Select-String searches each line of output for the given RegEx pattern. See this RegEx101 demo for a detailed explanation and the ability to experiment.
  • In the Get-Item line the path is specified through a delay-bind script block. This script block extracts the value of the 1st group (the file path) from the current RegEx match.
  • Get-Item outputs a FileInfo object, similar to what Expand-Archive -PassThru on newer PowerShell versions produces. This causes the default PowerShell formatter to produce the familiar directory listing.
  • Related