PowerShell для начинающих администраторов: основы

PowerShell для начинающих администраторов основы

PowerShell это командная оболочка и язык сценариев от Microsoft, созданный специально для администрирования Windows. В отличие от обычной командной строки, PowerShell работает с объектами, а не с текстом, что делает автоматизацию задач значительно проще и надёжнее.

Почему именно PowerShell

Короче, вот история. Командная строка (cmd.exe) существует с времён DOS. Она умеет выполнять команды. Но когда дело доходит до сложных задач, начинаются костыли. Парсинг текстового вывода, хрупкие bat-файлы, невозможность нормально работать с ошибками.

PowerShell работает иначе. Каждая команда возвращает не текст, а объекты. Объект это структура данных со свойствами и методами. Например, команда Get-Process возвращает не строки текста, а объекты процессов. У каждого объекта есть свойства: имя, PID, потребление памяти, CPU. Можно отфильтровать, отсортировать, сгруппировать. Без регулярных выражений и костылей.

Мой знакомый Игорь работает системным администратором в юридической фирме. У него 70 рабочих станций (в основном HP EliteDesk 800 G6 на i7-10700). Раньше он всё делал мышкой. Создать 20 пользователей в AD? Клик, клик, клик. Двадцать раз. После того как он освоил PowerShell, создание 20 пользователей это один скрипт, который работает 30 секунд. По факту, PowerShell сэкономил ему часы каждую неделю.

Первые команды

Тут такое дело. PowerShell использует систему именования Глагол-Существительное (Verb-Noun). Get-Process, Set-Location, New-Item. Это интуитивно понятно даже без документации.

# Получить список процессов
Get-Process

# Получить список запущенных служб
Get-Service | Where-Object {$_.Status -eq "Running"}

# Информация о компьютере
Get-ComputerInfo | Select-Object OsName, OsVersion, CsTotalPhysicalMemory
# Покажет версию ОС и объём оперативной памяти

# Содержимое папки (аналог dir/ls)
Get-ChildItem C:Users
# Можно сокращённо: ls, dir, gci -- все работают

А зачем вообще эта система именования? Потому что вы можете догадаться, что делает команда, даже если видите её впервые. Stop-Service? Останавливает службу. Remove-Item? Удаляет файл. New-ADUser? Создаёт пользователя в Active Directory. Знаете что? Три самые полезные команды для новичка:

  • Get-Help показывает справку по любой команде
  • Get-Command ищет команды по шаблону
  • Get-Member показывает свойства и методы объекта

# Найти все команды, связанные с пользователями AD
Get-Command *ADUser*
# Покажет: Get-ADUser, New-ADUser, Set-ADUser, Remove-ADUser

# Справка по команде
Get-Help Get-ADUser -Examples
# Покажет примеры использования

# Какие свойства есть у объекта процесса?
Get-Process | Get-Member
# Выведет все свойства и методы: Name, Id, CPU, WorkingSet...

Конвейер (Pipeline)

Вот в чём прикол PowerShell. Конвейер. Вы берёте результат одной команды и передаёте его в другую. Через символ |. Но в отличие от Linux, передаются не строки текста, а объекты.

# Найти 5 самых прожорливых процессов по памяти
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5 Name, @{N='RAM_MB';E={[math]::Round($_.WorkingSet64/1MB)}}

# Остановить все процессы notepad
Get-Process notepad | Stop-Process
# Получили объекты notepad, передали в Stop-Process -- всё закрылось

# Найти все большие файлы в папке
Get-ChildItem C:Temp -Recurse | Where-Object {$_.Length -gt 100MB} | Select-Object FullName, @{N='Size_MB';E={[math]::Round($_.Length/1MB)}}
# Ищем файлы больше 100 МБ рекурсивно

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

Переменные и типы данных

Переменные в PowerShell начинаются с $. Просто.

# Строка
$name = "Сервер01"

# Число
$count = 42

# Массив
$servers = @("Server01", "Server02", "Server03")

# Хеш-таблица (словарь)
$user = @{
    Name = "Иванов"
    Department = "IT"
    PC = "WS-042"
}

# Обращение к элементу
$user.Name    # выведет: Иванов
$servers[0]   # выведет: Server01

# Переменная с результатом команды
$processes = Get-Process
$processes.Count    # количество процессов
# Теперь можно работать с $processes как с массивом объектов

Условия и циклы

Грубо говоря, тут всё как в обычных языках программирования.

# Условие if/else
$freeSpace = (Get-PSDrive C).Free / 1GB
if ($freeSpace -lt 10) {
    Write-Warning "Мало места на диске C! Свободно: $([math]::Round($freeSpace)) ГБ"
} else {
    Write-Host "Место на диске C в порядке: $([math]::Round($freeSpace)) ГБ"
}

# Цикл foreach
$servers = @("Server01", "Server02", "Server03")
foreach ($server in $servers) {
    $status = Test-Connection $server -Count 1 -Quiet
    if ($status) {
        Write-Host "$server -- доступен" -ForegroundColor Green
    } else {
        Write-Host "$server -- НЕ доступен" -ForegroundColor Red
    }
}
# Пингует каждый сервер и показывает статус

Практические скрипты для администратора

А ещё давайте напишем несколько реально полезных скриптов. Не Hello World, а то, что можно использовать прямо завтра.

Скрипт 1: Отчёт о свободном месте на дисках удалённых серверов.

# Проверяем диски на нескольких серверах
$servers = @("Server01", "Server02", "Server03")

foreach ($server in $servers) {
    Get-CimInstance Win32_LogicalDisk -ComputerName $server -Filter "DriveType=3" |
    Select-Object @{N='Сервер';E={$server}},
                  DeviceID,
                  @{N='Всего_ГБ';E={[math]::Round($_.Size/1GB)}},
                  @{N='Свободно_ГБ';E={[math]::Round($_.FreeSpace/1GB)}},
                  @{N='Процент_свободно';E={[math]::Round($_.FreeSpace/$_.Size*100)}}
}
# Результат можно экспортировать в CSV: | Export-Csv -Path report.csv -NoTypeInformation

Скрипт 2: Массовое создание пользователей из CSV.

# CSV-файл (users.csv) должен содержать колонки: Name, SamAccountName, Department
# Пример строки: Иванов Пётр,p.ivanov,IT

Import-Csv "C:scriptsusers.csv" -Encoding UTF8 | ForEach-Object {
    New-ADUser `
        -Name $_.Name `
        -SamAccountName $_.SamAccountName `
        -UserPrincipalName "$($_.SamAccountName)@company.local" `
        -Path "OU=$($_.Department),OU=Компания,DC=company,DC=local" `
        -AccountPassword (ConvertTo-SecureString "Welcome1!" -AsPlainText -Force) `
        -ChangePasswordAtLogon $true `
        -Enabled $true
    Write-Host "Создан пользователь: $($_.Name)" -ForegroundColor Green
}
# Все пользователи создаются в нужных OU с временным паролем

Если честно, именно этот скрипт (ну, его вариации) я использую чаще всего. Новый отдел, 15 человек, HR прислал список в Excel. Сохраняю как CSV, запускаю скрипт. Три минуты вместо часа.

Моя коллега Елена (она перешла в IT из бухгалтерии, работает на Lenovo IdeaCentre 5 с Ryzen 7 5700G) начала учить PowerShell полгода назад. Первый её скрипт просто переименовывал файлы в папке. Сейчас она автоматизирует отчёты по Active Directory. Путь от новичка до уверенного использования занял примерно 3-4 месяца при регулярной практике.

Работа с удалёнными компьютерами

Кстати, PowerShell умеет выполнять команды на удалённых компьютерах. Это называется PowerShell Remoting.

# Выполнить команду на удалённом компьютере
Invoke-Command -ComputerName Server01 -ScriptBlock {
    Get-Service | Where-Object {$_.Status -eq "Stopped" -and $_.StartType -eq "Automatic"}
}
# Найдёт все остановленные службы, которые должны быть запущены

# Интерактивная сессия на удалённом компьютере
Enter-PSSession -ComputerName Server01
# Теперь все команды выполняются на Server01
# Для выхода: Exit-PSSession

# Выполнить скрипт на нескольких компьютерах одновременно
Invoke-Command -ComputerName Server01, Server02, Server03 -FilePath C:scriptscheck-updates.ps1
# Скрипт запустится параллельно на всех трёх серверах

Обработка ошибок

Тут такое дело. Скрипты ломаются. Серверы недоступны, файлы не найдены, прав не хватает. Нужно уметь обрабатывать ошибки.

# Try/Catch для перехвата ошибок
try {
    Get-Content "C:несуществующийфайл.txt" -ErrorAction Stop
} catch {
    Write-Warning "Ошибка: $($_.Exception.Message)"
    # Запишем ошибку в лог
    Add-Content -Path "C:logserrors.log" -Value "$(Get-Date): $($_.Exception.Message)"
}
# ErrorAction Stop нужен, чтобы нетерминирующая ошибка стала терминирующей
# Иначе catch не сработает

Работа с файлами и папками

Одна из самых частых задач администратора: массовые операции с файлами. PowerShell делает это элегантно.

# Найти все файлы больше 100 МБ на диске C
Get-ChildItem C: -Recurse -ErrorAction SilentlyContinue |
    Where-Object {$_.Length -gt 100MB} |
    Sort-Object Length -Descending |
    Select-Object FullName, @{N='Size_MB';E={[math]::Round($_.Length/1MB)}} -First 20

# Массовое переименование файлов (добавить дату)
Get-ChildItem "C:Reports*.xlsx" | Rename-Item -NewName {
    $_.BaseName + "_" + (Get-Date -Format "yyyy-MM-dd") + $_.Extension
}

# Удалить файлы старше 30 дней
Get-ChildItem "C:Temp" -Recurse |
    Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} |
    Remove-Item -Force

# Найти дубликаты файлов по хешу
Get-ChildItem "C:Photos" -Recurse -File |
    Get-FileHash |
    Group-Object Hash |
    Where-Object {$_.Count -gt 1} |
    Select-Object -ExpandProperty Group

Вот в чём прикол: скрипт для очистки старых файлов из временных папок можно поставить на расписание через Task Scheduler. Один раз настроил, и каждый понедельник утром сервер сам чистит мусор. Без вашего участия.

PowerShell и Windows Registry

Реестр Windows через PowerShell работается как обычная файловая система. Серьёзно.

# Перейти в раздел реестра (как в папку)
Set-Location HKLM:SOFTWAREMicrosoftWindowsCurrentVersion

# Прочитать значение
Get-ItemProperty HKLM:SOFTWAREMicrosoftWindowsCurrentVersion -Name ProgramFilesDir

# Создать ключ
New-Item -Path "HKLM:SOFTWAREMyApp" -Force

# Создать значение
New-ItemProperty -Path "HKLM:SOFTWAREMyApp" -Name "Version" -Value "1.0" -PropertyType String

# Удалить значение
Remove-ItemProperty -Path "HKLM:SOFTWAREMyApp" -Name "Version"

# Поиск по реестру (найти все ключи содержащие "Uninstall")
Get-ChildItem HKLM:SOFTWAREMicrosoftWindowsCurrentVersionUninstall |
    Get-ItemProperty | Select DisplayName, DisplayVersion | Sort DisplayName

Последняя команда, кстати, показывает все установленные программы с версиями. Очень полезно для инвентаризации. Грубо говоря, вместо того чтобы обходить 70 компьютеров и записывать софт вручную, запускаете скрипт удалённо на всех машинах и получаете отчёт за минуту.

Планировщик задач и автоматизация

Ну и главное: скрипты нужно запускать автоматически. Для этого есть Task Scheduler.

# Создаём запланированную задачу через PowerShell
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File C:Scriptscleanup.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "03:00"
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable
Register-ScheduledTask -TaskName "DailyCleanup" -Action $action -Trigger $trigger -Settings $settings -User "SYSTEM"

# Проверяем что задача создана
Get-ScheduledTask -TaskName "DailyCleanup"

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

Где учить PowerShell дальше

Ну и напоследок. PowerShell огромен. Этой статьи хватит, чтобы начать, но для глубокого погружения рекомендую (по факту, каждый из этих ресурсов стоит потраченного времени):

  • Встроенная справка: Get-Help about_* показывает концептуальные статьи
  • Microsoft Learn (бесплатные курсы от Microsoft)
  • Книга «Learn PowerShell in a Month of Lunches» (есть и на русском)
  • Практика, практика, практика. Каждую рутинную задачу пробуйте автоматизировать

Форматирование вывода

По факту, умение красиво вывести результат это половина успеха. Вот основные способы форматирования:

# Таблица (по умолчанию для большинства команд)
Get-Service | Format-Table Name, Status, StartType -AutoSize

# Список (когда много свойств)
Get-Process chrome | Format-List Name, Id, CPU, WorkingSet64

# Вывод в файл
Get-EventLog -LogName System -Newest 50 | Export-Csv -Path "C:reportsevents.csv" -NoTypeInformation -Encoding UTF8

# HTML-отчёт (можно открыть в браузере)
Get-Service | Where-Object {$_.Status -eq "Running"} |
    ConvertTo-Html -Title "Запущенные службы" |
    Out-File "C:reportsservices.html"

# Вывод в GridView (интерактивная таблица с фильтрацией)
Get-Process | Out-GridView -Title "Процессы"

Знаете что? Out-GridView это недооценённая команда. Она открывает окно с интерактивной таблицей, где можно сортировать, фильтровать и искать. Для быстрого анализа это просто идеально.

А ещё для работы PowerShell с Active Directory, Hyper-V и другими серверными ролями нужен Windows Server. Ключи для Windows Server Standard и Datacenter можно приобрести на keytrust24.store. Для рабочих станций нужна Windows 10/11 Pro или Enterprise (в Home PowerShell есть, но без серверных модулей и без присоединения к домену).

Модули PowerShell: расширяем возможности

Базовый PowerShell это хорошо, но с модулями он становится всемогущим.

# Установка модуля из PowerShell Gallery
Install-Module -Name PSWindowsUpdate -Force
# Модуль для управления обновлениями Windows

# Список установленных модулей
Get-Module -ListAvailable

# Популярные модули для администратора:
# PSWindowsUpdate - управление Windows Update
# ActiveDirectory - управление AD (ставится с RSAT)
# Microsoft.Graph - работа с Microsoft 365
# ImportExcel - создание Excel-файлов без установки Excel
# Pester - тестирование скриптов

# Пример: создание Excel-отчёта без Excel
Install-Module -Name ImportExcel -Force
Get-Process | Select Name, CPU, WorkingSet | Export-Excel -Path "C:Reportsprocesses.xlsx" -AutoSize -TableStyle Medium6

Вот в чём прикол: модуль ImportExcel позволяет создавать красивые Excel-файлы с таблицами, графиками и форматированием. И для этого не нужен установленный Excel. По факту это один из самых популярных модулей в PowerShell Gallery.

Профиль PowerShell: настройте под себя

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

# Проверяем путь к профилю
$PROFILE
# Обычно: C:UsersИмяПользователяDocumentsWindowsPowerShellMicrosoft.PowerShell_profile.ps1

# Создаём профиль (если не существует)
if (!(Test-Path $PROFILE)) { New-Item -Path $PROFILE -Force }

# Редактируем
notepad $PROFILE

# Пример содержимого профиля:
# function Get-DiskSpace { Get-PSDrive -PSProvider FileSystem | Select Name, @{N='Used_GB';E={[math]::Round($_.Used/1GB)}}, @{N='Free_GB';E={[math]::Round($_.Free/1GB)}} }
# Set-Alias -Name df -Value Get-DiskSpace
# Write-Host "Привет, $env:USERNAME! Сегодня $(Get-Date -Format 'dd.MM.yyyy')" -ForegroundColor Green

Если честно, хороший профиль PowerShell экономит время каждый день. Одна короткая команда вместо длинного пайплайна. Мой коллега Антон (сисадмин, 120 рабочих станций, серверная на Dell PowerEdge R640) создал в профиле функции для всех рутинных задач: проверка дисков, поиск заблокированных пользователей AD, мониторинг репликации. Говорит, каждое утро начинает с одной команды morning-check, которая за 30 секунд показывает состояние всей инфраструктуры.

Типичные ошибки начинающих

Несколько граблей, на которые наступают все.

«Выполнение скриптов отключено». По умолчанию PowerShell запрещает запуск скриптов (.ps1). Решение:

# Разрешаем запуск локальных скриптов
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# RemoteSigned = локальные скрипты можно, скачанные только подписанные

Путаница с $_ и $PSItem. В конвейере текущий объект обозначается $_. Это сбивает новичков. $_ это не ошибка, это специальная переменная для текущего элемента в конвейере.

Забывают -ErrorAction Stop. По умолчанию нетерминирующие ошибки не попадают в try/catch. Грубо говоря, если не указать -ErrorAction Stop, скрипт молча проглотит ошибку и продолжит работать. Для надёжных скриптов всегда добавляйте этот параметр.

PowerShell vs Bash: что выбрать

Вот вопрос, который задают все, кто работает и с Windows, и с Linux: PowerShell или Bash? Короче, ответ зависит от вашей инфраструктуры.

Если вы администрируете Windows серверы и Active Directory, PowerShell без вариантов. Bash не умеет работать с .NET объектами, не понимает WMI/CIM, не управляет AD. А вот если у вас Linux серверы, то Bash роднее и быстрее.

Вот в чём прикол: PowerShell 7 (PowerShell Core) работает и на Linux и на macOS. Можно писать кроссплатформенные скрипты. Но на практике большинство Linux-администраторов всё равно предпочитают Bash, потому что он проще и легче.

Мой коллега Роман, DevOps-инженер, работает на MacBook Pro M2 и управляет и Windows и Linux серверами. Для Windows использует PowerShell, для Linux Bash. Говорит, «пытался всё делать на PowerShell 7, но на Linux многие вещи быстрее через Bash, привычка сильнее». На самом деле, знать оба инструмента это идеальный вариант для современного администратора.

Безопасность скриптов PowerShell

Тут такое дело: PowerShell скрипты могут быть опасными. Скрипт с правами администратора может удалить данные, изменить настройки безопасности, скачать вредоносное ПО. Поэтому важно соблюдать правила:

  • Никогда не запускайте скрипты из непроверенных источников от имени администратора
  • Используйте Set-ExecutionPolicy AllSigned на серверах (запуск только подписанных скриптов)
  • Логируйте выполнение скриптов через Enable-PSScriptBlockLogging
  • Используйте JEA (Just Enough Administration) для ограничения прав пользователей PowerShell

Знаете что? Один из самых частых способов атаки на Windows серверы это вредоносные PowerShell скрипты. Злоумышленник присылает файл .ps1 по почте, сотрудник запускает, и всё. Поэтому политика выполнения (Execution Policy) и аудит скриптов это не паранойя, а необходимость.

PowerShell это инвестиция. Каждый час, потраченный на обучение, вернётся десятикратно в виде сэкономленного времени. На самом деле, знание PowerShell это то, что отличает администратора от продвинутого пользователя. Ну и зарплату тоже поднимает, если честно. Администратор с PowerShell ценится выше, чем администратор без него. Грубо говоря, если вы администрируете Windows и не знаете PowerShell, вы используете операционную систему на 30% от её возможностей. Это как водить машину только на первой передаче. Ездить можно, но зачем? Начните с малого: автоматизируйте одну рутинную задачу. Потом вторую. Через месяц вы не представите, как жили без PowerShell.