Fichier zip PowerShell de manière synchrone

Dans un script PowerShell, je veux supprimer un dossier avant de supprimer le dossier. Je cours ce qui suit (je ne me souviens pas où j'ai trouvé l'extrait):

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

Cet extrait compressé le dossier, mais d'une manière asynchrone. En fait, la méthode CopyHere des objets Shell.Application démarre la compression et n'attend pas son achèvement. Les prochaines déclarations de mes scripts sont alors désordonnées (au fur et à mesure que le processus de fichier zip n'est pas terminé).

Aucune suggestion? Si possible, j'aimerais éviter d'ajouter des fichiers exécutables et de rester sur des fonctionnalités Windows pur.

[Modifier] contenu complet de mon fichier PS1 moins le nom réel du DB. Le but du script est de sauvegarder un ensemble de SQL db, puis de sauvegarder les sauvegardes dans un seul package dans un dossier nommé avec la date actuelle:

 $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 

    J'ai finalement trouvé un moyen propre, en jouant avec les propriétés des objets com. Surtout, l'extrait suivant peut tester si le fichier est présent dans le fichier 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 } } 

    Le script complet est le suivant:

     $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 

    Parce que cela a fonctionné bien lorsque vous l'avez fait un arrêt manuel, voici un hack temporaire que vous pourriez utiliser jusqu'à ce que la solution «correcte» soit trouvée. Généralement, l'utilisation de «retards» et de «temporisateurs» comme celui-ci NE FAIT PAS ce que vous feriez pour des tâches critiques. Cela dit, jusqu'à ce qu'une meilleure réponse soit trouvée, vous pouvez le faire et voir si cela fonctionne:

    • Effectuez le processus manuellement à plusieurs reprises et TIME pendant combien de temps en secondes il prend généralement le processus zip pour terminer. Si la taille de la base de données est généralement la même tous les jours, le temps nécessaire pour terminer sera probablement le même temps.

    • Disons que vous avez une moyenne de 60 secondes dans vos tests manuels. Soyez prudent et multipliez-le par 4, car il ne faudra probablement pas 4 fois plus longtemps que d'habitude sur les jours «normaux». Donc maintenant, vous avez 240 secondes (60 secondes de temps moyen 4).

    • Donc, maintenant, au lieu d'avoir le code "appuyez sur n'importe quelle touche pour continuer", remplacez-le par un DELAY dans le code pour que le script passe un peu d'attente pour que le zip soit terminé. Cela nécessite des ajustements et des devinettes sur les horaires et n'est pas une bonne approche. Mais dans un pincement …

    • Quoi qu'il en soit, si vous voulez l'essayer, modifiez le code pour:

    Si vous utilisez PowerShell V1:

     foreach($file in $input) { $zipPackage.CopyHere($file.FullName) } [System.Threading.Thread]::Sleep(240000) 

    Si vous utilisez PowerShell V2, utilisez plutôt la cmdlet Sleep:

     foreach($file in $input) { $zipPackage.CopyHere($file.FullName) } Start-Sleep -Second 240 

    Pour faire du mal aux temps dans V1, il utilise des millisecondes. (So ​​10 secondes = 10000)

    Pour gâcher des temps dans V2, il utilise des secondes. (240 = 240 secondes)

    Je n'utiliserais jamais cela dans la production, mais si ce n'est pas un gros problème, et cela s'avère très bien 99% du temps, il pourrait être suffisant.