Защитите цикл foreach когда пустой список

Идите вперед и создайте себя новый пользователь. Просто удостоверьтесь, что поместили того пользователя в "администраторскую" группу и тест, входящий в систему как тот пользователь, прежде чем Вы сдуете пользователя 'человечности'.

Я не нашел причины сохранить пользователя человечности, и она кажется мне потенциальной дырой в системе безопасности.

Возможно, что Вы отключаете себя от других инструментов AWS как Облачные Часы или что-то еще, что ожидает, что AWS sitekey позволит Вам входить в поле, но я не использую те сервисы.

10
задан 13 December 2012 в 12:05
4 ответа

В Powershell 3 оператор foreach не выполняет итерацию по $ null , и проблема, описанная OP, больше не возникает.

Из

1146254] Блог Windows PowerShell сообщение Новые возможности языка V3 :

Оператор ForEach не выполняет итерацию по $ null

В PowerShell V2.0 люди часто удивлялись:

PS > foreach ($ i in $ null) {'got here'}

got here

Эта ситуация часто возникает, когда командлет не возвращает никаких объектов. В PowerShell V3.0 вам не нужно добавлять оператор if, чтобы избежать итерации по $ null. Мы позаботимся об этом за вас.

Для PowerShell $ PSVersionTable.PSVersion.Major -le 2 см. Следующий исходный ответ.


У вас есть два варианта, я в основном использую второй.

Проверьте $ backups , чтобы не было $ null . Простой If в цикле может проверять не $ null

if ( $backups -ne $null ) {

    foreach ($file in $backups) {
        Remove-Item $file.FullName;
    }

}

Или

Инициализировать $ backups как нулевой массив. Это позволяет избежать двусмысленности проблемы «повторения пустого массива» , о которой вы спрашивали в своем последнем вопросе .

$backups = @()
# $backups is now a null value array

foreach ( $file in $backups ) {
    # this is not reached.
    Remove-Item $file.FullName
}

Извините, я не предоставил пример интеграции вашего кода. Обратите внимание на командлет Get-ChildItem , заключенный в массив. Это также будет работать с функциями, которые могут возвращать $ null .

$backups = @(
    Get-ChildItem -Path $Backuppath |
        Where-Object { ($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like "backup*") }
)

foreach ($file in $backups) {
    Remove-Item $file.FullName
}
19
ответ дан 2 December 2019 в 22:01

Я разработал решение, выполнив запрос дважды, один раз для получения файлов и один раз для подсчитайте количество файлов, применив get-ChilItem для возврата массива (преобразование $ backups как массива после факта, похоже, не работает).
По крайней мере, он работает так, как ожидалось (производительность не должна быть такой проблемой, поскольку никогда не будет больше дюжины файлов), если кто-то знает решение для одного запроса, опубликуйте его.

$count = @(Get-ChildItem -Path $zipFilepath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")}).count;

if ($count -gt 0)
{
    $backups = Get-ChildItem -Path $zipFilepath | 
                Where-Object {($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and (-not $_.PSIsContainer) -and ($_.Name -like $partial + "*")};

    foreach ($file in $backups)
    {
        Remove-Item $file.FullName;
    }
}
1
ответ дан 2 December 2019 в 22:01

Используйте следующее, чтобы оценить, есть ли в массиве какое-либо содержимое:

if($backups.count -gt 0) { echo "Array has contents" } else { echo "Array is empty" }

Если переменная не существует, Powershell просто оценит ее как ложную, поэтому нет необходимости проверять, существует ли она.

0
ответ дан 2 December 2019 в 22:01

Я знаю, что это старый пост, но хотел бы отметить, что командлет ForEach-Object не страдает той же проблемой, что и использование ключевого слова ForEach. Таким образом, вы можете передать результаты DIR в ForEach и просто сослаться на файл с помощью $ _, например:

$backups | ForEach{ Remove-Item $_ }

Фактически вы можете перенаправить саму команду Dir через конвейер и избежать даже назначения переменной, например:

Get-ChildItem -Path $Backuppath | 
Where-Object {
             ($_.lastwritetime -lt (Get-Date).addDays(-$DaysKeep)) -and `
             (-not $_.PSIsContainer) -and ($_.Name -like "backup*")
             } |
ForEach{ Remove-Item $_ }

Я добавил разрывы строк для удобства чтения.

Я понимаю, что некоторым людям нравится ForEach / In для удобства чтения. Иногда ForEach-object может показаться непростым, особенно если вы выполняете вложение, так как становится трудно следовать ссылке $ _. Во всяком случае, для такой небольшой операции он идеален. Многие люди также утверждают, что это быстрее, но я обнаружил, что это ненамного.

2
ответ дан 2 December 2019 в 22:01

Теги

Похожие вопросы