PowerShell zip 파일을 동 기적으로


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)

    }
}

이 스 니펫은 실제로 폴더를 압축하지만 비동기 방식으로 압축합니다. 실제로 Shell.Application 개체의 CopyHere 메서드는 압축을 시작하고 완료를 기다리지 않습니다. 스크립트의 다음 문장은 zip 파일 프로세스가 완료되지 않아 엉망이됩니다.

어떤 제안? 가능하다면 실행 파일을 추가하지 않고 순수한 Windows 기능을 유지하고 싶습니다.

내 PS1 파일의 전체 내용에서 DB의 실제 이름을 뺀 것입니다. 스크립트의 목표는 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

동기화 된 경우 woudl 작동하는지 확인하십시오. foreach 후에 다음 코드를 추가하면 예상대로 작동합니까? 1 호선 : Write-Host "Press any key to continue ..." 2 호선$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Kerry

그리고 테스트하는 동안 zip 프로세스가 완료되었음을 수동으로 확인할 때까지 "계속하려면 아무 키나 누르지 마십시오"라고 가정합니다.
Kerry

@Kerry : 실제로 나는 당신의 수동 테스트를 추가 할 때 예상대로 작동
스티브 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 스크립트를 의미합니까? PowerShell과 VBScript는 모두 스크립팅 언어이므로 COM 개체를 사용할 수 있으므로 많은 어려움없이 여기에서 동작을 복제 할 수 있어야합니다.
Steve B

1

수동으로 일시 중지했을 때 제대로 작동했기 때문에 "올바른"솔루션을 찾을 때까지 사용할 수있는 임시 해킹이 있습니다. 일반적으로 이와 같은 "지연"과 "타이머"를 사용하는 것은 미션 크리티컬 한 일을위한 것이 아닙니다. 더 나은 대답을 찾을 때까지 이렇게하면 작동하는지 확인할 수 있습니다.

  • 일반적으로 zip 프로세스를 완료하는 데 걸리는 시간 (초)은 수동으로 몇 번 및 TIME으로 프로세스를 수행하십시오. 데이터베이스 크기가 일반적으로 매일 같으면 완료하는 데 걸리는 시간은 아마도 거의 같은 시간입니다.

  • 수동 테스트에서 평균 60 초가 걸린다고 가정 해 봅시다. "일반적인"날에는 평소보다 4 배 더 오래 걸리지 않기 때문에 보수적이고 4를 곱하십시오. 이제 240 초 (평균 60 초에 4)가 있습니다.

  • 따라서 지금은 "계속하려면 아무 키나 누르십시오"코드를 사용하지 말고 코드에서 지연을 대체하여 zip이 완료 될 때까지 스크립트가 중단되도록합니다. 이것은 타이밍에 대한 약간의 조정과 추측이 필요하며 좋은 접근 방식이 아닙니다. 그러나 꼬집음에서 ...

  • 어쨌든 시도하고 싶다면 코드를 다음으로 변경하십시오.

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 초 = 10000)

V2에서 시간을 혼란스럽게하려면 초를 사용합니다. (240 = 240 초)

나는 이것을 프로덕션에서 결코 사용하지 않을 것이지만 그렇게 큰 일이 아니며 99 %의 시간 만 잘 작동한다면 충분할 것입니다.


마침내 해결책을 찾았습니다. 어쨌든 당신의 도움에 감사드립니다. Thx
Steve B
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.