#powershell
#powershell
Вопрос:
У меня есть скрипт, который проверяет, есть ли на диске определенное количество свободного места. Если нет, появится всплывающее окно с запросом «да» или «нет». Если да, то для сигнала тревоги устанавливается значение 1, а затем запускается другой сценарий, который удаляет файлы из папки. Моя проблема в том, что, похоже, он удаляет в два раза больше числа, указанного в скрипте. Основной сценарий:
$limit_low = 0.1 # låg gräns 10%
$DiskD = Get-PSDrive D | Select-Object Used,Free | Write-Output
$DiskD_use = [math]::Round(($DiskD.Free / ($DiskD.Used $DiskD.Free)),2)
if( $DiskD_use -le $limit_low ) {
Write-Host "RDS-server har för lite utrymme på disk D $diskD_use < $limit_low" -ForegroundColor Red -BackgroundColor Yellow
$ButtonType = 4
$Timeout = 60
$Confirmation = New-Object -ComObject wscript.shell
$ConfirmationAnswer = $Confirmation.popup("Clear disk space?",$Timeout,"No space",$ButtonType)
If( $ConfirmationAnswer -eq 6 ) {
Write-Host "Kör script Diskspace.ps1 under P:backupscripts"
amp; c:dynamicsappJDSend.exe "/UDP /LOG:c:dynamicsappFixskick.log /TAG:Lunsc2:K_PROCESS_LARM_DISKUTRYMME "1""
amp; P:BackupScriptsDelete_archives_test.ps1 # here i call the other script
} else {
Write-Host "Gör ingenting"
amp; c:dynamicsappJDSend.exe "/UDP /LOG:c:dynamicsappFixskick.log /TAG:Lunsc2:K_PROCESS_LARM_DISKUTRYMME "0""
}
}
Другой сценарий:
# List all txt-files in directory, sort them och select the first 10, then delete
Get-ChildItem -Path c:temp -File Archive*.txt | Sort-Object | Select-Object -First 10 | Remove-Item -Force
Приветствия
Редактировать
Поэтому было бы достаточно заключить первый оператор следующим образом:
(Get-ChildItem -Path c:temp -File Archive*.txt) | Sort-Object | Select-Object -First 10 | Remove-Item -Force
?? Забавно, что я попытался воспроизвести это сегодня дома без какого-либо эффекта. Отсюда работает так, как задумано, даже без скобок.
Кроме того, я совершенно не осведомлен о том, как использовать foreach
statement, поскольку он не передает ублюдка 🙂
foreach ($file in $filepath) {$file} | Sort-Object | Select-Object -First 10 | Remove-Item -Force
Попытался поместить сортировку и выбрать часть в {}
тоже, но ничего хорошего из этого не вышло. Поскольку я застрял в трубе и не понимаю foreach
логики.
Комментарии:
1. Загрузите procmon из Sysinternals (Microsoft), запустите его от имени администратора и выполните свой сценарий. Остановите procmon от сбора информации (может получить очень много за очень короткое время!) и фильтруйте файлы / ваш скрипт / папку или что-то еще, чтобы убедиться, что ваш скрипт вызывается только один раз и что только 10 файлов удалены (или нет).
2. итак, ваш 2-й сценарий удаляет 20 файлов вместо 10? я не знаю, почему он это делает… но бывают случаи, когда использование
G-CI
для подачи конвейера может привести к повторному прочтению списка. я бы заключилG-CI
вызов в начале вашего конвейера в скобки, чтобы заставить его читать все элементы сразу .3. Итак, проблема здесь только в
Delete_archives_test.ps1
? Что произойдет, если вы запустите второй сценарий сам по себе? Перед его запуском попробуйте изменить его на использованиеRemove-Item -Force -Verbose
вместо. Это покажет вам, какие именно файлы были удалены. Или вы можете использовать-WhatIf
, если на самом деле ничего не хотите удалять.4. @zett42 — подумайте о том, что делает конвейер … он берет ЧТО-то ОДНО, выполняет с ним какие-то действия, а затем передает это на следующий этап. в случае
Get-ChildItem
это означает, что он может повторно прочитать тот же файл, когда что-то изменяет файл. заключая вызов в скобки, вы заставляетеG-CI
захватывать все файлы сразу… а ЗАТЕМ передайте их в конвейер. возможно, вы видите свое «делает это дважды», потому что вы меняете список файлов в процессе использования списка файлов.5. @Theo — готово! дайте мне знать, если он нуждается в доработке. [ усмешка ]
Ответ №1:
похоже, ваша проблема вызвана тем, как работает ваш конвейер. [усмешка]
подумайте о том, что он делает…
- прочитайте ОДИН элемент fileinfo
- отправьте его в конвейер
- изменение / добавление файла
- продолжайте конвейер
этот 3-й шаг приведет к изменению списка файлов… и может привести к повторному чтению файла ИЛИ к каким-либо другим изменениям в списке файлов для работы.
на ум приходят два решения…
- оберните
Get-ChildItem
вызов в скобки
, которые заставят одно чтение списка перед отправкой чего-либо в конвейер… и это будет игнорировать любые изменения, вызванные более поздними этапами конвейера. - используйте
foreach
цикл
, который будет считывать весь список, а затем выполнять итерацию по списку по одному элементу за раз.
преимущество 2-го решения также заключается в том, что его легче отлаживать, поскольку значение вашего current item
значения изменяется только при явном изменении. current pipeline item
изменения на каждом этапе конвейера… и это легко забыть. [усмешка]