PowerShell:脚本无法打开存档中的本机文件,但能够用于新创建的文件

嗨,大家好!

我创建了一个Powershell脚本,该脚本会处理一些存档文件,以对其中一个文件进行一些简单的文本编辑。

我的问题很简单,当我想打开和编辑xxx.ini时,它失败了。 但是,当我添加一个test.ini (或删除xxx.ini,然后将其重新添加),并尝试在此新文件上运行完全相同的脚本时,它就可以工作。

我尝试寻找 IsReadOnly 属性,但它返回false。

任何人都可以帮忙吗?

        if ($f -notmatch "bulkPrefEditor"){
            # The zip file to be updated
            $file = $f

            # Is the file read only ? Let's try to force that to false
            $isReadOnly = Get-ItemProperty -Path $file | Select-Object IsReadOnly
            Write-Log "Is $file Read-Only : $isReadOnly" "INFO" $logfile
            Set-ItemProperty -Path $file -Name IsReadOnly -Value $false


            Write-Log "Editing following file : $f" "INFO" $logfile

            # Load ZipFile (Compression.FileSystem) if necessary
            try { $null = [IO.Compression.ZipFile] }
            catch { [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') }

            # Open zip file with update mode (Update,Read,Create -- are the options)
            try { 
                $fileZip = [System.IO.Compression.ZipFile]::Open( $file,'Update' )
            }
            catch {
                Write-Log "Another process has locked the '$file' file." "ERROR" $logfile
                Write-Log "Another process has locked the '$file' file."
                continue
            }

            # Finding the specific file within the zip file
            try{
                $fileZip.Entries | Where-Object { $_.FullName -match "$innerpath" }
            } catch {
                Write-Log "Could not find $filepath\$innerpath in $f,have you used anti-slash instead of slash ?" "WARN" $logfile
                Write-Log "Could not find $filepath\$innerpath in $f,have you used anti-slash instead of slash "
                continue
            }
            pause
            # If needed,read the contents of specific file to $text and release the file so to use streamwriter later
            try{
                $desiredFile = [System.IO.StreamReader]($fileZip.Entries | Where-Object { $_.FullName -match "$innerpath" }).Open()
                $text = $desiredFile.ReadToEnd()
                $desiredFile.Close()
                $desiredFile.Dispose()
            }
            catch {
                Write-Log "Could not read $f/$innerpath in $f " "WARN" $logfile
                Write-Log "Could not read $f/$innerpath in $f "
                continue
            }

结果:

PowerShell:脚本无法打开存档中的本机文件,但能够用于新创建的文件

我已经在脚本中添加了一些简单的日志:

  

2019/11/21 18:40:12信息###################开始脚本... ########### #########   2019/11/21 18:40:12信息此脚本将对C:\ Users \ pfournet \ Documents \ Factory \ BulkPrefEditor中包含的文件进行操作   2019/11/21 18:40:12 INFO此脚本可以查看(4)文件。   2019/11/21 18:40:12 INFO可用文件列表(单行):20191119-123448387-Copie(2).zip 20191119-123448387-Copie.zip 20191119-123448387.zip BulkPrefEditor.ps1 BulkPrefEditor_Zip.ps1   2019/11/21 18:40:12 INFO已找到该文件:20191119-123448387-Copie(2).zip   2019/11/21 18:40:12 INFO已找到该文件:20191119-123448387-Copie.zip   2019/11/21 18:40:12 INFO已找到该文件:20191119-123448387.zip   2019/11/21 18:40:12 INFO此脚本将替换以下行:use-compression = true和use-compression = false   2019/11/21 18:40:12信息#################### COMMENCING OPERATIONS ################## ###   2019/11/21 18:40:12信息是20191119-123448387-Copie(2).zip只读:@ {IsReadOnly = False}   2019/11/21 18:40:12 INFO编辑以下文件:20191119-123448387-Copie(2).zip   2019/11/21 18:40:13 WARN无法读取20191119-123448387-Copie(2).zip / ul-flow / plugins / interactivedata.ini in 20191119-123448387-Copie(2).zip   2019/11/21 18:40:13信息是20191119-123448387-Copie.zip只读:@ {IsReadOnly = False}   2019/11/21 18:40:13 INFO编辑以下文件:20191119-123448387-Copie.zip   2019/11/21 18:40:13警告无法读取20191119-123448387-Copie.zip/ul-flow/plugins/interactivedata.ini in 20191119-123448387-Copie.zip   2019/11/21 18:40:13 INFO为20191119-123448387.zip只读:@ {IsReadOnly = False}   2019/11/21 18:40:13 INFO编辑以下文件:20191119-123448387.zip   2019/11/21 18:40:14警告无法读取20191119-123448387.zip中的20191119-123448387.zip/ul-flow/plugins/interactivedata.ini   2019/11/21 18:40:14信息#################### ENDING SCRIPT ... ############## ######

illidanwyz 回答:PowerShell:脚本无法打开存档中的本机文件,但能够用于新创建的文件

正如Rich Moss在他们的评论中提到的那样,编写的脚本没有处理这些对象,并且您将zip文件保持锁定状态。我最初的解决方案是从存档中提取所有文件,修改所需的文件,然后重新压缩。

Add-Type -AssemblyName System.IO.Compression.FileSystem

$file = Get-ChildItem C:\temp\test3.zip

$tempOutputFolder = "c:\temp\$(New-Guid)"

[System.IO.Compression.ZipFile]::ExtractToDirectory($file.FullName,$tempOutputFolder)

$zippedFilesToEdit = Get-ChildItem $tempOutputFolder -Recurse -File | Where-Object { $_.Name -eq "new 1" }

foreach ($zippedFile in $zippedFilesToEdit){
    #Modifiy your file,and save it
    Get-Content $zippedFile | for-each {$_ -replace "Pattern","ReplaceWith"} | Out-File $zippedFile.FullName
}

Remove-Item $file.FullName
[System.IO.Compression.ZipFile]::CreateFromDirectory($tempOutputFolder,$file.FullName)

这不像直接从存档中修改文件对象那样灵活。如果您的档案/文件很大,那么这将花费很长时间,因此我坐下来通过流进行了处理。该脚本有效,但是我敢肯定会有改进。 (我认为我们实际上可以直接编辑流),而且错误处理可能更好。我们要确保在失败完成后关闭/处置所有对象,因此我们需要对整个事物进行try / catch / finally块,这需要我们检查单个错误,将它们重新包装并抛出(`Write-错误-ErrorAction停止)再次。因为您将看不到错误的实际行号,所以这会使调试更加困难。您必须确保在捕获错误时能够正确处理预期的和意外的错误。

这在Win 10 / PS 5.1上为我运行。

编辑,我在开头和结尾处添加了代码,将通过创建包含10个生成文件的zip归档文件,报告大小,然后执行编辑操作并解压缩以检查zip文件的大小来进行测试。修改后的文件。 此代码将从$ Test *位置删除文件。在运行脚本之前,请先阅读该脚本,以便在按F5键之前知道该怎么做

$TestPath = "C:\temp\zipTest"
$testZipPath = "C:\temp\ZipTest.zip"
$filePathToFind = "test 1.txt"

If (-not (Test-Path $TestPath)){New-Item -Path $TestPath -ItemType Directory}
foreach( $i in 1..10){
   "Some Text/file contents" | Set-Content -Path "$TestPath\test $i.txt" 
}
Remove-Item -Path $testZipPath -Force -ErrorAction SilentlyContinue | Out-Null
[System.IO.Compression.ZipFile]::CreateFromDirectory($TestPath,$testZipPath)

Write-Host "File sizes before any operation: "
Get-ChildItem $testZipPath | foreach { Write-Host "filename: $($_.Name),length: $($_.Length)"}
Write-Host "test zip file size: $(Get-ChildItem $testZipPath | select -ExpandProperty Length)"

$file = $testZipPath
Write-Host ""
Write-Host "Running the opertion to modify the file in the archive"
try{

    # Check if zip files exists,and can open the file,then open if possible
    If(-not (Test-Path $file)){Write-Error "Zip File does not exist" -ErrorAction Stop}
    try { $fileZip = [System.IO.Compression.ZipFile]::Open( $file,'Update' ) }
    catch { Write-Error "Another process has locked the '$file' file." -ErrorAction Stop }

    # Finding the specific file within the zip file
    try{ $fileZip.Entries | Where-Object { $_.FullName -eq $filePathToFind } | Out-Null} 
    catch { Write-Error "Could not find $filePathToFind in $file." -ErrorAction Stop }

    # If needed,read the contents of specific file to $text and release the file so to use streamwriter later
        #Get the entry in the archive that you want to modify
        $zippedEntry = $fileZip.Entries | Where-Object { $_.FullName -eq $filePathToFind }
        if($zippedEntry -eq $null){Write-Error "Could not find entry in zip file" -ErrorAction Stop}
        #Open the file as a stream
        $desiredFile = [System.IO.StreamReader]($zippedEntry).Open() 
        #Read the entire contents to a string variable (Maybe you could manipulate the stream but not sure how to do that)
        $text = $desiredFile.ReadToEnd()

        #Cleanup
        $desiredFile.Close() | Out-Null
        $desiredFile.Dispose()| Out-Null

        #Modify the contents as needed. In this case I am just setting the contents to a bunch of numbers
        [string]$newText = ((1..1000) | % {"$_`n"})

        #Delete the entry in the archive
        $zippedEntry.Delete()
        #Create a new (empty) entry at the path inside the archive
        $newEntry = $fileZip.CreateEntry($filePathToFind)

        #Open the new entry as a stream and write the new text to it
        $stream = [System.IO.StreamWriter] $newEntry.Open()
        $stream.Write($newText)
        $stream.Close()
}
catch {
    throw
}
finally{
    # You want to dispose of everything in a finally block so that the objects get removed even if an error is thrown 
    $desiredFile.Close() | Out-Null
    $desiredFile.Dispose()| Out-Null
    $stream.Close() | Out-Null
    $fileZip.Dispose()| Out-Null
}
Write-Host "Zipped file update complete"
Write-Host ""

# Check zip size and individual file sizes after operation (Just to test. Will delete files on your computer!!!!)
Write-Host "test zip file size after replacement: $(Get-ChildItem $testZipPath | select -ExpandProperty Length)"
$FollowUpTestPath = "$(Split-Path $testZipPath -Parent)\FollowUpTest"
Remove-Item $FollowUpTestPath -Recurse -Force -ErrorAction SilentlyContinue
If(-not (Test-Path $FollowUpTestPath)){New-Item -Path $FollowUpTestPath -ItemType Directory | Out-Null}
[System.IO.Compression.ZipFile]::ExtractToDirectory($testZipPath,$FollowUpTestPath)
Write-Host "File sizes after operation: "
Get-ChildItem $FollowUpTestPath | foreach { Write-Host "filename: $($_.Name),length: $($_.Length)"}
本文链接:https://www.f2er.com/3055933.html

大家都在问