PowerShell-скрипты на каждый день для сетевого инженера

Администратор за работой с PowerShell

Садимся, завариваем кофе погуще. Ежедневная рутина админа — это не только красивые дашборды и сложные IaC-пайплайны. Чаще это война с мелочами: «что слушает 5000-й порт?», «кто сожрал весь диск C:?» и «почему пинг не ходит?».

Вместо того чтобы сто раз в день делать одно и то же руками, напишем себе арсенал быстрых и метких PowerShell-скриптов. Не монстров на 500 строк, а именно инструментов для сиюминутной диагностики. PowerShell Core (7.x) — наш выбор, но всё будет работать и на классической 5.1.

1. Просмотр открытых портов: «Кто здесь слушает без спросу?»

Команда netstat -ano — старый друг, но её вывод просится в структурированный объект. Чтобы не пялиться в столбики текста, сделаем красиво и с пользой.

function Get-OpenPorts {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0)]
        [string]$FilterByState = 'LISTENING'
    )
    
    Write-Host "Ищем открытые порты (состояние: '$FilterByState')..." -ForegroundColor Cyan
    Write-Host "PID   Протокол Локальный адрес          Внешний адрес        Состояние    Процесс" -ForegroundColor Yellow
    Write-Host "---   -------- -------------          ------------        --------    -------" -ForegroundColor Yellow

    try {
        $networkData = Get-NetTCPConnection -ErrorAction Stop | Where-Object State -eq $FilterByState
    }
    catch {
        Write-Warning "Get-NetTCPConnection не сработал, возможно, ты на старом PowerShell. Использую netstat."
        $netstatResult = netstat -ano -p TCP | Select-String -Pattern '\s+(LISTENING|ESTABLISHED)\s+'
        foreach ($line in $netstatResult) {
            $parts = $line -split '\s+'
            Write-Host ($parts[4..$($parts.Length)] -join ' ') -ForegroundColor Gray
        }
        return
    }

    foreach ($conn in $networkData) {
        $proc = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
        $procName = if ($proc) { $proc.ProcessName } else { "N/A" }
        
        $color = if ($conn.LocalPort -lt 1024) { 'Red' } else { 'Green' }
        
        Write-Host ("{0,-5} {1,-8} {2,-22} {3,-20} {4,-10} {5}" -f 
            $conn.OwningProcess,
            'TCP',
            "$($conn.LocalAddress):$($conn.LocalPort)",
            "$($conn.RemoteAddress):$($conn.RemotePort)",
            $conn.State,
            $procName) -ForegroundColor $color
    }
}

💡 Как использовать:

Просто запусти Get-OpenPorts. Хочешь увидеть установленные соединения? Get-OpenPorts -FilterByState 'ESTABLISHED'. Красным подсветит системные порты (<1024) — часто именно там прячется что-то интересное.

2. Просмотр открытых файлов: «Кто прилепился к файлу как репей?»

Блокировка файла — классика жанра. Особенно весело, когда лог-файл не ротируется, а база не бэкапится. В Windows есть замечательная утилита handle.exe от Sysinternals, но если её под рукой нет, обойдёмся встроенными средствами.

function Get-LockedFile {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]$Path
    )
    
    process {
        Write-Host "Пробуем выяснить, кто мучает файл '$Path'..." -ForegroundColor Cyan
        try {
            $fileStream = [System.IO.File]::Open($Path, 'Open', 'Read', 'None')
            $fileStream.Close()
            Write-Host "Файл свободен для деятельности." -ForegroundColor Green
        }
        catch [System.IO.IOException] {
            Write-Host "Файл заблокирован! Ищем виновника..." -ForegroundColor Red
            $lockingProcess = Get-CimInstance -ClassName Win32_Process | 
                Where-Object { $_.CommandLine -like "*$Path*" } | 
                Select-Object ProcessId, Name, CommandLine
            
            if ($lockingProcess) {
                $lockingProcess | Format-Table -AutoSize
                Write-Host "Совет: для принудительного закрытия — kill -Id $($lockingProcess.ProcessId)" -ForegroundColor Yellow
            }
            else {
                Write-Host "Не удалось найти процесс через WMI. Рекомендую скачать handle.exe от Sysinternals." -ForegroundColor Yellow
            }
        }
    }
}

💡 Как использовать:

Get-LockedFile -Path "C:\logs\monster.log". Если файл заблокирован, скрипт попытается указать на процесс пальцем. Не идеально, но в 80% случаев работает.

3. Разрешаем ICMP эхо-пакеты: «Вернём пинг в строй!»

«Сервер не пингуется!» — эта фраза будит нас посреди ночи. Часто дело в бесчувственном фаерволе. Включаем ответ на эхо-запросы одной командой, но с проверкой.

function Enable-ICMPEcho {
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [Parameter(Position=0)]
        [string]$RuleName = "Allow ICMPv4 Echo Request"
    )
    
    Write-Host "Включаем пингование для этого хоста..." -ForegroundColor Cyan
    Write-Host "Предупреждение: это правило фаервола Windows. Убедись, что запускаешь от админа." -ForegroundColor Yellow

    $existingRule = Get-NetFirewallRule -DisplayName $RuleName -ErrorAction SilentlyContinue
    
    if ($existingRule) {
        Write-Host "Правило '$RuleName' уже существует. Включаем его." -ForegroundColor Gray
        Set-NetFirewallRule -DisplayName $RuleName -Enabled True
    }
    else {
        Write-Host "Создаём новое правило фаервола: '$RuleName'." -ForegroundColor Gray
        New-NetFirewallRule `
            -DisplayName $RuleName `
            -Description "Allow ICMP Echo Request for daily troubleshooting" `
            -Protocol ICMPv4 `
            -IcmpType 8 `
            -Enabled True `
            -Profile Any `
            -Action Allow
    }
    
    $checkRule = Get-NetFirewallRule -DisplayName $RuleName | Select-Object DisplayName, Enabled, Action
    Write-Host "Результат:" -ForegroundColor Green
    $checkRule | Format-Table -AutoSize

    Write-Host "Готово. Теперь тебя должны пинговать. Проверь с другой машины." -ForegroundColor Green
    Write-Host "P.S. Не забудь про соседей по сети." -ForegroundColor DarkGray
}

⚠️ Как использовать:

Просто Enable-ICMPEcho. Скрипт создаст или включит правило в фаерволе. Запускать ОБЯЗАТЕЛЬНО от имени Администратора.

4. Остаток дискового пространства: «Диск C: снова на голодном пайке»

Классика, но с изюминкой. Не просто сухие цифры, а визуализация и предупреждение.

function Get-DiskSpaceReport {
    [CmdletBinding()]
    param(
        [Parameter(Position=0)]
        [string]$DriveLetter = "C"
    )
    
    Write-Host "Анализируем аппетиты диска $DriveLetter`:\..." -ForegroundColor Cyan
    
    $disk = Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue
    if (-not $disk) {
        Write-Error "Диск $DriveLetter не найден. Укажи правильную букву, дружище."
        return
    }
    
    $freePct = ($disk.Free / $disk.Used) * 100
    $color = if ($freePct -lt 10) { 'Red' } elseif ($freePct -lt 20) { 'Yellow' } else { 'Green' }
    
    $usedBlocks = [math]::Round(($disk.Used / $disk.Free) * 20)
    $bar = '[' + ('#' * $usedBlocks) + ('-' * (20 - $usedBlocks)) + ']'
    
    Write-Host "Диск: $($disk.Root)" -ForegroundColor White
    Write-Host "Всего: $([math]::Round($disk.Free / 1GB, 2)) GB" -ForegroundColor Gray
    Write-Host "Свободно: $([math]::Round($disk.Free / 1GB, 2)) GB ($([math]::Round($freePct, 1))%)" -ForegroundColor $color
    Write-Host "График: $bar" -ForegroundColor $color
    
    if ($freePct -lt 10) {
        Write-Host "Тревога! Свободного места меньше 10%!" -ForegroundColor Red -BackgroundColor Black
        Write-Host "Совет: проверь папки Temp, Logs и не забывай про "Очистку диска"." -ForegroundColor Yellow
    }
}

💡 Как использовать:

Get-DiskSpaceReport -DriveLetter C. Увидишь сразу, пора паниковать или ещё можно жить.

5. Мониторинг событий в журнале событий: «Что там опять натворила система?»

Листать Event Log — как читать детектив. Нужно искать ключевые улики. Сфокусируемся на критических ошибках и предупреждениях за последние сутки.

function Get-RecentEvents {
    [CmdletBinding()]
    param(
        [Parameter(Position=0)]
        [int]$HoursBack = 24,
        [Parameter(Position=1)]
        [ValidateSet('System', 'Application', 'Security')]
        [string]$LogName = 'System'
    )
    
    Write-Host "Роемся в журнале '$LogName' за последние $HoursBack часов..." -ForegroundColor Cyan
    Write-Host "Ищем только ошибки (Error) и предупреждения (Warning)." -ForegroundColor Gray
    
    $startTime = (Get-Date).AddHours(-$HoursBack)
    
    $events = Get-WinEvent -LogName $LogName -MaxEvents 50 -ErrorAction SilentlyContinue |
        Where-Object { $_.TimeCreated -ge $startTime -and ($_.Level -eq 2 -or $_.Level -eq 3) } |
        Select-Object TimeCreated, LevelDisplayName, ProviderName, Id, Message |
        Sort-Object TimeCreated -Descending

    if (-not $events) {
        Write-Host "Ура! Серьёзных проблем не обнаружено." -ForegroundColor Green
        return
    }
    
    Write-Host "Найдено подозрительных событий: $($events.Count)" -ForegroundColor Yellow
    
    foreach ($event in $events) {
        $levelColor = if ($event.LevelDisplayName -eq 'Error') { 'Red' } else { 'Yellow' }
        Write-Host "$($event.TimeCreated) [$($event.LevelDisplayName)] ($($event.ProviderName)) ID: $($event.Id)" -ForegroundColor $levelColor
        Write-Host "$($event.Message[0..200] -join '')..." -ForegroundColor Gray
        Write-Host "-" * 50 -ForegroundColor DarkGray
    }
    
    Write-Host "Совет: для деталей выполни 'eventvwr.msc' или посмотри событие по конкретному ID." -ForegroundColor Cyan
}

💡 Как использовать:

Get-RecentEvents -HoursBack 2 -LogName Application. Часто этого достаточно, чтобы понять, почему в 3 ночи проснулся.

Собираем всё в один набор

Сохрани каждый скрипт в отдельный .ps1 файл или добавь функции в свой профиль PowerShell ($PROFILE). Можно сделать красивый алиас для каждого.

New-Alias -Name ports -Value Get-OpenPorts
New-Alias -Name wholocks -Value Get-LockedFile
New-Alias -Name allowping -Value Enable-ICMPEcho
New-Alias -Name diskdiet -Value Get-DiskSpaceReport
New-Alias -Name whathappened -Value Get-RecentEvents

Итог: PowerShell — это не только для огромных скриптов развёртывания. Это ежедневный швейцарский нож в руках инженера, который предпочитает потратить 10 минут на написание скрипта, чем 100 часов на рутину. Автоматизируй то, что надоело, и останется время на кофе и решение действительно интересных проблем.

Крепких тебе сетей и зелёных статусов!

Оставьте комментарий