Em um script do PowerShell, desejo compactar uma pasta antes de excluí-la. Executo o seguinte (não me lembro onde encontrei o trecho):
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)
}
}
Na verdade, esse trecho compacta a pasta, mas de maneira assíncrona. De fato, o método CopyHere dos objetos Shell.Application inicia a compactação e não espera sua conclusão. As próximas instruções dos meus scripts são uma bagunça (como o processo do arquivo zip não foi concluído).
Alguma sugestão? Se possível, eu gostaria de evitar adicionar arquivos executáveis e permanecer com os recursos puros do Windows.
[edit] conteúdo completo do meu arquivo PS1 menos o nome real do banco de dados. O objetivo do script é fazer backup de um conjunto de SQL db e compactar os backups em um único pacote em uma pasta chamada com a data atual:
$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
fonte
Write-Host "Press any key to continue ..."
Linha2:$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Respostas:
Finalmente encontrei uma maneira limpa, brincando com as propriedades dos objetos com. Especialmente, o seguinte snippet pode testar se o arquivo está presente no arquivo zip:
O script completo é o seguinte:
fonte
Como funcionou bem quando você o pausou manualmente, eis um hack temporário que você pode usar até que a solução "correta" seja encontrada. Geralmente, usar "atrasos" e "temporizadores" como esse NÃO é o que você faria para tarefas críticas. Dito isto, até encontrar uma resposta melhor, você pode fazer isso e ver se funciona:
Execute o processo manualmente algumas vezes e TIME quanto tempo, em segundos, geralmente leva o processo zip para concluir. Se o tamanho do banco de dados geralmente é o mesmo todos os dias, o tempo que leva para terminar provavelmente será medido na mesma hora.
Digamos que você consiga uma média de 60 segundos em seus testes manuais. Seja conservador e multiplique-o por 4 ou mais, pois provavelmente não levará quatro vezes mais que o normal em dias "normais". Então agora você tem 240 segundos (média de 60 segundos 4).
Portanto, por enquanto, em vez de ter o código "pressione qualquer tecla para continuar", substitua-o por um ATRASO no código para deixar o script apenas um pouco para esperar um pouco o zip terminar. Isso requer alguns ajustes e adivinhações nos horários e não é uma boa abordagem. Mas em uma pitada ...
De qualquer forma, se você quiser experimentá-lo, altere o código para:
Se você estiver usando o PowerShell V1:
Se você estiver usando o PowerShell V2, use o cmdlet Sleep:
Para mexer com os tempos na V1, ele usa milissegundos. (Então, 10 segundos = 10000)
Para mexer com os tempos na V2, ele usa segundos. (240 = 240 segundos)
Eu nunca usaria isso na produção, mas se não for tão grande assim, e provar funcionar bem 99% do tempo, pode ser bom o suficiente.
fonte