In einem PowerShell-Skript möchte ich einen Ordner komprimieren, bevor ich den Ordner lösche. Ich führe Folgendes aus (ich erinnere mich nicht, wo ich das Snippet gefunden habe):
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)
}
}
Dieses Snippet komprimiert den Ordner tatsächlich, jedoch auf asynchrone Weise. Tatsächlich startet die CopyHere-Methode der Shell.Application-Objekte die Komprimierung und wartet nicht auf ihren Abschluss. Die nächsten Anweisungen meiner Skripte sind dann durcheinander (da der Zip-Datei-Prozess nicht abgeschlossen ist).
Irgendwelche Vorschläge? Wenn möglich, möchte ich das Hinzufügen ausführbarer Dateien vermeiden und mich auf reine Windows-Funktionen beschränken.
[Bearbeiten] Vollständiger Inhalt meiner PS1-Datei abzüglich des tatsächlichen Namens der Datenbank. Das Ziel des Skripts besteht darin, eine Reihe von SQL-Datenbanken zu sichern und dann die Sicherungen in einem einzelnen Paket in einem Ordner mit dem aktuellen Datum zu komprimieren:
$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
quelle
Write-Host "Press any key to continue ..."
Linie 2:$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Antworten:
Ich habe endlich einen sauberen Weg gefunden und mit den Eigenschaften der COM-Objekte gespielt. Insbesondere kann das folgende Snippet testen, ob die Datei in der Zip-Datei vorhanden ist:
Das vollständige Skript lautet wie folgt:
quelle
Da es gut funktioniert hat, als Sie es manuell angehalten haben, ist hier ein vorübergehender Hack, den Sie möglicherweise verwenden können, bis die "richtige" Lösung gefunden ist. Im Allgemeinen ist die Verwendung von "Verzögerungen" und "Timern" wie diesen NICHT das, was Sie für geschäftskritische Dinge tun würden. Das heißt, bis eine bessere Antwort gefunden wird, können Sie dies tun und sehen, ob es funktioniert:
Führen Sie den Vorgang einige Male manuell durch und geben Sie an, wie lange es in Sekunden dauert, bis der Zip-Vorgang abgeschlossen ist. Wenn die Datenbankgröße im Allgemeinen jeden Tag gleich ist, wird die durchschnittliche Zeit bis zur Fertigstellung wahrscheinlich ungefähr zur gleichen Zeit betragen.
Angenommen, Sie erhalten in Ihren manuellen Tests durchschnittlich 60 Sekunden. Seien Sie konservativ und multiplizieren Sie es mit 4 oder so, da es an "normalen" Tagen wahrscheinlich nicht 4-mal länger dauert als gewöhnlich. Jetzt haben Sie also 240 Sekunden (durchschnittlich 60 Sekunden mal 4).
Anstatt den Code "Drücken Sie eine beliebige Taste, um fortzufahren" dort zu haben, ersetzen Sie ihn vorerst durch eine VERZÖGERUNG im Code, damit das Skript nur eine Weile hängen bleibt, bis die Zip-Datei fertig ist. Dies erfordert einige Anpassungen und Schätzungen des Timings und ist kein guter Ansatz. Aber zur Not ...
Wenn Sie es versuchen möchten, ändern Sie den Code in:
Bei Verwendung von PowerShell V1:
Wenn Sie PowerShell V2 verwenden, verwenden Sie stattdessen das Cmdlet Sleep:
Um mit den Zeiten in V1 zu spielen, werden Millisekunden verwendet. (Also 10 Sekunden = 10000)
Um mit den Zeiten in V2 zu spielen, werden Sekunden benötigt. (240 = 240 Sekunden)
Ich würde dies niemals in der Produktion verwenden, aber wenn es keine so große Sache ist und es sich in 99% der Fälle als gut funktioniert, könnte es gut genug sein.
quelle