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文件的全部内容减去数据库的实际名称。该脚本的目标是备份一组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:当我添加您的手动测试时,它实际上按预期方式工作
Steve B

Answers:


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 2012年

@Leandro:您的意思是VB脚本吗?由于PowerShell和VBScript都是脚本语言,能够使用COM对象,因此您应该能够在这里复制行为而没有太多困难
Steve B

1

因为当您手动将其暂停时它可以正常工作,所以在找到“正确”的解决方案之前,您可以使用此临时hack。通常,像这样使用“延迟”和“计时器”并不是您要执行的关键任务。也就是说,在找到更好的答案之前,您可以执行此操作并查看它是否有效:

  • 手动执行几次该过程,然后再按TIME(时间)通常需要几秒钟才能完成压缩过程。如果数据库大小通常每天都是相同的,那么完成该数据库所花费的时间可能平均大约是同一时间。

  • 假设您的手动测试时间平均为60秒。保守一点,将其乘以4左右,因为在“正常”的日子里,它花费的时间可能不会比平时长4倍。因此,现在您有了240秒(平均60秒乘以4)。

  • 因此,就目前而言,与其在其中具有“按任意键继续”的代码,不如将其替换为代码中的DELAY,以使脚本挂出一点以等待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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.