Tệp zip PowerShell đồng bộ


10

Trong tập lệnh PowerShell, tôi muốn nén thư mục trước khi xóa thư mục. Tôi chạy như sau (Tôi không nhớ nơi tôi tìm thấy đoạn trích):

function Compress-ToZip
{
    param([string]$zipfilename)

    if(-not (test-path($zipfilename)))
    {
        set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
        (Get-ChildItem $zipfilename).IsReadOnly = $false   
    }

    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipfilename)

    foreach($file in $input)
    {
         $zipPackage.CopyHere($file.FullName)

    }
}

Đoạn mã này thực sự nén thư mục, nhưng theo cách không đồng bộ. Trong thực tế, phương thức CopyHere của các đối tượng Shell.Application bắt đầu nén và không chờ hoàn thành. Các câu lệnh tiếp theo của tập lệnh của tôi sau đó bị rối (vì quá trình tệp zip chưa hoàn thành).

Bất kỳ đề xuất? Nếu có thể, tôi muốn tránh thêm bất kỳ tệp thực thi nào và duy trì các tính năng thuần Windows.

[sửa] toàn bộ nội dung của tệp PS1 của tôi trừ đi tên thật của DB. Mục tiêu của tập lệnh là sao lưu một tập hợp SQL db, sau đó nén các bản sao lưu trong một gói duy nhất trong một thư mục có tên là ngày hiện tại:

$VerbosePreferenceBak = $VerbosePreference
$VerbosePreference = "Continue"

add-PSSnapin SqlServerCmdletSnapin100

function BackupDB([string] $dbName, [string] $outDir)
{
    Write-Host "Backup de la base :  $dbName"
    $script = "BACKUP DATABASE $dbName TO DISK = '$outDir\$dbName.bak' WITH FORMAT, COPY_ONLY;"

    Invoke-Sqlcmd -Query "$script" -ServerInstance "." -QueryTimeOut 600
    Write-Host "Ok !"
}

function Compress-ToZip
{
    param([string]$zipfilename)

Write-Host "Compression du dossier"

    if(-not (test-path($zipfilename)))
    {
        set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
        (Get-ChildItem $zipfilename).IsReadOnly = $false   
    }

    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipfilename)

    foreach($file in $input)
    {
         $zipPackage.CopyHere($file.FullName)       
    }
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

}


$targetDir = "E:\Backup SQL"
$date = Get-Date -format "yyyy-MM-dd"
$newDir = New-Item -ItemType Directory "$targetDir\$date\sql" -Force

BackupDB  "database 1" "$newDir"
BackupDB  "database 2" "$newDir"
BackupDB  "database 3" "$newDir"

Get-Item $newDir | Compress-ToZip "$targetDir\$date\sql_$date.zip"


Write-Host "."
remove-item $newDir -Force -Confirm:$false -Recurse

$VerbosePreference = $VerbosePreferenceBak

Chỉ để xem nếu nó hoạt động nếu nó đồng bộ: Nếu bạn thêm mã sau đây sau khi foreach của bạn, nó có hoạt động như mong đợi không? Dòng 1: Write-Host "Press any key to continue ..." Dòng2:$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Kerry

Và trong quá trình kiểm tra, tôi rõ ràng giả định rằng bạn sẽ không "nhấn bất kỳ phím nào để tiếp tục" cho đến khi bạn xác nhận thủ công rằng quy trình zip đã hoàn tất.
Kerry

@Kerry: nó thực sự hoạt động như mong đợi khi tôi thêm bài kiểm tra thủ công của bạn
Steve B

Câu trả lời:


5

Cuối cùng tôi đã tìm thấy một cách sạch sẽ, chơi với các thuộc tính của các đối tượng com. Đặc biệt, đoạn mã sau có thể kiểm tra xem tệp có trong tệp zip hay không:

foreach($file in $input)
{
    $zipPackage.CopyHere($file.FullName)    
    $size = $zipPackage.Items().Item($file.Name).Size
    while($zipPackage.Items().Item($file.Name) -Eq $null)
    {
        start-sleep -seconds 1
        write-host "." -nonewline
    }
}

Kịch bản đầy đủ như sau:

$VerbosePreferenceBak = $VerbosePreference
$VerbosePreference = "Continue"

add-PSSnapin SqlServerCmdletSnapin100

function BackupDB([string] $dbName, [string] $outDir) {
    Write-Host "Backup de la base :  $dbName"
    $script = "BACKUP DATABASE $dbName TO DISK = '$outDir\$dbName.bak' WITH FORMAT, COPY_ONLY;"

    Invoke-Sqlcmd -Query "$script" -ServerInstance "." -QueryTimeOut 600
    Write-Host "Ok !"
}

function Compress-ToZip {
    param([string]$zipfilename)

    Write-Host "Compression du dossier"

    if(-not (test-path($zipfilename)))  {
        set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
        (Get-ChildItem $zipfilename).IsReadOnly = $false   
    }

    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipfilename)

    foreach($file in $input) {
        $zipPackage.CopyHere($file.FullName)    
        $size = $zipPackage.Items().Item($file.Name).Size
        while($zipPackage.Items().Item($file.Name) -Eq $null)
        {
            start-sleep -seconds 1
            write-host "." -nonewline
        }
        write-host "."
    }      
}


$targetDir = "E:\Backup SQL"
$date = Get-Date -format "yyyy-MM-dd"
$newDir = New-Item -ItemType Directory "$targetDir\$date\sql" -Force

BackupDB  "DB1" "$newDir"
BackupDB  "DB2" "$newDir"
BackupDB  "DB3" "$newDir"
BackupDB  "DB4" "$newDir"

Get-ChildItem "$newDir" | Compress-ToZip "$targetDir\$date\sql_$date.zip"

remove-item $newDir -Force -Confirm:$false -Recurse

$VerbosePreference = $VerbosePreferenceBak

Làm thế nào bạn có thể sử dụng nó trên VB?
MacGyver

@Leandro: ý bạn là tập lệnh VB? Vì cả PowerShell và VBScript đều là ngôn ngữ kịch bản, có thể hoạt động với các đối tượng COM, bạn sẽ có thể sao chép hành vi ở đây mà không gặp nhiều khó khăn
Steve B

1

Bởi vì nó hoạt động tốt khi bạn tạm dừng thủ công, đây là một hack tạm thời mà bạn có thể sử dụng cho đến khi tìm thấy giải pháp "đúng". Nói chung, sử dụng "độ trễ" và "bộ hẹn giờ" như thế này KHÔNG phải là điều bạn sẽ làm cho nhiệm vụ quan trọng. Điều đó nói rằng, cho đến khi một câu trả lời tốt hơn được tìm thấy, bạn có thể làm điều này và xem nếu nó hoạt động:

  • Thực hiện quy trình thủ công một vài lần và THỜI GIAN mất bao lâu trong vài giây để quá trình zip hoàn thành. Nếu kích thước cơ sở dữ liệu nói chung là giống nhau mỗi ngày thì thời gian cần thiết để hoàn thành có thể sẽ trung bình vào khoảng thời gian đó.

  • Giả sử bạn nhận được trung bình 60 giây trong các bài kiểm tra thủ công của mình. Hãy thận trọng và nhân nó lên gấp 4 lần vì nó có thể sẽ không mất nhiều thời gian hơn 4 lần so với bình thường vào những ngày "bình thường". Vì vậy, bây giờ bạn có 240 giây (60 giây trung bình 4 lần).

  • Vì vậy, bây giờ, thay vì có mã "nhấn phím bất kỳ để tiếp tục" trong đó, hãy thay thế bằng mã XÓA trong mã để có đoạn script chờ một chút để chờ mã zip kết thúc. Điều này đòi hỏi một số điều chỉnh và đoán về thời gian và không phải là một cách tiếp cận tốt. Nhưng trong một nhúm ...

  • Dù sao, nếu bạn muốn thử nó, hãy đổi mã thành:

Nếu sử dụng PowerShell V1:

foreach($file in $input)
{
  $zipPackage.CopyHere($file.FullName)       
}

[System.Threading.Thread]::Sleep(240000)

Nếu sử dụng PowerShell V2, hãy sử dụng lệnh ghép ngắn Ngủ:

foreach($file in $input)
{
   $zipPackage.CopyHere($file.FullName)       
}

Start-Sleep -Second 240

Để xử lý thời gian trong V1, nó sử dụng mili giây. (Vậy 10 giây = 10000)

Để gây rối với thời gian trong V2, nó sử dụng giây. (240 = 240 giây)

Tôi sẽ không bao giờ sử dụng điều này trong sản xuất nhưng nếu nó không phải là vấn đề lớn, và nó chứng minh rằng nó chỉ hoạt động tốt 99% thời gian, nó có thể đủ tốt.


Cuối cùng tôi đã tìm ra giải pháp. Tôi đánh giá cao sự giúp đỡ của bạn dù sao. Thx
Steve B
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.