Войти

Показать полную графическую версию : разобраться в выводе условного оператора


lcnet
01-07-2021, 13:01
Приветствую!
Хочу, чтобы цикл завершился, если обе (количество не важно, если все) службы остановлены
Может кто подсказать, почему такая конструкция не работает?


$status = 'Stopped'
[array]$srv = 'dwmrcs', 'FoxitReaderUpdateService'

Stop-Service -Name $srv

while ($true){
if ($status -eq (Get-Service -Name $srv).Status){
Write-Host 'Служба остановлена'
sleep 5
break
}
}


Обе службы остановлены...

Тут, наверное, надо понять, почему ($status -eq (Get-Service -Name $srv).Status) выдает False.
Я не совсем понимаю...

Elven
01-07-2021, 13:42
емнип break будет выводить из текущей итерации, на цикл он никак не влияет. а т.к. это while ($true), то цикл и продолжит выполняться.
($status -eq (Get-Service -Name $srv).Status) выдает False потому, что сравнивается строка с массивом. можно попробовать опрашивать каждый из элементов массива, только не руками, конечно проверки добавлять, а в цикле. их в пошике есть и кроме while. я бы использовал в данном случае пайп на foreach, ну или (вдруг) for с нуля до < $srv.length.
можно, конечно, и while, и do until - как фантазия подскажет, но всё же условия выхода из цикла должно быть оговорено в самом цикле, а различные искусственные выбивания из оного - есть неправильно и весьма нехорошо. Скрипты и так очень часто по сути своей костыли, не нужно костыли подпирать дополнительными костылями.
и еще один пункт, остановку сервиса лучше тоже запихать в цикл, а то он будет бесконечно пытаться проверить остановился ли сервис, который попытался остановиться один раз, у него не получилось и всё (да и то я не уверен, что в stop-Service можно скармливать массив, команда-то пройдет, а всем ли сервисам будет отдан приказ на остановку - вилами по воде).

и последнее, но не по значению. Почему службы останавливаются скриптом, а не групповыми политиками? Это было бы и проще и эффективнее.

Pavel Nagaev
01-07-2021, 13:52
$status = 'Stopped'
[array]$srv = 'Spooler', 'MSExchangeHM'

Stop-Service -Name $srv

while (((Get-Service -Name $srv)|Where-Object {$PSItem.Status -ne "Stopped"})){

sleep 5
}

cls
write-host "finish" -ForegroundColor Green

По вашему коду.
1. while ($true) и выход по break, это считается плохой практикой, т.к. цикл может продолжаться вечно, если есть условие выхода из цикла, то надо его в условия и ставить.
2. ($status -eq (Get-Service -Name $srv).Status) вы[B] сравниваете строку с массивом, обычно в левой части условия используется вычисляемое значение, а в правой статическое значение, хотя это больше дело привычки. Поэтому True и не будет.

lcnet
01-07-2021, 14:25
Pavel Nagaev, Спасибо! Я хотел поставить условие в цикл, но что-то меня смутил и я решил сделать условие внутри.

Elven, Спасибо! я Решил, что раз я вызываю свойство объекта, его можно сравнить со строкой, видно ошибался... Это моя "фантазия" для одного ПК, в определенный момент времени (незапланированный), по этому и не через ГПО.
Службы по факту другие и действия тоже.

greg zakharov
01-07-2021, 18:08
Службы по факту другие и действия тоже.Да и цикл, видимо, был женский...
По-хорошему, опрос пары-тройки сервисов в цикле - ересь. Прочитайте внимательно man Get-Service, раздел параметры.

Sham
01-07-2021, 19:58
Строку с массивом сравнивать можно (https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-arrays?view=powershell-7#-eq-and--ne). Предлагают через -not -ne (https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-arrays?view=powershell-7#all--eq), типа if (-not ((Get-Service -Name $srv).Status -ne $status)) или можно через Array.TrueForAll (https://docs.microsoft.com/en-us/dotnet/api/system.array.trueforall?view=net-5.0) с делегатом [array]::TrueForAll([String[]](Get-Service -Name $srv).Status, [Predicate[String]]{param($str) $str -eq $status})

greg zakharov
01-07-2021, 21:51
Строку с массивом сравнивать можно. Предлагают через -not -ne, типа
if (-not ((Get-Service -Name $srv).Status -ne $status))
или можно через Array.TrueForAll с делегатом
[array]::TrueForAll([String[]](Get-Service -Name $srv).Status, [Predicate[String]]{param($str) $str -eq $status})Для чего оверинжениринг?
(Get-Service service1, service2).Status.ForEach{$_ -eq 'stopped'}

Sham
02-07-2021, 00:30
.ForEach{$_ -eq 'stopped'} »
1. PS 4.0+
2. там требуется булев, а не массив булей. Непустой массив всегда кастуется к true.

greg zakharov
02-07-2021, 07:41
Sham, 1. И что? 2. Метод TrueForAll, если вы не в курсе, также выводит логический тип для всех значений, итогом чего становится результат их объединения согласно правилам булевой математики.

Sham
02-07-2021, 22:29
greg zakharov, если мы имеем коэрсию array->bool в if(), то она не по булевым правилам. [bool]@($false, $false) это $true

greg zakharov
03-07-2021, 07:32
Sham, ещё раз (с чувством и расстановкой). Приведение непустого объекта к булеву типу даёт $true. Однако речь была именно о значениях в массиве, а не самом массиве. Иными словами [Boolean]@($false, $false) можно рассматривать как проверку на пустоту, но не эквант булевой математики. Не нужно переиначивать сказанное.




© OSzone.net 2001-2012