PowerShell: 10 командлетов, без которых жить нельзя

PowerShell команды на экране

Если ты сетевой инженер или системный администратор, и PowerShell для тебя — это только Get-Help и Get-Process, то эта статья как раз для тебя. Я собрал десять командлетов, которые реально экономят время, нервы и, возможно, карьеру. Не все из них лежат на поверхности, но каждый стоит своего веса в золоте. Поехали!

1. Get-Command: «Что вообще ты умеешь, PowerShell?»

Когда забыл название команды, но помнишь, что она точно существует. Или хочешь понять, какие командлеты доступны в новом модуле.

# Простой поиск
Get-Command *service*

# Поиск по модулю (например, для NetTCPConnection)
Get-Command -Module NetTCPConnection

# Поиск по типу: cmdlet, function, alias
Get-Command -CommandType Cmdlet *net*

# Показать детали одной команды
Get-Command Get-Service | Format-List

💡 Почему это гениально:

Вместо гугления «как посмотреть службы в PowerShell» ты за 2 секунды находишь все команды со словом service. Особенно полезно при работе с новыми модулями типа Az или ExchangeOnline.

2. Select-Object: «Покажи мне только то, что нужно»

Многие думают, что это просто для выбора колонок. На самом деле — это швейцарский нож для работы с объектами.

# Базовое использование - выбор полей
Get-Process | Select-Object Name, CPU, WorkingSet

# Выбор первых/последних записей
Get-EventLog -LogName System -Newest 100 | Select-Object -First 10
Get-EventLog -LogName System -Newest 100 | Select-Object -Last 10

# Выбор уникальных значений
Get-Service | Select-Object Status -Unique

# Создание вычисляемых свойств (самая мощная фича!)
Get-Process | Select-Object Name, 
    @{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSet/1MB,2)}},
    @{Name="CPU_Time";Expression={$_.CPU.ToString("N2")}},
    @{Name="Is_Heavy";Expression={$_.WorkingSet -gt 100MB}}

# Выбор по индексу (если объект - массив)
$services = Get-Service
$services[0..4] | Select-Object Name, Status

💡 Про-фишка:

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

3. Where-Object: «Отфильтруй это немедленно!»

Фильтрация — это 80% работы с данными. Where-Object делает это элегантно, особенно в PowerShell 7 с упрощённым синтаксисом.

# Классический синтаксис (PowerShell 5.1+)
Get-Service | Where-Object {$_.Status -eq "Running"}

# Упрощённый синтаксис (PowerShell 7+)
Get-Service | Where-Object Status -eq "Running"

# Несколько условий
Get-Process | Where-Object {
    $_.CPU -gt 100 -and 
    $_.WorkingSet -gt 100MB -and 
    $_.Name -notlike "*chrome*"
}

# Фильтрация по шаблону
Get-Service | Where-Object Name -like "*sql*"

# Использование оператора -in
$importantServices = "WinRM", "Spooler", "EventLog"
Get-Service | Where-Object Name -in $importantServices

# Фильтрация по наличию свойства
Get-Process | Where-Object {$_.MainWindowTitle} | Select-Object Name, MainWindowTitle

⚡ Важно:

В PowerShell 7 появился «синтаксис без фигурных скобок» для простых условий. Меньше печатать — меньше ошибаться.

4. ForEach-Object: «Сделай это с каждым»

Циклы — хорошо, ForEach-Object — лучше. Особенно когда работаешь с конвейером.

# Базовый перебор
Get-Service | ForEach-Object {
    Write-Host "Служба $($_.Name) имеет статус $($_.Status)" -ForegroundColor Cyan
}

# Возврат изменённых объектов
Get-ChildItem C:\Windows\*.log | ForEach-Object {
    [PSCustomObject]@{
        Name = $_.Name
        Size_MB = [math]::Round($_.Length/1MB, 2)
        LastAccess = $_.LastAccessTime.ToString("dd.MM.yyyy HH:mm")
        IsOld = $_.LastAccessTime -lt (Get-Date).AddDays(-30)
    }
}

# Параллельное выполнение! (PowerShell 7+)
1..10 | ForEach-Object -Parallel {
    Start-Sleep -Seconds 1
    "Элемент $_ обработан в потоке $([System.Threading.Thread]::CurrentThread.ManagedThreadId)"
} -ThrottleLimit 5

# Использование $PSItem (синоним $_)
Get-Process | ForEach-Object { $PSItem.Name }

🔥 Мега-фича:

ForEach-Object -Parallel в PowerShell 7 — это революция. Обрабатывай тысячи элементов, используя несколько ядер процессора. Прощай, однопоточность!

5. Group-Object: «Сгруппируй и властвуй»

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

# Группировка по статусу служб
Get-Service | Group-Object Status -NoElement |
    Select-Object Count, Name |
    Sort-Object Count -Descending

# Группировка с вычисляемым свойством
Get-Process | Group-Object {$_.Name.Substring(0,1).ToUpper()} |
    Select-Object Name, Count, 
        @{Name="TotalMemory(MB)";Expression={[math]::Round(($_.Group.WorkingSet | Measure-Object -Sum).Sum/1MB,2)}} |
    Sort-Object Count -Descending

# Группировка по нескольким свойствам
Get-EventLog -LogName System -EntryType Error -Newest 100 |
    Group-Object Source, InstanceID |
    Select-Object Count, Name |
    Sort-Object Count -Descending |
    Select-Object -First 5

# Сохранить группы для дальнейшего анализа
$groupedProcesses = Get-Process | Group-Object Company
$groupedProcesses | Where-Object Count -gt 5 | ForEach-Object {
    Write-Host "Компания: $($_.Name) - процессов: $($_.Count)" -ForegroundColor Yellow
    $_.Group | Select-Object -First 3 Name, CPU
}

📊 Аналитика:

Group-Object + Select-Object с вычисляемыми свойствами = мгновенная аналитика. За 30 секунд получаешь то, на что в GUI потратил бы 10 минут.

6. Sort-Object: «Всё по порядку»

Казалось бы, что тут сложного? Но и тут есть свои хитрости.

# Сортировка по одному полю
Get-Service | Sort-Object Status, Name | Format-Table -AutoSize

# Обратная сортировка
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, CPU

# Сортировка по вычисляемому свойству
Get-ChildItem C:\Windows\*.exe |
    Sort-Object @{Expression={$_.Length/1MB}; Descending=$true} |
    Select-Object -First 10 Name, 
        @{Name="Size(MB)";Expression={[math]::Round($_.Length/1MB,2)}}

# Сортировка с учётом регистра
Get-ChildItem | Sort-Object Name -CaseSensitive

# Уникальность через сортировку (альтернатива Get-Unique)
Get-EventLog -LogName System -Newest 50 | 
    Select-Object -ExpandProperty Source | 
    Sort-Object -Unique

🎯 Секрет:

Sort-Object @{Expression={…}} позволяет сортировать по любым вычислениям. Хочешь отсортировать файлы по размеру в мегабайтах, а не в байтах? Легко!

7. Measure-Object: «Посчитай-ка это»

Статистика в одну строку. Больше не нужно писать циклы для подсчёта суммы или среднего.

# Базовые измерения
Get-Process | Measure-Object

# Сумма, среднее, минимум, максимум
Get-Process | Measure-Object WorkingSet -Sum -Average -Minimum -Maximum

# Сумма в человекочитаемом виде
$memoryStats = Get-Process | Measure-Object WorkingSet -Sum -Average
Write-Host "Всего памяти: $([math]::Round($memoryStats.Sum/1GB,2)) GB" -ForegroundColor Green
Write-Host "В среднем на процесс: $([math]::Round($memoryStats.Average/1MB,2)) MB" -ForegroundColor Cyan

# Подсчёт строк в файлах
Get-ChildItem *.ps1 -Recurse | ForEach-Object {
    $lineCount = Get-Content $_.FullName | Measure-Object -Line
    [PSCustomObject]@{
        File = $_.Name
        Lines = $lineCount.Lines
        Path = $_.DirectoryName
    }
} | Sort-Object Lines -Descending | Select-Object -First 10

# Подсчёт уникальных значений (альтернатива Group-Object)
Get-Service | Select-Object -ExpandProperty Status | Measure-Object

🧮 Магия чисел:

Measure-Object делает то, на что в других языках нужны отдельные функции или даже библиотеки. Всё встроено и оптимизировано.

8. Compare-Object: «Найди отличия»

Сравнение конфигураций, списков файлов, пользователей — ежедневная рутина. Compare-Object делает это безболезненно.

# Сравнение двух списков
$yesterday = Get-Service | Select-Object Name, Status
Start-Sleep -Seconds 60
$today = Get-Service | Select-Object Name, Status

Compare-Object $yesterday $today -Property Name, Status |
    Where-Object SideIndicator -eq "=>" |
    Select-Object Name, Status

# Сравнение файлов в папках
$sourceFiles = Get-ChildItem C:\Source -Recurse
$destFiles = Get-ChildItem C:\Backup -Recurse

Compare-Object $sourceFiles $destFiles -Property Name, Length, LastWriteTime |
    Format-Table -AutoSize

# Сравнение с игнорированием регистра
$list1 = @("SERVER1", "server2", "Server3")
$list2 = @("server1", "SERVER2", "server4")

Compare-Object $list1 $list2 -CaseSensitive:$false

# Что есть в одном, но нет в другом
$domainUsers = Get-ADUser -Filter * | Select-Object -ExpandProperty SamAccountName
$localUsers = Get-LocalUser | Select-Object -ExpandProperty Name

$missingUsers = Compare-Object $domainUsers $localUsers |
    Where-Object SideIndicator -eq "<=" |
    Select-Object -ExpandProperty InputObject

🕵️‍♂️ Детектив:

Идеально для аудита. Что изменилось в конфигурации сервера? Какие пользователи появились/исчезли? Какие файлы не скопировались в бэкап?

9. Export-Csv / Import-Csv: «Экспорт во внешний мир»

PowerShell хорош, но иногда нужно поделиться результатами с Excel, Tableau или просто сохранить для истории.

# Экспорт в CSV
Get-Service | 
    Select-Object Name, Status, StartType, DisplayName |
    Export-Csv -Path "C:\reports\services_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8

# Импорт CSV
$services = Import-Csv -Path "C:\reports\services_20231215.csv"
$services | Where-Object Status -eq "Stopped" | ForEach-Object {
    Write-Host "Служба $($_.Name) остановлена" -ForegroundColor Red
}

# Работа с пользовательскими разделителями
Get-Process | Select-Object -First 5 Name, CPU | 
    Export-Csv -Path "processes.txt" -Delimiter "`t" -NoTypeInformation

# Экспорт с фильтрацией в одну строку
Get-EventLog -LogName System -EntryType Error -Newest 100 |
    Select-Object TimeGenerated, Source, Message |
    Export-Csv "system_errors.csv" -NoTypeInformation

# Импорт и преобразование типов
$data = Import-Csv "report.csv" | ForEach-Object {
    [PSCustomObject]@{
        Name = $_.Name
        Date = [DateTime]$_.Date
        Value = [int]$_.Value
    }
}

📁 Совместимость:

CSV — универсальный формат. Импортируешь в Excel, загружаешь в базу данных, анализируешь в Python. Все довольны.

10. Get-Member: «Что внутри этого объекта?»

Самый важный командлет для изучения PowerShell. Не знаешь, что можно сделать с объектом? Спроси у Get-Member!

# Показать всё содержимое объекта
Get-Service | Get-Member

# Только свойства
Get-Process | Get-Member -MemberType Property

# Только методы
Get-Date | Get-Member -MemberType Method

# Поиск по имени
Get-ChildItem | Get-Member *time*

# Детальная информация о конкретном свойстве
(Get-Service)[0] | Get-Member -Name Status

# Практический пример: узнаём, какие методы есть у строки
"Hello, PowerShell" | Get-Member -MemberType Method |
    Where-Object {$_.Name -like "*replace*"} |
    Select-Object Name, Definition

# Узнаём, как преобразовать дату
Get-Date | Get-Member *string* | Select-Object Name, Definition

🎓 Учитель:

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

Бонус: Комбинируем всё вместе

Настоящая сила PowerShell — в комбинации командлетов. Вот реальный пример из жизни:

# Анализ логов: какие ошибки чаще всего встречаются за последний час?
Get-EventLog -LogName Application -After (Get-Date).AddHours(-1) -EntryType Error |
    Group-Object Source |
    Select-Object Name, Count,
        @{Name="LastError";Expression={$_.Group[0].TimeGenerated}} |
    Sort-Object Count -Descending |
    Export-Csv "hourly_errors.csv" -NoTypeInformation

# Мониторинг диска: какие папки занимают больше всего места?
Get-ChildItem C:\ -Directory | ForEach-Object {
    $size = Get-ChildItem $_.FullName -Recurse -File -ErrorAction SilentlyContinue |
        Measure-Object -Property Length -Sum
    [PSCustomObject]@{
        Folder = $_.Name
        Size_GB = [math]::Round($size.Sum / 1GB, 2)
        Files = $size.Count
    }
} | Sort-Object Size_GB -Descending |
    Select-Object -First 10 |
    Format-Table -AutoSize

# Сравнение конфигураций серверов
$server1 = Invoke-Command -ComputerName SRV01 {Get-Service | Select-Object Name, Status}
$server2 = Invoke-Command -ComputerName SRV02 {Get-Service | Select-Object Name, Status}

Compare-Object $server1 $server2 -Property Name, Status |
    Where-Object SideIndicator -eq "=>" |
    Group-Object SideIndicator |
    ForEach-Object {
        Write-Host "На сервере SRV0$($_.Name -replace '=',''):" -ForegroundColor Yellow
        $_.Group | Select-Object -First 5 Name, Status
    }

Золотое правило PowerShell: Если ты делаешь что-то вручную больше двух раз — автоматизируй это. Эти 10 командлетов — твой базовый набор. Комбинируй их, создавай конвейеры, пиши функции. Скоро ты обнаружишь, что 90% рутины можно упаковать в 10-20 строк кода.

Удачи в автоматизации! Помни: лень — двигатель прогресса, особенно если ты инженер.

📚 Что дальше?

Освоил эти командлеты? Пришло время для:

  • Функций: Оберни свои конвейеры в функции с параметрами
  • Модулей: Собери набор функций в модуль для повторного использования
  • Pester: Напиши тесты для своих скриптов
  • PowerShell 7: Переходи на новую версию для скорости и новых фич

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