Powershell - Как мне вернуть имя приложения из цикла foreach, только если код состояния -ne 200?

Название говорит само за себя. Я возвращал выходные данные каждой итерации обоих приведенных ниже циклов foreach (см. Строки Write-Host и Write-Output), но приложение, использующее этот сценарий (Nagios), не может обрабатывать такой объем данных. Поэтому я хотел бы возвращать только 1 вывод за раз. Обычно «Все приложения в порядке» или «Приложение (а) не работает: затем перечислить приложения, не возвращающие код ответа 200». Я понятия не имею, как это сделать, поскольку заставить работать циклы foreach в первую очередь было для меня сложной задачей.

$ok = 0
$warning = 1
$critical = 2
$unknown = 3

$appPool = get-webapplication
$errorcode = 0
$time_errorcode = 0

foreach($a in $appPool) {

    $app = $a.Attributes[0].Value;
    $url = "http://localhost$app/apitest/index"
    $HTTP_Request = [System.Net.WebRequest]::Create($url)
    $HTTP_Response = try{ $HTTP_Request.GetResponse() }catch {$exceptionMessage = $_.Exception.Message
    $exceptionItem = $app}

    [int]$HTTP_Response.StatusCode -ne 200 
    $statuscode = [int]$HTTP_Response.StatusCode
    Write-Host "$app status code: $statuscode"
    if ($HTTP_Response.StatusCode.value__ -ne 200) {
        [int]$errorcode = 1
    }
}

foreach($t in $appPool){
    $app = $t.Attributes[0].Value;
    $url = "http://localhost$app/apitest/index"
    $output = "$PSScriptRoot\10meg.test"
    $start_time = Get-Date

    try {Invoke-WebRequest -Uri $url -OutFile $output} catch {
    $exceptionMessage = $_.Exception.Message
    $exceptionItem = $app
    Write-Output "$app error: $exceptionMessage"}
    Write-Output "$app Time taken: $((Get-Date).Subtract($start_time).milliSeconds) millisecond(s)"
    $timetaken = $((Get-Date).Subtract($start_time).milliSeconds)
    if ($timetaken.StatusCode.value__ -ge 500) {
        [int]$time_errorcode = 1
    }
}
#Uncomment for testing
#Write-Output $time_errorcode
#Write-Output $errorcode

if (($errorcode -eq 0 -and $time_errorcode -eq 0)){exit $ok}
if (($errorcode -eq 1 -and $time_errorcode -eq 0)){exit $critical}
if (($errorcode -eq 0 -and $time_errorcode -eq 1)){exit $warning}
if (($errorcode -eq 1 -and $time_errorcode -eq 1)){exit $critical}
else {exit $unknown}

Моим первым инстинктом было бы предложить использовать Where-Object. Я не уверен, где и как включить это в ваш пример. Проще говоря, сохраните все в массиве, а затем используйте Where-Object для проверки, чтобы определить, какой вывод отображать.

Clayton Lewis 16.10.2018 14:22
$timetaken.StatusCode.value__ -ge 500 - это явно опечатка. Также объясните, почему у вас петли 2. Кроме того, то, что вы спросили, банально, я могу помочь вам, если у меня будет больше информации.
marsze 16.10.2018 14:38

@marsze, это не опечатка. Этот раздел кода предназначен для проверки того, занимает ли загрузка приложения более 500 мс. Собственно поэтому и у меня 2 петли. 1, чтобы проверить код ответа, и секунду, чтобы проверить время загрузки. Какая дополнительная информация вам нужна?

RaptorPete 16.10.2018 16:17
$timetaken - это число (кстати, вы, вероятно, хотели использовать TotalMilliseconds) и не имеет свойства StatusCode. Вероятно, вы имели в виду: if (((Get-Date) - $start_time).TotalMilliseconds -gt 500)
marsze 16.10.2018 16:20

Хорошо, я попробую. Как насчет того, чтобы иметь возможность писать-выводить отдельные приложения, когда они ошибаются (или когда они достигают 500 во втором цикле)? Я хотел бы написать только те приложения, которые потерпели неудачу, а не все они, чтобы сохранить данные, о которых сообщается.

RaptorPete 16.10.2018 16:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
105
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это может вам помочь:

$list = @()
Foreach(x in y){
$item = @{}
If(x.error -eq 200){
$item.Name = x.Name
}
$obj = New-Object PSObject -Property $item
$list += $obj
}

Добавление этих частей оставит вам список имен приложений в переменной $list.

Похоже, у вас есть этот список, только если ошибка равна 200. Как мне вернуть имя приложения, если ошибка отличается от 200?

RaptorPete 16.10.2018 16:20

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

Tourius 16.10.2018 16:33
Ответ принят как подходящий

Вот мой подход. НЕПРОВЕРЕНО. Просто чтобы дать вам представление о работе.

$appPool = Get-WebApplication
$errorcode = 0
$time_errorcode = 0

# Using a hashset ensures every app is contained only once
$appsDown = New-Object "System.Collections.Generic.HashSet[string]"

foreach($a in $appPool) {
    $app = $a.Attributes[0].Value;
    $url = "http://localhost$app/apitest/index"

    ### Test response code ###

    $HTTP_Request = [System.Net.WebRequest]::Create($url)
    $HTTP_Response = $null
    try {
        $HTTP_Response = $HTTP_Request.GetResponse()
    } catch {
        # for test
        Write-Host $_
    }
    if ($null -eq $HTTP_Response -or [int]$HTTP_Response.StatusCode -ne 200 ) {
        [int]$errorcode = 1
        [void]$appsDown.Add($app)
    }

    ### Test response time ###

    $output = "$PSScriptRoot\10meg.test"
    $start_time = Get-Date
    $timetaken = -1
    try {
        Invoke-WebRequest -Uri $url -OutFile $output
        $timetaken = ((Get-Date) - $start_time).TotalMilliSeconds
    } catch {
        # for test
        Write-Host $_
    }
    if ($timetaken -lt 0 -or $timetaken -ge 500) {
        [int]$time_errorcode = 1
        [void]$appsDown.Add($app)
    }
}

# Output the results here
if ($appsDown.Count -eq 0) {
    Write-Output "All apps okay"
}
else {
    Write-Output ($appsDown.Count.ToString() + "app(s) down")
    $appsDown | sort | foreach {
        Write-Output $_
    }
}

if (($errorcode -eq 0 -and $time_errorcode -eq 0)){exit $ok}
if (($errorcode -eq 1 -and $time_errorcode -eq 0)){exit $critical}
if (($errorcode -eq 0 -and $time_errorcode -eq 1)){exit $warning}
if (($errorcode -eq 1 -and $time_errorcode -eq 1)){exit $critical}
else {exit $unknown}

Пояснения:

$appsDown = New-Object "System.Collections.Generic.HashSet[string]"

Создайте новый экземпляр .NET HashSet для хранения имен приложений. (Это неупорядоченная коллекция, в которой каждое значение сохраняется только один раз.)

[void]$appsDown.Add($app)

Добавьте название приложения в коллекцию. [void] предназначен для предотвращения отправки возвращаемого значения метода в конвейер.

Это прекрасно и работает как шарм, спасибо. Я также хотел бы понять это, поэтому у меня есть несколько дополнительных вопросов. Прежде всего, что делает этот раздел? [void]$appsDown.Add($app) Во-вторых, я этого раньше не видел, для чего это тоже? New-Object "System.Collections.Generic.HashSet[string]"

RaptorPete 16.10.2018 17:25

@RaptorPete Я добавил несколько пояснений к своему ответу, надеюсь, это поможет. Если это решило вашу проблему, отметьте мой ответ как принятый.

marsze 17.10.2018 09:10

Сегодня я только понимаю, что ваш пример сообщит, что приложение «не работает», если время загрузки превышает 500 мс. В конечном итоге я бы хотел, чтобы он включал отдельный вывод для time_errorcode, а не просто «приложение не работает». Что-то вроде "$currentapp warning - download time 850ms" При этом в вашем операторе if / else, который выводит результаты, я не могу найти способ легко включить этот раздел. Вы сообщаете о любых приложениях в коллекцию, но можно ли также сообщить о конкретном времени в эту коллекцию и вывести их?

RaptorPete 17.10.2018 21:22

@RaptorPete У ​​вас есть несколько вариантов. Вы можете создавать несколько коллекций, наборов пользовательских объектов, вывод на итерацию и т. д. Все зависит от того, что именно вы хотите выводить и как. Попробуйте, и если вам нужна дополнительная помощь, не стесняйтесь расширять исходный вопрос.

marsze 18.10.2018 09:04

Другие вопросы по теме