ไฟล์ซิป PowerShell แบบซิงโครนัส


10

ในสคริปต์ PowerShell ฉันต้องการซิปโฟลเดอร์ก่อนที่จะลบโฟลเดอร์ ฉันเรียกใช้สิ่งต่อไปนี้ (ฉันจำไม่ได้ว่าฉันพบข้อมูลโค้ดที่ใด):

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)

    }
}

ตัวอย่างนี้บีบอัดโฟลเดอร์จริงๆ แต่ในแบบอะซิงโครนัส อันที่จริงแล้ววิธี CopyHere ของวัตถุ Shell.Application เริ่มการบีบอัดและไม่รอให้เสร็จสมบูรณ์ ประโยคต่อไปของสคริปต์ของฉันก็จะเลอะ (เนื่องจากกระบวนการไฟล์ zip ยังไม่เสร็จสิ้น)

ข้อเสนอแนะใด ๆ หากเป็นไปได้ฉันต้องการหลีกเลี่ยงการเพิ่มไฟล์ที่ปฏิบัติการได้และใช้งานฟีเจอร์ Windows ล้วน ๆ

[แก้ไข] เนื้อหาทั้งหมดของไฟล์ PS1 ของฉันลบด้วยชื่อจริงของฐานข้อมูล เป้าหมายของสคริปต์คือการสำรองข้อมูลชุดของ SQL db จากนั้นทำการบีบอัดข้อมูลสำรองในแพ็คเกจเดียวในโฟลเดอร์ที่ชื่อด้วยวันที่ปัจจุบัน:

$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

เพียงเพื่อดูว่ามันทำงานได้หรือไม่ถ้ามันเป็นแบบซิงโครนัส: ถ้าคุณเพิ่มรหัสต่อไปนี้หลังจาก foreach ทำงานได้ตามที่คาดไว้ Line1: Write-Host "Press any key to continue ..." Line2:$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Kerry

และในระหว่างการทดสอบฉันเห็นได้ชัดว่าคุณจะไม่ "กดปุ่มใด ๆ เพื่อดำเนินการต่อ" จนกว่าคุณจะยืนยันด้วยตนเองว่ากระบวนการซิปเสร็จสิ้น
Kerry

@Kerry: ใช้งานได้จริงอย่างที่คาดไว้เมื่อฉันเพิ่มการทดสอบด้วยตนเองของคุณ
Steve B

คำตอบ:


5

ในที่สุดฉันก็พบวิธีที่สะอาดเล่นกับคุณสมบัติของวัตถุ com โดยเฉพาะอย่างยิ่งข้อมูลโค้ดต่อไปนี้สามารถทดสอบว่ามีไฟล์อยู่ในไฟล์ zip หรือไม่:

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

สคริปต์แบบเต็มมีดังต่อไปนี้:

$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 ได้อย่างไร?
MacGyver

@Leandro: คุณหมายถึง VB script หรือเปล่า ในฐานะที่เป็นทั้ง PowerShell และ VBScript เป็นภาษาสคริปต์สามารถทำงานกับวัตถุ COM คุณควรจะสามารถทำซ้ำพฤติกรรมที่นี่ได้โดยไม่ต้องลำบากมาก
Steve B

1

เนื่องจากมันทำงานได้ดีเมื่อคุณหยุดมันเองด้วยตนเองนี่คือแฮ็กชั่วคราวที่คุณอาจใช้งานได้จนกว่าจะพบโซลูชัน "ถูกต้อง" โดยทั่วไปการใช้ "ความล่าช้า" และ "ตัวจับเวลา" เช่นนี้ไม่ใช่สิ่งที่คุณจะทำเพื่อภารกิจที่สำคัญ ที่กล่าวว่าจนกว่าจะพบคำตอบที่ดีกว่าคุณสามารถทำสิ่งนี้และดูว่ามันใช้งานได้หรือไม่:

  • ทำกระบวนการด้วยตนเองสองสามครั้งและ TIME นานแค่ไหนในไม่กี่วินาทีโดยปกติแล้วกระบวนการ zip จะเสร็จสมบูรณ์ หากขนาดฐานข้อมูลโดยทั่วไปเท่ากันทุกวันเวลาที่ใช้ในการเสร็จสิ้นอาจจะเฉลี่ยในเวลาเดียวกัน

  • สมมติว่าคุณได้รับค่าเฉลี่ย 60 วินาทีในการทดสอบด้วยตนเอง ระมัดระวังและคูณด้วย 4 หรือมากกว่าเพราะจะไม่ใช้เวลานานกว่าปกติ 4 เท่าในวัน "ปกติ" ตอนนี้คุณมี 240 วินาที (เฉลี่ย 60 วินาทีคูณ 4)

  • ดังนั้นในตอนนี้แทนที่จะมีรหัส "กดปุ่มใด ๆ เพื่อดำเนินการต่อ" ในนั้นให้แทนที่ด้วย DELAY ในรหัสเพื่อให้สคริปต์แฮงเอาท์กันเล็กน้อยเพื่อรอให้ซิปเสร็จสิ้น ต้องมีการปรับแต่งและคาดเดาเวลาและไม่ใช่วิธีการที่ดี แต่ในไม่กี่นาที ...

  • อย่างไรก็ตามหากคุณต้องการลองเปลี่ยนรหัสเป็น:

หากใช้ PowerShell V1:

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

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

หากใช้ PowerShell V2 ให้ใช้ Sleep cmdlet แทน:

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

Start-Sleep -Second 240

หากต้องการยุ่งกับเวลาใน V1 จะใช้มิลลิวินาที (ดังนั้น 10 วินาที = 10,000)

หากต้องการยุ่งกับเวลาใน V2 จะใช้วินาที (240 = 240 วินาที)

ฉันจะไม่ใช้สิ่งนี้ในการผลิต แต่ถ้ามันไม่ใช่เรื่องใหญ่อะไรและมันพิสูจน์ได้ว่าทำงานได้ดีเพียง 99% ของเวลามันอาจจะดีพอ


ในที่สุดฉันก็พบทางออก ฉันขอขอบคุณสำหรับความช่วยเหลือของคุณ ขอบคุณ
Steve B
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.