Я пытаюсь создать свой собственный скрипт для проверки некоторых служб Windows (состояние и режим запуска), и я столкнулся с проблемой в IF... Например, даже если служба «Работает», она никогда не запустит код внутри ЕСЛИ...

Позвольте мне поделиться своим кодом ниже (я новичок в powershell, так что будьте осторожны xD)

Для информации, я буду делать больше действий внутри IF и ELSE, это просто для примера.

# import computers list, 1 by line
$Computers = get-content .\computers.txt

# define variable of services we want to check
$ServiceNetbios = "netbt"

# define variable to ask credentials
$Cred = Get-Credential

# declare Function to open a session a remote computer
Function EndPSS { Get-PSSession | Remove-PSSession }

EndPSS

########################################################
#                   BEGINNING OF SCRIPT                #
#                         by xxx                       #
#                       2022-02-03                     #
########################################################


# loop for each computer imported from the file
foreach ($computer in $computers) {
    
    # show name of computer in progress
    $computer

    # connect remotely to the computer
    $session = New-PSSession -ComputerName $computer -Credential $Cred

    # check Netbios service
    $StatusServiceNetbios = Invoke-Command -Session $session -ScriptBlock { Get-Service -Name $Using:ServiceNetbios | select -property * }
    
    # Check Netbios service started or not
    write-host $StatusServiceNetbios.Status
    
    if ($StatusServiceNetbios.Status -eq 'Running')
        {
           Write-host "IF Running"
        }
    else
    {
        write-host "IF NOT Running"
    }
    
EndPSS

}

И что возвращает мой скрипт:

computername
Running           (<= the variable $StatusServiceNetbios.Status )
IF NOT Running    (<= the ELSE action)

Заранее спасибо за вашу помощь, это сводит меня с ума и, может быть, это очень просто...

3
SebR 3 Фев 2022 в 18:02
Он никогда не запускает ваш "IF Running"? Помимо того, что на самом деле не требуется Invoke-Command, поскольку Get-Service поддерживает удаленные компьютеры, я не понимаю, почему это не сработает.
 – 
Abraham Zinala
3 Фев 2022 в 18:08
Нет, никогда :( Я использовал команду invoke для указания учетных данных, скрипт будет использоваться разными людьми, я не хочу хранить учетные данные внутри
 – 
SebR
3 Фев 2022 в 18:11
А, понятно. Хорошо, он запускает ваш блок else?
 – 
Abraham Zinala
3 Фев 2022 в 18:15
Ваш код выглядит нормально.. вы можете попробовать вернуть (Get-Service -Name $Using:ServiceNetbios).Status из Invoke-Command, а затем условие if($StatusServiceNetbios -eq 'Running')
 – 
Santiago Squarzon
3 Фев 2022 в 18:19
Да, это видно по строчке "IF NOT Running"
 – 
SebR
3 Фев 2022 в 18:21

2 ответа

Лучший ответ

Вероятно, это связано с тем, как powershell создает сервисные объекты — у (Get-Service netbt).Status есть дочернее свойство с именем Value:

$StatusServiceNetbios.Status

Value  
-----  
Running

# so Status is never -eq to 'Running':
$StatusServiceNetbios.Status -eq 'Running'
False

# use the Value property in your If statement instead:
$StatusServiceNetbios.Status.Value -eq 'Running'
True
2
Cpt.Whale 3 Фев 2022 в 18:25
Спасибо !!! Это оно !
 – 
SebR
3 Фев 2022 в 18:29
Спасибо всем, это был мой первый вопрос здесь, и ответ через минуту xD !
 – 
SebR
3 Фев 2022 в 18:31

Чтобы дополнить полезный ответ Cpt.Whale, это, вероятно, вызвано сериализацией и десериализацией, выполненной Invoke-Command :

using namespace System.Management.Automation
$service = Get-Service netbt
$service.Status -eq 'Running' # True
$afterInvokeCmd = [PSSerializer]::Deserialize(([PSSerializer]::Serialize($service)))
$afterInvokeCmd.Status -eq 'Running' # False
$afterInvokeCmd.Status.Value -eq 'Running' # True

ИЗМЕНИТЬ

Чтобы придать контекст моему ответу, это хорошая цитата из about_Remote_Output, которые могут лучше объяснить, почему и что происходит:

Поскольку большинство активных объектов Microsoft .NET Framework (например, объекты, возвращаемые командлетами PowerShell) не могут быть переданы по сети, активные объекты "сериализуются". Другими словами, живые объекты преобразуются в XML-представления объекта и его свойств. Затем сериализованный объект на основе XML передается по сети.

На локальном компьютере PowerShell получает сериализованный объект на основе XML и "десериализует" его, преобразуя объект на основе XML в стандартный объект .NET Framework.

Однако десериализованный объект не является живым объектом. Это моментальный снимок объекта на момент его сериализации, включающий свойства, но не методы.

3
Santiago Squarzon 3 Фев 2022 в 19:44
Ой, ты говоришь со мной по-китайски (без обид на Китай, лол) я не знаю "сериализация и десериализация" я посмотрю, спасибо
 – 
SebR
3 Фев 2022 в 18:39
1
Проще говоря, когда Invoke-Command переносит объект из удаленного сеанса в ваш локальный сеанс, он выполняет процесс сериализации объекта(ов), а затем десериализации это/они (это то, что делает PSSerializer)
 – 
Santiago Squarzon
3 Фев 2022 в 18:47
Я добавил цитату из официальных документов, которая может помочь вам лучше понять, что происходит.
 – 
Santiago Squarzon
3 Фев 2022 в 19:45