繁体   English   中英

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

[英]PowerShell : Script unable to open native file in archive, but able for newly created file

嗨,大家好 !

我创建了一个 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
            }

结果: 在此处输入图像描述

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

2019/11/21 18:40:12 INFO ################### 启动脚本... ############## ###### 2019/11/21 18:40:12 INFO 此脚本将对 C:\Users\pfournet\Documents\Factory\BulkPrefEditor 中包含的文件进行操作 2019/11/21 18:40:12 INFO 此脚本可以看到(4)个文件。 2019/11/21 18:40:12 INFO List of available files (single line): 20191119-123448387 - Copie (2).zip 20191119-123448387 - Copie.zip 20191119-123448387.zip BulkPrefEditor.ps1 BulkPrefEditor_Zip.ps1 2019/ 11/21 18:40:12信息已找到此文件:20191119-123448387 -Copie(2).zip 2019/2021/21/21/21/21/21 18:40:12 INFO THIN222221B. 2011BIE:20191119-119-123488888888888888884888484848484848484848484848484848484848484848484848484848488848 lar /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 INFO ################### 开始运营################ ### 2019/11/21 18:40:12 INFO 是 20191119-123448387 - 副本 (2).zip 只读:@{IsReadOnly=False} 2019/11/21 18:40:12 INFO 编辑以下文件: 2 0191119-123448387 - 复制 (2).zip 2019/11/21 18:40:13 警告无法读取 20191119-123448387 - 复制 (2).zip/ul-flow/plugins/19-191.ini in 24481721 (2)。 -123448387 - Copie.zip 2019/11/21 18:40:13 WARN Could not read 20191119-123448387 - Copie.zip/ul-flow/plugins/interactivedata.ini in 20191119-123448387 - Copie.zip 2019/11/21 18:40:13 INFO Is 20191119-123448387.zip Read-Only: @{IsReadOnly=False} 2019/11/21 18:40:13 INFO Editing following file: 20191119-123448387.zip 2019/11/21 18:40 :14 WARN 无法读取 20191119-123448387.ZADCDBD79A8D84 中的 20191119-123448387.zip/ul-flow/plugins/interactivedata.ini 175C229B192AADC02F2Z 2019/11/21 18:40:14 信息 #################### 结束脚本... ############# #######

正如 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)

这不如直接从存档中修改文件 object 灵活。 如果你有一个很大的存档/文件,这将花费太长时间,所以我坐下来通过 stream 来完成它。 该脚本有效,但我相信可能会有改进。 (我认为我们实际上可以直接编辑 stream)此外,错误处理可能会更好。 我们希望确保在失败完成时关闭/处理所有对象,因此我们需要一个 try/catch/finally 块围绕整个事物,这需要我们检查单个错误,重新打包并抛出(`Write- Error -ErrorAction Stop) 再次。 这会使调试更加困难,因为您不会看到错误的实际行号。 您必须确保在捕获错误时正确处理预期和意外错误。

这适用于我在 Win 10/PS 5.1 上运行。

编辑我在开头和结尾添加了代码,它将通过创建一个包含 10 个生成文件的 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)"}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM