PowerShell zip dosyası senkronize


10

Bir PowerShell betiğinde, klasörü silmeden önce bir klasörü sıkıştırmak istiyorum. Aşağıdakileri çalıştırıyorum (snippet'i nerede bulduğumu hatırlamıyorum):

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)

    }
}

Bu snippet aslında klasörü sıkıştırır, ancak eşzamansız bir şekilde. Aslında, Shell.Application nesnelerinin CopyHere yöntemi sıkıştırmayı başlatır ve tamamlanmasını beklemez. Betiklerimin sonraki ifadeleri daha sonra bozulur (zip dosyası işlemi tamamlanmadığından).

Herhangi bir öneri? Mümkünse yürütülebilir dosyalar eklemekten kaçınmak ve saf Windows özelliklerinde kalmak istiyorum.

[değiştir] PS1 dosyamın tam içeriği eksi DB'nin gerçek adı. Komut dosyasının amacı, bir dizi SQL db'yi yedeklemektir, ardından yedekleri geçerli tarihle adlandırılmış bir klasörde tek bir pakette ziplemektir:

$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

Sadece senkron olup olmadığını görmek için woudl olup olmadığını görmek için: Aşağıdaki kodu ekledikten sonra eklerseniz, beklendiği gibi çalışıyor mu? Satır1: Write-Host "Press any key to continue ..." Satır2:$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Kerry

Test sırasında, zip işleminin tamamlandığını manuel olarak onaylayana kadar "devam etmek için herhangi bir tuşa basmayacağınızı" varsayıyorum.
Kerry

@Kerry: Manuel testinizi eklediğimde aslında beklendiği gibi çalışıyor
Steve B

Yanıtlar:


5

Sonunda temiz bir yol buldum, com nesnelerin özellikleri ile oynuyor. Özellikle, aşağıdaki snippet, dosyanın zip dosyasında olup olmadığını test edebilir:

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
    }
}

Komut dosyasının tamamı şöyledir:

$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

VB'de nasıl kullanabilirsiniz?
MacGyver

@Leandro: VB senaryosu mu demek istediniz? Hem PowerShell hem de VBScript komut dosyası dili olduğundan, COM nesneleriyle çalışabildiğinden, burada davranışı çok zorlanmadan çoğaltabilmelisiniz
Steve B

1

Manuel olarak duraklattığınızda iyi çalıştığı için, "doğru" çözüm bulunana kadar kullanabileceğiniz geçici bir saldırı. Genellikle bu gibi "gecikmeler" ve "zamanlayıcılar" kullanarak kritik görevler için ne yapacağınız DEĞİLDİR. Bununla birlikte, daha iyi bir cevap bulunana kadar bunu yapabilir ve çalışıp çalışmadığını görebilirsiniz:

  • İşlemi birkaç kez manuel olarak yapın ve genellikle zip işleminin tamamlanması saniye cinsinden ne kadar sürer? Veritabanı boyutu genellikle her gün aynıysa, bitirmek için gereken süre muhtemelen aynı süre civarında olacaktır.

  • Manuel testlerinizde ortalama 60 saniye olduğunu varsayalım. Muhafazakar olun ve "normal" günlerde normalden 4 kat daha uzun sürmeyeceği için 4 ile çarpın. Şimdi 240 saniyeniz var (ortalama 60 saniye ortalama 4).

  • Şimdilik, "devam etmek için herhangi bir tuşa basın" kodunu kullanmak yerine, kodun zip'in bitmesini beklemesi için biraz takılması için koddaki bir GECİKME ile değiştirin. Bu, zamanlamalarda biraz ince ayar ve tahmin gerektirir ve iyi bir yaklaşım değildir. Ama bir tutam ...

  • Her neyse, denemek istiyorsanız kodu şu şekilde değiştirin:

PowerShell V1 kullanıyorsanız:

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

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

PowerShell V2 kullanıyorsanız, bunun yerine Uyku cmdlet'ini kullanın:

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

Start-Sleep -Second 240

V1'deki zamanları karıştırmak için milisaniye kullanır. (Yani 10 saniye = 10000)

V2'deki zamanlarla uğraşmak saniyeler kullanır. (240 = 240 saniye)

Bunu asla üretimde kullanmam, ancak bu kadar büyük bir anlaşma değilse ve zamanın% 99'unda iyi çalıştığını kanıtlarsa, yeterince iyi olabilir.


Sonunda çözümü buldum. Yine de yardımlarınız için teşekkür ederim. Teşekkürler
Steve B
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.