В сценарии 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)
}
}
Этот фрагмент фактически сжимает папку, но асинхронно. Фактически метод CopyHere объектов Shell.Application запускает сжатие и не ожидает его завершения. Следующие операторы моих скриптов затем запутываются (поскольку процесс 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
backup
zip
database
powershell
Стив Б
источник
источник
Write-Host "Press any key to continue ..."
Строка2:$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Ответы:
Я наконец нашел чистый способ, поиграв со свойствами com-объектов. В частности, следующий фрагмент может проверить, присутствует ли файл в zip-файле:
Полный скрипт выглядит следующим образом:
источник
Поскольку он работал нормально, когда вы вручную приостанавливали его, вот временный хак, который вы можете использовать, пока не найдете «правильное» решение. Обычно использование таких «задержек» и «таймеров» НЕ является тем, что вы бы сделали для критически важных задач. Тем не менее, пока не будет найден лучший ответ, вы можете сделать это и посмотреть, работает ли он:
Выполните процесс вручную несколько раз и ВРЕМЯ, сколько времени в секундах обычно занимает процесс zip для завершения. Если размер базы данных, как правило, один и тот же каждый день, то время, необходимое для ее завершения, вероятно, будет примерно таким же.
Допустим, вы получаете в среднем 60 секунд в ваших ручных тестах. Будьте консервативны и умножьте это на 4 или около того, так как это не займет в 4 раза больше времени, чем обычно в «нормальные» дни. Так что теперь у вас есть 240 секунд (60 секунд в среднем 4 раза).
Так что сейчас вместо того, чтобы использовать код «нажмите любую клавишу для продолжения», замените его на DELAY в коде, чтобы скрипт просто зависал немного, ожидая окончания работы zip. Это требует некоторой подстройки и догадок по времени и не является хорошим подходом. Но в крайнем случае ...
В любом случае, если вы хотите попробовать, измените код на:
При использовании PowerShell V1:
При использовании PowerShell V2 используйте вместо этого командлет Sleep:
Чтобы возиться со временем в V1 он использует миллисекунды. (Итак 10 секунд = 10000)
Чтобы возиться со временем в V2 он использует секунды. (240 = 240 секунд)
Я бы никогда не использовал это в производстве, но если это не так уж важно, и в 99% случаев это работает нормально, это может быть достаточно.
источник