Сравните временное смещение всех контроллеров домена в PowerShell - PullRequest
0 голосов
/ 26 февраля 2020

Я хотел бы сравнить разницу времени всех контроллеров домена через PowerShell.

Я нашел что-то вроде этого:

$output1 = & w32tm /monitor /domain:mydomain.local /threads:5
    $stdOutStart = 8
    $output = $output1[$stdOutStart..$output1.Length]

Я хочу извлечь данные из $output и сравните только время смещения ntp, и если оно превышает одну секунду, оно должно отправить почтовое оповещение.

$output - это не объект, а просто текст, как я могу извлечь необходимые поля ?

$output looks like
server2.mydomain.local[192.168.22.22:123]:
    ICMP: 1ms delay
    **NTP: +0.0017247s offset** from server1.mydomain.local
        RefID: server1.mydomain.local [192.168.22.122.]
        Stratum: 3

Ответы [ 4 ]

1 голос
/ 26 февраля 2020

Вы можете проанализировать смещение NTP в $output в [Double] и, если оно больше 1, отправить оповещение по электронной почте.

Примерно так:

if ($output -match 'NTP:\s+([+-]?\d(?:\.\d+)?)s') {
    $seconds = [double]::Parse($matches[1], [cultureinfo]::InvariantCulture)
    if ($seconds -gt 1) {
        # send an email alert
    }
}

Детали регулярного выражения:

NTP:             Match the characters “NTP:” literally
\s               Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   +             Between one and unlimited times, as many times as possible, giving back as needed (greedy)
[+-]             Match a single character present in the list below
                 The character “+”
                 The character “-”
   ?             Between zero and one times, as many times as possible, giving back as needed (greedy)
(                Match the regular expression below and capture its match into backreference number 1
   \d            Match a single digit 0..9
   (?:           Match the regular expression below
      \.         Match the character “.” literally
      \d         Match a single digit 0..9
         +       Between one and unlimited times, as many times as possible, giving back as needed (greedy)
   )?            Between zero and one times, as many times as possible, giving back as needed (greedy)
)               
s                Match the character “s” literally

В соответствии с вашим комментарием вы можете объединить мой код с ответом Стивенса .
Поскольку у вас уже есть строк в переменной массива с именем $output, я буду использовать это имя.

Пример:

$output = @"
server2.mydomain.local[192.168.22.22:123]:
    ICMP: 1ms delay
    NTP: +0.0017247s offset from server1.mydomain.local
        RefID: server1.mydomain.local [192.168.22.122.]
        Stratum: 3
server3.mydomain.local[192.168.22.23:123]:
    ICMP: 1ms delay
    NTP: +1.0017555s offset from server1.mydomain.local
        RefID: server1.mydomain.local [192.168.22.122.]
        Stratum: 3
server4.mydomain.local[192.168.22.24:123]:
    ICMP: 1ms delay
    NTP: +21.095731s offset from server1.mydomain.local
        RefID: server1.mydomain.local [192.168.22.122.]
        Stratum: 3
"@ -split '\r?\n'

Код может быть таким:

$AlertThreshold = 1 # Number of seconds before an alert...

for( $i = 0; $i -lt $output.Count; $i++ ) {
    if ($output[$i] -match 'NTP:\s+([+-]?\d+(?:\.\d+)?)s') {
        $seconds = [double]::Parse($matches[1], [cultureinfo]::InvariantCulture)
        if ($seconds -gt $AlertThreshold) {
            # prepare to send an send an email alert
            $currentServer = $output[$i - 2].TrimEnd(":")
            $refServer = ($output[$i] -split ' ')[-1]
            $message = "Alert: $currentServer time offset $seconds seconds from $refServer !"
            Write-Host $message
            # send the message
            $mailParams = @{
                To         = 'someone@yourdomain.com'
                From       = 'ntpchecker@yourdomain.com'
                SmtpServer = 'mailserver.yourdomain.com'
                Subject    = 'Alert Server Time Difference'
                Body       = $message
                Priority   = 'High'
                # etc.
            }
            # Send-MailMessage @mailParams
        }
    }
}

Результат:

Alert: server3.mydomain.local[192.168.22.23:123] time offset 1.0017555 seconds from server1.mydomain.local !
Alert: server4.mydomain.local[192.168.22.24:123] time offset 21.095731 seconds from server1.mydomain.local !
0 голосов
/ 29 февраля 2020

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

w32tm.exe действительно может вернуть отрицательное число, например -1.001755. Это не учитывается в последнем ответе. Кроме того, я бы использовал -ge & -le вместо -gt & -lt, так как есть крайний случай различия + + - ровно 1 секунда. Я знаю, что это, вероятно, тривиально в таком сценарии, но это также ничего не стоит, чтобы быть тщательным.

Я бы установил sh $mailParams га sh до For l oop и только сбросить значение body в блоке if.

Я не совсем уверен, почему мы используем метод [Double]::Parse(). Я работаю в США, где меньше нужны возможности глобализации. Однако в быстром тестировании я не вижу никакой разницы в результате. Рад, что это объяснили дальше.

Ключом к этому была возможность взглянуть назад через массив относительно строки NTP. То, как мы сопоставляем / идентифицируем линию и разделяем ее, является вопросом предпочтения. Тем не менее, я нашел недостаток в моем подходе, потому что в некоторых случаях может отображаться «NTP: ошибка». Это достаточно просто исправить без более сложного RegEx. Я добавил строки с ошибками в пример вывода, чтобы охватить его в следующих примерах.

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

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

Я сделал комментарий в своем первоначальном ответе на poli sh до $CurrentServer. @ Тео сделал это с .TrimEnd(':'), однако я думаю, что мы можем пойти дальше. Сначала я подумал, что это номер порта, который я могу сделать что-то вроде -replace ":\d{1,5}:", которое будет разделять двоеточие в конце и конце на 1-5 цифр. Это сработало, но не кажется правильным. Возможность отклонения NTP от хорошо известного порта 123 крайне мала. Итак, вместо этого давайте нарежем его, используя буквальное совпадение типа -replace ":123]:","]" Примечание: .Replace(":123]:", "]"), вероятно, будет работать так же хорошо.

Пример Вывод из w32tm:

# Sample Output, in practice set this to the output of w32tm.exe
$W32t_Output =
@(
'server2.mydomain.local[192.168.22.22:123]:'
'    ICMP: 1ms delay'
'    NTP: +0.0017247s offset from server1.mydomain.local'
'        RefID: server1.mydomain.local [192.168.22.122.]'
'        Stratum: 3'
'server2.mydomain.local[192.168.22.22:123]:'
'    ICMP: 1ms delay'
'    NTP: -1.0017247s offset from server1.mydomain.local'
'        RefID: server1.mydomain.local [192.168.22.122.]'
'        Stratum: 3'
'server2.mydomain.local[192.168.22.22:123]:'
'    ICMP: 1ms delay'
'    NTP: +2.0017247s offset from server1.mydomain.local'
'        RefID: server1.mydomain.local [192.168.22.122.]'
'        Stratum: 3'
'server2.mydomain.local[192.168.200.200:123]:'
'    ICMP: 0ms delay'
'    NTP: error ERROR_TIMEOUT - no response from server in 1000ms'
'DownServer.mydomain.local [error WSAHOST_NOT_FOUND]'
)

Пример 1 с использованием моего оригинальный подход:

# > Set $OneAlert to true if you want 1 alert for all the interesting time variances per run.
# > Set to false if you want a single alert for each interesting variance encountered per run.
$OneAlert       = $true
$Body           = [Collections.ArrayList]@()
$AlertThreshold = 1 # Number of seconds before an alert...

$mailParams = 
@{
    To         = 'someone@yourdomain.com'
    From       = 'ntpchecker@yourdomain.com'
    SmtpServer = 'mailserver.yourdomain.com'
    Subject    = 'Alert Server Time Difference'
    Body       = ''
    Priority   = 'High'
}

For( $i = 0; $i -lt $W32t_Output.Length; ++$i )
{
    $CurrentLine = $W32t_Output[$i].Trim()

    If( $CurrentLine -match '^NTP: ' -and $CurrentLine -notmatch 'error' )
    {
        $CurrentLineFields = $CurrentLine.Split(' ')                    # Break up the NTP line, as long as the output is predictable this should work.
        [Double]$OffSet    = $CurrentLineFields[1].Replace('s','')      # The second index should be the offset, clean it up to be a number...
        $DiffServer        =  $CurrentLineFields[-1]                    # Last thing on the current line should be the server is offset from.
        $CurrentServer     = $W32t_Output[$i-2] -replace ":123]:","]"   # Look back through the output array to get the current server. 

        # Logic for echoing and/or email alerting:
        If( $OffSet -ge $AlertThreshold -or $OffSet -le -$AlertThreshold )
        {
            If($OneAlert)
            {
                [Void]$Body.Add( "Alert : $CurrentServer time offset $Offset seconds from $DiffServer !" )
            }
            Else
            {
                $mailParams['Body'] = "Alert : $CurrentServer time offset $Offset seconds from $DiffServer !"
                Send-MailMessage @mailParams
            }
        }
    }
}

# $Body will only be populated if $OneAlert is true
If( $Body )
{
    $mailParams['body'] = $Body -join "`r`n"
    Send-MailMessage @mailParams   
}

Пример 2, дополнительно объединяющий подход @Theo:

# > Set $OneAlert to true if you want 1 alert for all the interesting time variances per run.
# > Set to false if you want a single alert for each interesting variance encountered per run.
$OneAlert       = $false
$Body           = [Collections.ArrayList]@()
$AlertThreshold = 1 # Number of seconds before an alert...

$mailParams = 
@{
    To         = 'someone@yourdomain.com'
    From       = 'ntpchecker@yourdomain.com'
    SmtpServer = 'mailserver.yourdomain.com'
    Subject    = 'Alert Server Time Difference'
    Body       = ''
    Priority   = 'High'
}

for( $i = 0; $i -lt $output.Count; $i++ ) {
    if ($output[$i] -match 'NTP:\s+([+-]?\d+(?:\.\d+)?)s') {
        $seconds = [double]::Parse($matches[1], [cultureinfo]::InvariantCulture)

        # Adjusted the if condition a little:
        if ( $seconds -ge $AlertThreshold -or $seconds -le -$AlertThreshold ) {
            $currentServer = $output[$i - 2] -replace ":123]:","]" # changed a little
            $refServer = ($output[$i] -split ' ')[-1]

            If($OneAlert) # prepare to send an email alert
            {
                [Void]$Body.Add( "Alert: $currentServer time offset $seconds seconds from $refServer !" )
            }
            Else
            {
                $mailParams['body'] = "Alert: $currentServer time offset $seconds seconds from $refServer !"
                Send-MailMessage @mailParams
            }
        }
    }
}

# $Body will only be populated if $OneAlert is true
If( $Body )
{
    $mailParams['body'] = $Body -join "`r`n"
    Send-MailMessage @mailParams   
}

Очевидно, это маленькое голубое небо, и я, вероятно, увлекся. В любом случае, дайте мне / нам знать, что вы думаете.

0 голосов
/ 26 февраля 2020

@ Тео, навыки RegEx - это то, что я просто не могу совмещать ... Посмотрите, что я там делал.

Серьезно, на днях я стану более свободным с RegEx, а пока я застрял делать вещи трудным путем. В этом случае я думаю, что вы хотите немного больше информации в вашем предупреждении. Для меня это означает, что нужно вернуться к выходным данным, чтобы получить смещение сервера от другого сервера за пределами желаемого порога. Обычно я использую традиционный For l oop, потому что я могу изменить значение переменной итерации для просмотра назад или вперед через массив.

    $Arr =
@(
'server2.mydomain.local[192.168.22.22:123]:'
'    ICMP: 1ms delay'
'    NTP: +0.0017247s offset from server1.mydomain.local'
'        RefID: server1.mydomain.local [192.168.22.122.]'
'        Stratum: 3'
'server2.mydomain.local[192.168.22.22:123]:'
'    ICMP: 1ms delay'
'    NTP: +0.0017247s offset from server1.mydomain.local'
'        RefID: server1.mydomain.local [192.168.22.122.]'
'        Stratum: 3'
'server2.mydomain.local[192.168.22.22:123]:'
'    ICMP: 1ms delay'
'    NTP: +0.0017247s offset from server1.mydomain.local'
'        RefID: server1.mydomain.local [192.168.22.122.]'
'        Stratum: 3'
)

$AlertThreshold = .0016 # Number of seconds before an alert...

For( $i = 0; $i -lt $Arr.Length; ++$i )
{
    $CurrentLine = $Arr[$i].Trim()
    # $CurrentLine

    If( $CurrentLine -match '^NTP: ')
    {
        # Break up the NTP line, as long as the output is predictable this should work.
        $CurrentLineFields = $CurrentLine.Split(' ')

        # The second index should be the offset, clean it up to be a number...
        [Double]$OffSet = $CurrentLineFields[1].Replace('s','')

        # Last thing on the current line should be the server is offset from.
        $DiffServer = $CurrentLineFields[-1]

        # Look back through the output array to get the current server.
        $CurrentServer = $Arr[$i-2] #May need some more work here to polish up the output.

        # Logic for echoing and/or email alerting:
        If( $OffSet -ge $AlertThreshold -or $OffSet -le -$AlertThreshold )
        {
            Write-Host "Alert : $CurrentServer time offset $Offset seconds from $DiffServer !"
            # You can send the email here of build up an email body for a single email alert that will
            # all the curious offsets...
        }
    }
}

Вывод:

Alert : server2.mydomain.local[192.168.22.22:123]: time offset 0.0017247 seconds from server1.mydomain.local !
Alert : server2.mydomain.local[192.168.22.22:123]: time offset 0.0017247 seconds from server1.mydomain.local !
Alert : server2.mydomain.local[192.168.22.22:123]: time offset 0.0017247 seconds from server1.mydomain.local !
  • Очевидно, я просто повторил данные, которые вы дали. Я не сижу в среде AD в данный момент. В вашем случае вы хотите назначить переменную для вывода w32tm.exe
  • Я не знаю, может ли смещение быть отрицательным, поэтому я учел этот сценарий.
  • Отрегулируйте порог переменная по мере необходимости. Я, очевидно, изменил его, чтобы проверить.
  • Комментарии для вашей пользы, если вы удалите их, они будут намного более краткими.

Скажите, если это безумие. Дайте мне знать, как это происходит.

0 голосов
/ 26 февраля 2020

Спасибо за ваш ответ, это выглядит как интересное решение. Не уверен, как набрать c номер ntp, для меня это будет нормально, если рассогласование будет на секундах, если первое число -не "0" NTP: - 0 .0022387s из полного вывода , (на выходе будет около 5 серверов ..)

$output1 = & w32tm /monitor /domain:mydomain.local /threads:5

$stdOutStart = 8
$output = $output1[$stdOutStart..$output1.Length]
$timeInfos = @()

for ($i = 0 ; $i -lt $output.Length ; $i+=4) {
        $server = $output[$i].Split(' ')[0]
        $icmp = $output[$i+1].Trim().Split(' ')[1]
        $offset = $output[$i+2].Trim().Split(' ')[1]
        $timeInfos += New-Object PsObject -Property @{
            Server = $server
            ICMP = $icmp
            Offset = $offset
        }
}

$timeInfos

if ($output -match 'NTP:\s+([+-]?\d(?:\.\d+)?)s') {
    $seconds = [double]::Parse($matches[1], [cultureinfo]::InvariantCulture)
    if ($seconds -gt 1) {
        Write-host " send an email alert..#mail script here"
    }

    else
    {
    Write-host " everything ok"

    }
    }


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...