Powershell 2.0 извлекает определенные файлы из zip (включая подкаталоги) - PullRequest
1 голос
/ 06 апреля 2020

Извинения, этот вопрос разбросан по inte rnet, но мне еще предстоит найти удовлетворительный ответ, который использует только Powershell 2.0 (с. NET v3.5) - без внешних библиотек или программ

Я использую следующий код для извлечения log.txt из ZipFile.zip (независимо от местоположения log.txt)

$Destination = (new-object -com shell.application).NameSpace('C:\ZipExtractDir')
$ZipFile = (new-object -com shell.application).NameSpace('C:\ZipFile.zip')

$Destination.CopyHere(($Zipfile.Items() | where-object {$_.Name -like '*log.txt'}), 1044)
  • Работает, если log.txt находится в каталоге root \log.txt
  • Сбой, если log.txt находится в подкаталоге \Subfolder\log.txt
  • Сбой при обращении к буквенному (.zip) пути {$_.Name -Like '*Subfolder\log.txt'} (оба типа double и одиночные кавычки не работают)
  • Попробовал использовать -eq -like -contains '' "" $_.FullName

Я совершенно уверен, что я неправильно фильтрую - может кто-нибудь помочь с этим кодом, чтобы он также анализировал подкаталоги?

1 Ответ

0 голосов
/ 06 апреля 2020

Подобно тому, что вы уже сделали, вы можете настроить пространства имен Shell.Application следующим образом. Затем вы можете скопировать извлеченный каталог в путь назначения.

$zipFilePath = "Zipfile.zip"
$destinationPath = "C:\Users\Public\Downloads"

$zipfile = (New-Object -Com Shell.Application).NameSpace($zipFilePath)
$destination = (New-Object -Com Shell.Application).NameSpace($destinationPath)
$destination.CopyHere($zipfile.Items())

Затем, чтобы составить список log.txt файлов, мы можем построить полный извлеченный путь с помощью Join-Path. Это в основном просто добавляет имя файла zip из System.IO.Path.GetFileNameWithoutExtension() к пути назначения. Затем просто используйте Get-ChildItem для рекурсивного вывода списка файлов с помощью переключателей -Recurse и -Filter.

$extractedPath = Join-Path -Path $destinationPath -ChildPath ([System.IO.Path]::GetFileNameWithoutExtension($zipFilePath))
Get-ChildItem -Path $extractedPath -Filter log.txt -Recurse

И чтобы проверить это для PowerShell 2.0 , мы можем использовать -version 2 с powershell.exe:

powershell.exe -version 2 .\test.ps1

ОБНОВЛЕНИЕ

Если вы хотите проверить файлы перед извлечением, вам нужно будет самостоятельно просмотреть каталоги. Ниже приведена демонстрация того, как это можно сделать.

function New-ZipChildRootFolder 
{
    param 
    (
        [string]$DestinationPath,
        [string]$ZipFileName
    )

    $folderPath = Split-Path -Path $ZipFileName -Leaf

    $destination = (New-Object -ComObject Shell.Application).NameSpace($DestinationPath)

    $destination.NewFolder($folderPath)
}

function Get-ZipChildItems 
{
    param 
    (
        [string]$ZipFilePath,
        [string]$DestinationPath
    )

    $zipfile = (New-Object -ComObject Shell.Application).NameSpace($ZipFilePath)
    $zipFileName = [System.IO.Path]::GetFileNameWithoutExtension($ZipFilePath)

    Write-Output "Create root zip folder : $zipFileName"
    New-ZipChildRootFolder -DestinationPath $DestinationPath -ZipFileName $zipFileName

    foreach ($item in $zipFile.items()) 
    {
        Get-ZipChildItemsRecurse -Items $item -DestinationPath $DestinationPath -ZipFileName $zipFileName
    }
}

function Get-ZipChildItemsRecurse
{
    param 
    (
        [object]$Items,
        [string]$DestinationPath,
        [string]$ZipFileName
    )

    foreach ($file in $Items.getFolder.Items())
    {
        if ($file.IsFolder -eq $true) 
        {
            Write-Output "Creating folder : $($file.Path)"
            New-ZipChildFolder -Folder $file -DestinationPath $DestinationPath -ZipFileName $ZipFileName
            Get-ZipChildItemsRecurse -Items $file -DestinationPath $DestinationPath -ZipFileName $ZipFileName
        }
        else 
        {
            $filename = Split-Path -Path $file.Path -Leaf
            if ($filename -eq "log.txt")
            {
                Write-Output "Copying file : $($file.Path)"
                New-ZipChildFile -File $file -DestinationPath $DestinationPath -ZipFileName $ZipFileName
            }
        }
    }
}   

function New-ZipChildFile
{
    param
    (
        [object]$File,
        [string]$DestinationPath,
        [string]$ZipFileName
    )

    $destination = New-Object -ComObject Shell.Application

    $items = $File.Path.Split("\")

    $zipRootIndex = [array]::IndexOf($items, $ZipFileName)

    $path = $items[$zipRootIndex..($items.Length - 2)] -join "\"

    $fullPath = Join-path -Path $DestinationPath -ChildPath $path

    $destination.NameSpace($fullPath).CopyHere($File)
}

function New-ZipChildFolder
{
    param 
    (
        [object]$Folder,
        [string]$DestinationPath,
        [string]$ZipFileName
    )

    $destination = New-Object -ComObject Shell.Application

    $items = $Folder.Path.Split("\")

    $zipRootIndex = [array]::IndexOf($items, $ZipFileName)

    $folders = $items[$zipRootIndex..($items.Length - 1)]

    $currentFolder = $DestinationPath
    foreach ($folder in $folders)
    {
        $destination.NameSpace($currentFolder).NewFolder($folder)
        $currentFolder = Join-Path -Path $currentFolder -ChildPath $folder
    }
}

Использование:

$zipFilePath = "C:\Zipfile.zip"
$destinationPath = "C:\Users\Public\Downloads"

Get-ZipChildItems -ZipFile $zipFilePath -DestinationPath $destinationPath
...