Pull to refresh
805.01
OTUS
Цифровые навыки от ведущих экспертов

Мониторим работу Windows с помощью Powershell

Level of difficultyEasy
Reading time6 min
Views8.7K

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

В операционных системах семейства Windows для автоматизации выполнения задач мониторинга лучше всего использовать Powershell. И далее в этой статье мы рассмотрим несколько полезных скриптов, которые могут упростить мониторинг состояния различных компонентов ОС.

Начнем с мониторинга состояния сетевых портов и взаимодействующих с ними процессов.

Про сети

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

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

В приведенном ниже примере, в переменной $ExpectedApplication мы определяем процесс, который мы ожидаем увидеть в списке слушающих порты, $NotAllowedApplication это соответственно тот процесс, который мы не хотим видеть в списке слушателей. Здесь Teamviewer это как раз то самое нежелательное приложение.

Результат работы скрипта представляется сообщениями со статусами Healthy/Unhealthy и соответствующей информацией. Так отсутствие процесса из $ExpectedApplication это Unhealthy, а отсутствие $NotAllowedApplication это наоборот Healthy.

$ExpectedApplication = "svchost"
$NotAllowedApplication = "Teamviewer"
$CompareToPrevious = $true

$Connections = Get-NetTCPConnection |  Where-Object { $_.LocalAddress -eq "0.0.0.0" -and $_.State -eq "Listen" }
$Processes = Get-Process

$CurrentListeners = foreach ($Connection in $Connections) {
 [PSCustomObject]@{
      Process = ($Processes | Where-Object id -eq $Connection.OwningProcess).Name
      Port    = ($Connection.LocalPort)
Path = ($Processes | Where-Object id -eq $Connection.OwningProcess).Path
}
} 

if ($ExpectedApplication -notin $CurrentListeners.Process) {
write-host "Unhealthy - The expected application was not found in the current process list"
} else {
write-host "Healthy - The expected application was found in the current process list"
} 

if ($NotAllowedApplication -in $CurrentListeners.Process) {
write-host "Unhealthy - The non-allowed application was found in the current process list"
} else {
write-host "Healthy - The non-allowed application was not found in the current process list"
} 

if ($CompareToPrevious -eq $true) {
   $PreviousResult = Get-content -Path "C:\ProgramData\ListenerMonitor.txt" | ConvertFrom-Json
   $Result = Compare-Object $CurrentListeners $PreviousResult -Property Process,Port,Path
   if ($Result) {

write-host "Unhealthy - The Listener list has changed."
$Result
} else {
write-host "Healthy - The Listener list is still the same."
}
$CurrentListeners | ConvertTo-Json |out-file "C:\ProgramData\ListenerMonitor.txt"
}

Результаты выполнения скрипта сохраняются в текстовом файле C:\ProgramData\ListenerMonitor.txt и при каждом следующем запуске мы сравниваем текущий список процессов с предыдущим, полагая, что сохраненный список является правильным. В файле хранится название процесса, номер порта и путь к файлу.

На основе этого сценария можно разработать собственные средства анализа состояния процессов и портов для того, чтобы с помощью этого скрипта мониторить не только сетевую активность процессов, но и безопасность системы в целом.

Про безопасность

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

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

Psexec в общем случае не является хакерской утилитой (хотя в Metasploit есть эксплоиты, реализующие функционал данной утилиты), и с ее помощью администраторы могут выполнять массу полезных задач в клиентских системах. Поэтому просто запретить ее использование мы не можем, но хотелось бы мониторить появление соответствующего процесса в системе.

Для этого можно воспользоваться следующим скриптом.

$PSExecmon =  get-process | Where-Object { $_.description -like "*psexec*" }
if (!$PSExecmon) {
    $PSExecHealth = "Healthy - no PSExec service found."
} else {
    $PSExecHealth = "Unhealthy - PSExec service found"
}
write-host $PSExecHealth

Здесь мы специально ищем по маске, на случай переименования с помощью команды psexec -r. Но злоумышленники могут пойти дальше и в принципе изменить персональные идентификаторы процесса. В таком случае, мы можем попробовать поискать psexec по сертификату Майкрософт, которым он подписан.

$Procs = Get-Process | Where-Object { $_.Path -ne $null }
$PSExecmon = foreach ($Proc in $procs) {
    $Sig = Get-AuthenticodeSignature $proc.path
    if ($Sig.SignerCertificate.Thumbprint -eq "3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC") { $proc }
}
if (!$PSExecmon) {
    $PSExecHealth = "Healthy - no PSExec service found."
} else {
    $PSExecHealth = "Unhealthy - PSExec service found"
}

write-host $PSExecHealth

Здесь правда есть риск столкнуться с ложными срабатываниями, так как данную подпись используют также другие решения Майкрософт, например .NET.  

Продолжая эту тему, также хотелось бы рассмотреть еще один скрипт для мониторинга, который отслеживает любое приложение, запущенное из под SYSTEM и у которого нет идентификатора сеанса 0. Идентификатор сеанса 0 обычно используется только для служб и процессов, которые должны запускаться как системные. Если у вас есть приложение, запущенное под любым другим идентификатором сеанса, это означает, что оно использовало интерактивный вход в систему.

Также возможна ситуация, когда некоторые приложения запускаются в режиме интерактивного сеанса, и тогда нужно будет исключить эти процессы.

Для списка исключений мы используем переменную $ExcludedList. Далее получаем общий список процессов, извлекаем из него запущенные с правами SYSTEM и с ненулевым идентификатором.

$ExcludedList = "RtkAuduService64","Winlogon","SomeRMMApp"
 
$StrangeProcesses = get-process -IncludeUserName | Where-Object {$_.username -like "\*SYSTEM" -and $_.SessionId -ne 0 -and $\_.ProcessName -notin $ExcludedList}

if($StrangeProcesses){
Write-Host "Processes found running as system inside an interactive session. Please investigate"
$StrangeProcesses
} else {
write-host "Healthy. No processes found."
}

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

Про заряд

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

$AlertPercent = "70"

& powercfg /batteryreport /XML /OUTPUT "batteryreport.xml"
Start-Sleep 1
[xml]$Report = Get-Content "batteryreport.xml"

$BatteryStatus = $Report.BatteryReport.Batteries |
ForEach-Object {
[PSCustomObject]@{
DesignCapacity = $_.Battery.DesignCapacity
FullChargeCapacity = $_.Battery.FullChargeCapacity
CycleCount = $_.Battery.CycleCount
Id = $_.Battery.id
}
}

if (!$BatteryStatus) {
Write-Host "This device does not have batteries, or we could not find the status of the batteries."
}

foreach ($Battery in $BatteryStatus) {
    if ([int64]$Battery.FullChargeCapacity \* 100 [int64]$Battery.DesignCapacity -lt $AlertPercent) {
        Write-host "The battery health is less than expect. The battery was designed for $($battery.DesignCapacity) but the maximum charge is $($Battery.FullChargeCapacity). The battery info is $($Battery.id)"

    }
}

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

Заключение

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

Хочу пригласить вас на бесплатный вебинар про инвентаризацию Active Directory с помощью Powershell, а также на вебинар про групповые политики Windows.

Tags:
Hubs:
Total votes 9: ↑7 and ↓2+8
Comments3

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS