Автоматизация задач в Windows с помощью PowerShell
Терминал и CMD → справочник команд → простые цепочки в BAT → этот материал про .ps1.
Сначала о модели автоматизации — 124 PowerShell.
Для Linux-серверов параллельный путь — скрипты Unix.
Play ITЗагрузка интерактивного демо…
Скрипты в среде Windows на PowerShell
Если BAT-файл из статьи про сценарии CMD перестаёт хватать — нужны объекты, JSON, модули Azure AD или нормальная обработка ошибок — следующий шаг PowerShell. Скрипт .ps1 запускается так же из консоли или планировщика, но внутри вы работаете с типизированными объектами .NET, а не только со строками CMD.
Скрипты в Windows — это программы, написанные на языке сценариев и предназначенные для управления операционной системой, её компонентами и приложениями без прямого участия человека. Автоматизация в Windows изначально развивалась через пакетные файлы (.bat, .cmd) и visual-basic Script (.vbs). Эти технологии выполняли базовые задачи — запуск программ, копирование файлов, управление переменными окружения. Однако их возможности были ограничены — слабая интеграция с системными API, отсутствие строгой типизации, минимальные средства обработки ошибок, трудности в работе с объектами.
PowerShell появился как ответ на вызовы современной ИТ-инфраструктуры — рост числа управляемых узлов, усложнение конфигураций, необходимость централизованного администрирования. Это не просто оболочка, как Command Prompt. PowerShell — это полноценная платформа автоматизации, основанная на .NET Framework (в Windows PowerShell) и .NET Core/.NET 5+ (в PowerShell Core / PowerShell 7+). Она встроена в каждую версию Windows начиная с Windows 7 и Windows Server 2008 R2, и поддерживается на всех современных серверных и клиентских редакциях.
Главное отличие PowerShell от предшественников — его объектная природа. В традиционных текстовых оболочках (например, в Bash) команды обмениваются текстом. Команда ls -l выдаёт строку текста, которую grep парсит по шаблону, cut разрезает на колонки, awk агрегирует числа. Каждый инструмент работает с потоком символов, и программист отвечает за корректность структуры этого потока. В PowerShell команды (cmdlet’ы) передают друг другу объекты — экземпляры классов .NET с именованными свойствами и методами. Когда вы вызываете Get-Process, вы получаете не строки, а массив объектов типа System.Diagnostics.Process. У каждого объекта есть свойства — Id, Name, CPU, WorkingSet; и методы — Kill(), WaitForExit(), Refresh(). Последующие команды (Where-Object, Sort-Object, Select-Object) работают непосредственно со свойствами и методами, не требуя синтаксического разбора текста. Это исключает ошибки в парсинге, повышает надёжность и делает скрипты самодокументируемыми.
Что такое PowerShell
PowerShell — это комбинация из трёх компонентов:
-
Оболочка командной строки (shell) — интерфейс, в который пользователь вводит команды. Это программа
powershell.exe(для Windows PowerShell) илиpwsh.exe(для PowerShell 7+). Она загружает среду выполнения, обрабатывает ввод, выводит результаты, управляет сессией. -
Язык сценариев — декларативный и императивный язык, поддерживающий переменные, условные конструкции, циклы, функции, классы, модули, обработку исключений, потоки и асинхронные операции. Синтаксис заимствован из языков C-семейства, но адаптирован под административные задачи — глагол-существительное в именах команд (
Get-ChildItem,Set-Location,Test-Path), конвейерная передача (|), автоматическое связывание параметров. -
Платформа управления — набор командлетов (cmdlet), провайдеров (provider), модулей и API, позволяющих управлять практически всем в системе — файловой системой, реестром, сетевыми интерфейсами, службами, задачами планировщика, сертификатами, WMI/CIM, Active Directory, Azure, Office 365 и сотнями других компонентов. Большинство командлетов реализованы как .NET-классы, унаследованные от
CmdletилиPSCmdlet. Это позволяет сторонним разработчикам создавать собственные расширения, интегрируя PowerShell в любые системы.
PowerShell поддерживает кроссплатформенную работу: начиная с версии 6.0, он работает не только в Windows, но и в Linux, macOS, даже в контейнерах Docker и на устройствах ARM. Это делает его универсальным инструментом для гибридных и облачных сред.
Файлы скриптов
Скрипт PowerShell — это текстовый файл с расширением .ps1. Простейший скрипт может содержать одну команду:
Write-Host "Привет, Вселенная IT!"
Более сложный скрипт включает параметры, проверки, циклы, обработку ошибок:
param(
[string]$Path = ".",
[switch]$Recurse
)
if (-not (Test-Path $Path)) {
Write-Error "Путь '$Path' не существует."
exit 1
}
$files = Get-ChildItem -Path $Path -File -Recurse:$Recurse
Write-Host "Найдено $($files.Count) файлов."
$files | ForEach-Object {
Write-Host " $($_.Name) — $($_.Length) байт"
}
Такой файл сохраняется как List-Files.ps1. Его содержимое — это программа, которую PowerShell интерпретирует построчно (или компилирует в памяти для повышения производительности). Скрипт может быть запущен многократно, с разными параметрами, в разных контекстах.
Кроме .ps1, в экосистеме PowerShell используются:
-
.psm1— файлы модулей (загрузка:Import-Module <имя>). -
.psd1— файлы манифеста модуля. Это данные в формате хэш-таблицы PowerShell, описывающие модуль — его версию, автора, зависимости, экспортируемые функции, требуемые разрешения. -
.ps1xml— файлы форматирования и типов. Они определяют, как объекты отображаются в консоли (столбцы, ширина, цвета), какие методы и свойства доступны по умолчанию.
Эти расширения не требуют дополнительной настройки — PowerShell распознаёт их по имени и применяет соответствующие правила обработки.
Политика выполнения
PowerShell включает встроенную систему безопасности, называемую политикой выполнения (Execution Policy). Эта политика не является средством защиты от вредоносного ПО, а скорее инструментом предотвращения случайного запуска непроверенного кода. По умолчанию на клиентских системах (Windows 10/11) установлена политика Restricted. Она блокирует выполнение всех скриптов, включая локальные, и разрешает только интерактивный ввод команд в консоли.
Другие распространённые политики:
-
AllSigned— разрешает выполнение только тех скриптов, которые подписаны цифровой подписью доверенного издателя. Это используется в строго контролируемых корпоративных средах. -
RemoteSigned— разрешает запуск локальных скриптов без подписи, но требует подписи для скриптов, скачанных из интернета (например, через браузер или почту). Эта политика считается оптимальной для большинства пользователей. -
Unrestricted— разрешает запуск всех скриптов, но перед выполнением скачанного скрипта выводит предупреждение. Подходит для изолированных сред разработки и тестирования. -
Bypass— отключает все проверки. Используется в автоматизированных системах, где скрипты запускаются без участия человека.
Политику можно проверить командой:
Get-ExecutionPolicy
Изменение политики выполнения:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Важно: политика выполнения хранится в реестре и применяется на этапе запуска сессии PowerShell. Она не влияет на выполнение команд, введённых вручную, и не блокирует вызов .NET-методов напрямую.
Типичная ситуация на домашнем ПК: при двойном щелчке по .ps1 появляется сообщение, что выполнение скриптов запрещено. Для учебных скриптов своего авторства достаточно (один раз, от своего пользователя):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Скрипты, созданные локально, запустятся; файлы, скачанные из браузера, Windows помечает зоной "из интернета" — может понадобиться Unblock-File .\script.ps1. В корпоративной сети политику задаёт GPO: администратор может запретить Set-ExecutionPolicy — тогда запускайте подписанные скрипты или используйте powershell -ExecutionPolicy Bypass -File script.ps1 только там, где это разрешено политикой безопасности.
Запуск скриптов
Скрипт можно запустить несколькими способами, каждый со своими особенностями.
1. Запуск из консоли PowerShell
Откройте PowerShell (через "Пуск" → "Windows PowerShell" или поиск). Перейдите в каталог со скриптом:
cd C:\Scripts
Выполните скрипт с помощью оператора вызова (&) или точечной нотации (dot-sourcing):
-
.\MyScript.ps1— запускает скрипт в дочерней области видимости. Переменные, созданные внутри скрипта, не попадают в текущую сессию после завершения. Это стандартный и безопасный способ. -
. .\MyScript.ps1— dot-source — загружает скрипт в текущую область видимости. Функции и переменные остаются доступны после завершения. Используется для загрузки профилей, библиотек функций, настройки окружения.
2. Запуск из командной строки (cmd.exe) или ярлыка
Можно вызвать PowerShell из любого места системы, передав путь к скрипту:
powershell.exe -File "C:\Scripts\MyScript.ps1"
Ключ -File гарантирует, что аргумент интерпретируется как путь к файлу, даже если имя содержит пробелы или специальные символы. Альтернатива — -Command, но она требует экранирования и менее надёжна для сложных скриптов.
Этот способ используется в ярлыках, планировщике задач, групповых политиках и системных службах.
3. Запуск через контекстное меню
Если щёлкнуть правой кнопкой по файлу .ps1 в Проводнике, в меню появится пункт "Выполнить с помощью PowerShell". Эта команда запускает скрипт в новом окне консоли с политикой, установленной по умолчанию. Окно остаётся открытым после завершения — это позволяет увидеть результаты и ошибки. Для автоматических задач такой способ не подходит, но он удобен при тестировании.
4. Запуск через PowerShell ISE или VS Code
Интегрированные среды предоставляют кнопки "Запустить", "Запустить выделенное", "Отладка". Запуск происходит в рамках текущей сессии, что позволяет пошагово выполнять код, просматривать значения переменных, ставить точки останова.
Сравнение PowerShell и Bash
PowerShell и Bash — это не просто две разные командные оболочки. Это выражение двух различных подходов к управлению вычислительной средой: один — ориентированный на объекты и строгую типизацию, другой — на текст и композицию утилит.
Исторический контекст
Bash (Bourne-Again Shell) развивалась в среде Unix и Linux, где доминировала идея "всё есть файл". Даже устройства, процессы и сетевые сокеты представлены как файлы в виртуальной файловой системе. Это позволило создать утилиты, которые читают из stdin, пишут в stdout, и комбинируются через конвейер (|). Каждая утилита решает одну задачу, делает это хорошо, и передаёт результат — текст — следующей. Так родились grep, sed, awk, cut, sort, uniq. Эта модель чрезвычайно гибкая, но требует от пользователя знания синтаксиса регулярных выражений, экранирования и формата вывода каждой утилиты.
PowerShell появился позже, в 2006 году, в среде Windows, где API системных компонентов строились на COM и .NET — объектно-ориентированных технологиях. Разработчики PowerShell осознанно отказались от текстового конвейера в пользу объектного. Цель — сделать автоматизацию доступной для администраторов без глубоких знаний программирования, сохраняя при этом мощь и выразительность.
Конвейер
В Bash команда:
ps aux | grep nginx | awk '{print $2, $11}'
— сначала порождает текстовый вывод ps, затем grep фильтрует строки, содержащие "nginx", затем awk разбирает каждую строку по пробелам и выбирает второе и одиннадцатое поле. Если формат вывода ps изменится (например, добавится колонка с GPU-нагрузкой), скрипт сломается. Если имя процесса содержит пробелы, awk сдвинет индексы. Это хрупкая конструкция.
В PowerShell аналогичная задача:
Get-Process -Name nginx | Select-Object Id, Path
— получает массив объектов Process, фильтрует по свойству Name, затем выбирает два свойства: Id (идентификатор процесса) и Path (полный путь к исполняемому файлу). Формат объекта не зависит от способа отображения. Даже если Microsoft изменит текстовый вывод Get-Process, объекты останутся теми же. Свойства Id и Path — часть контракта API, и их изменение потребует критического обновления системы, что маловероятно.
Объектный конвейер исключает необходимость в grep/awk для базовой фильтрации и выборки. Вместо них используются универсальные командлеты:
Where-Object— фильтрация по условию ({ $_.CPU -gt 50 })Sort-Object— сортировка по свойствам (-Property CPU -Descending)Group-Object— группировка (-Property Company)Measure-Object— агрегация (-Property WS -Sum -Average)ForEach-Object— применение кода к каждому элементу ({ $_.Kill() })
Эти командлеты работают с любыми объектами, а не только с процессами. Это обеспечивает единообразие — один и тот же синтаксис применим к файлам, службам, сетевым адаптерам, сертификатам.
Синтаксис и читаемость
Bash использует компактный, насыщенный символами синтаксис:
$?— код возврата последней команды$$— PID текущего процесса$!— PID последнего фонового процесса&>— перенаправление stdout и stderr[[ ]]— расширенное условие$( )— подстановка команды
Этот стиль экономит символы, но повышает порог входа. PowerShell выбирает многословность и самодокументируемость:
$LASTEXITCODE— понятное имя переменной$PID— идентификатор процессаStart-Process -NoNewWindow— параметры в именованной формеif ($result -eq $true)— читаемое условие& { Get-Date }— явный вызов скрипт-блока
Имена командлетов следуют схеме Глагол-Существительное (Get-Service, Stop-Process, New-Item, Test-Connection). Это позволяет угадывать команду по её назначению и легко находить её через Get-Command -Verb Stop или Get-Help *service*.
Ошибки и отладка
Bash по умолчанию не прерывает выполнение при ошибке. Скрипт продолжает работать, даже если команда завершилась с кодом 1. Это требует явной проверки $? после каждой критической операции. PowerShell по умолчанию использует останавливающие ошибки (terminating errors) для большинства командлетов. Если Get-ChildItem не находит путь, он генерирует исключение. Это принуждает к осознанной обработке сбоев.
PowerShell поддерживает полноценную обработку исключений:
try {
$content = Get-Content -Path "C:\secret.txt" -ErrorAction Stop
Write-Host "Файл прочитан."
}
catch [System.UnauthorizedAccessException] {
Write-Warning "Нет прав на чтение файла."
}
catch {
Write-Error "Неизвестная ошибка: $($_.Exception.Message)"
}
finally {
Write-Host "Операция завершена."
}
Конструкция try/catch/finally работает как в C# или Java. Это делает код предсказуемым и устойчивым к внештатным ситуациям.
Провайдеры
Bash работает преимущественно с файловой системой. Доступ к реестру, сертификатам или переменным окружения требует специальных утилит (reg, certutil, printenv) или встроенных команд (declare, export).
PowerShell вводит концепцию провайдеров (providers). Провайдер — это адаптер, который отображает произвольное хранилище данных в иерархию, похожую на файловую систему. Встроенные провайдеры:
FileSystem— диски, папки, файлыRegistry— разделы и параметры реестра Windows (HKLM:\SOFTWARE)Environment— переменные окружения (Env:\PATH)Certificate— сертификаты (Cert:\CurrentUser\My)Alias— псевдонимы команд (Alias:\cd)Variable— переменные сессии (Variable:\PWD)Function— определённые функции (Function:\Write-Host)
Команды Get-ChildItem, Get-Item, Set-Item, New-Item, Remove-Item работают со всеми провайдерами одинаково:
# Просмотр переменных
Get-ChildItem Env:
# Чтение параметра реестра
(Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager").BootExecute
# Добавление переменной окружения
New-Item -Path Env:\MY_APP_CONFIG -Value "Production"
# Удаление сертификата
Remove-Item -Path "Cert:\LocalMachine\My\$thumbprint"
Это создаёт единый язык управления разнородными данными.
Интегрированная среда сценариев (ISE)
Подробнее на Learn: Introducing the Windows PowerShell ISE.
Windows PowerShell ISE — это официальная графическая среда разработки скриптов, поставляемая вместе с Windows. Она включает три основные области:
-
Панель меню и панель инструментов — кнопки "Создать", "Открыть", "Сохранить", "Запустить", "Остановить", "Выполнить выделенное". Каждая операция имеет горячие клавиши (например, F5 — запуск всего скрипта, F8 — выполнение выделенного фрагмента).
-
Область сценариев — редактор кода с подсветкой синтаксиса, автоформатированием, сворачиванием блоков (
#region/#endregion), навигацией по ошибкам. Поддерживается поиск и замена по регулярным выражениям, переход к строке по номеру (Ctrl+G), отмена и повтор действий (Ctrl+Z, Ctrl+Y). -
Область консоли — интерактивная сессия PowerShell. В отличие от отдельного окна консоли, здесь можно комбинировать выполнение скриптов и ручной ввод. Например, запустить скрипт, затем вызвать функцию из него, проверить значение переменной, изменить её и повторно вызвать функцию — всё в одном окне.
Отладка
ISE предоставляет полноценный отладчик:
- Точки останова ставятся кликом слева от номера строки или через меню. Можно задать условие (
$i -gt 10) или действие при остановке (вывести значение переменной). - Шаг с заходом (F11) — заходит внутрь функции.
- Шаг с обходом (F10) — выполняет функцию целиком, не заходя внутрь.
- Выполнение до курсора (Ctrl+F10) — запускает код до указанной строки.
- Панель локальных переменных — отображает все переменные в текущей области видимости, их тип и значение. Можно изменить значение прямо в таблице.
- Панель стека вызовов — показывает цепочку вызовов функций, позволяя "подняться" на уровень выше.
Это позволяет анализировать состояние программы в реальном времени, выявлять логические ошибки, проверять граничные условия.
Работа с профилями и модулями
ISE автоматически загружает пользовательский профиль при запуске. Профиль — это скрипт Microsoft.PowerShellISE_profile.ps1, расположенный в папке Documents\WindowsPowerShell. В нём можно:
- Задать псевдонимы (
Set-Alias ll Get-ChildItem) - Определить вспомогательные функции (
function prompt { "PS> " }) - Настроить цветовую схему (
$psISE.Options.ConsoleTokenColors['String'] = 'DarkGreen') - Импортировать часто используемые модули (
Import-Module ActiveDirectory)
ISE также поддерживает работу с модулями. Можно открыть .psm1-файл, внести изменения, нажать F5 — и модуль перезагрузится в текущей сессии. Это ускоряет цикл "написать — проверить — доработать".
Примечание: Начиная с Windows 10 версии 1903, Microsoft объявила ISE устаревшей и рекомендует использовать Visual Studio Code с расширением PowerShell. Однако ISE остаётся в системе по совместимости и удобна для быстрого запуска и отладки без установки дополнительных инструментов.
Структура скрипта
Простой одноразовый скрипт — это последовательность команд. Профессиональный скрипт — это программная единица, которая:
- принимает параметры
- содержит документацию
- проверяет входные данные
- обрабатывает ошибки
- логирует действия
- возвращает результат
Параметры
В начале скрипта объявляется блок param(). Он определяет, какие аргументы может принимать скрипт, их тип, значение по умолчанию, обязательность:
param(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$ComputerName,
[int]$Port = 80,
[ValidateSet("HTTP", "HTTPS")]
[string]$Protocol = "HTTP",
[switch]$Verbose
)
[Parameter(Mandatory = $true)]требует обязательного указания параметра.[ValidateNotNullOrEmpty()]проверяет, что строка не пустая и не null.[ValidateSet(...)]ограничивает значения списком.[switch]— это булев флаг, который активируется, если указан (например,-Verbose).
Параметры можно передавать:
- По имени:
.\Test-Connection.ps1 -ComputerName srv01 -Port 443 - Позиционно:
.\Test-Connection.ps1 srv01 443(если порядок соблюдён) - Через хэш-таблицу (splatting):
$params = @{ ComputerName = "srv01"; Port = 443; Verbose = $true }
.\Test-Connection.ps1 @params
Splatting особенно удобен при вызове командлетов с множеством параметров.
Документация
PowerShell поддерживает стандарт комментариев на основе XML — комментарии помощи (comment-based help). Они размещаются в начале скрипта или функции и описываются так:
<#
.SYNOPSIS
Проверяет доступность веб-сервера.
.DESCRIPTION
Отправляет HTTP-запрос на указанный хост и порт, возвращает код ответа.
.PARAMETER ComputerName
Имя или IP-адрес сервера.
.PARAMETER Port
Порт (по умолчанию — 80).
.EXAMPLE
Test-WebServer -ComputerName example.com -Port 443
#>
После этого команда Get-Help .\Test-WebServer.ps1 выводит отформатированное описание, как для встроенных командлетов. Это делает скрипты самодокументируемыми и интегрируемыми в обучающие материалы.
Обработка ошибок
В скриптах используются три уровня обработки:
-
Предварительная проверка —
Test-Path,Test-Connection,Test-ModuleManifest. Эти командлеты возвращают$true/$falseбез исключений. -
Управляемые исключения —
try/catch, как показано выше. -
Глобальные настройки — параметр
-ErrorActionу каждой команды:Stop— превращает неостанавливающую ошибку в исключение.Continue— выводит ошибку, но продолжает выполнение (по умолчанию).SilentlyContinue— подавляет вывод ошибки.Ignore— подавляет ошибку и не записывает её в$Error.
Пример надёжного чтения файла:
$content = Get-Content -Path $Path -ErrorAction SilentlyContinue
if (-not $content) {
Write-Warning "Файл '$Path' пуст или недоступен."
return
}
Такой подход позволяет избежать аварийного завершения и дать пользователю осмысленную обратную связь.
Сквозной пример — скрипт под планировщик
Ниже один файл, который объединяет параметры, проверки, лог, обработку ошибок и готов к запуску из Планировщика заданий (аналог cron/systemd на Linux — скрипты Unix).
Сохраните как C:\Scripts\Sync-ProjectLogs.ps1:
<#
.SYNOPSIS
Копирует логи проекта в архивную папку с датой в имени.
.EXAMPLE
.\Sync-ProjectLogs.ps1 -SourcePath C:\App\logs -ArchiveRoot D:\LogArchive
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateScript({ Test-Path $_ -PathType Container })]
[string]$SourcePath,
[string]$ArchiveRoot = "D:\LogArchive",
[int]$KeepDays = 14
)
$ErrorActionPreference = 'Stop'
$LogFile = Join-Path $ArchiveRoot ("sync_{0:yyyyMMdd}.log" -f (Get-Date))
function Write-Log {
param([string]$Message)
$line = "[{0:yyyy-MM-dd HH:mm:ss}] {1}" -f (Get-Date), $Message
Add-Content -Path $LogFile -Value $line -Encoding UTF8
Write-Host $line
}
try {
if (-not (Test-Path $ArchiveRoot)) {
New-Item -Path $ArchiveRoot -ItemType Directory -Force | Out-Null
}
$stamp = Get-Date -Format "yyyy-MM-dd_HHmmss"
$dest = Join-Path $ArchiveRoot "logs_$stamp"
Write-Log "Старт: $SourcePath -> $dest"
Copy-Item -Path (Join-Path $SourcePath '*') -Destination $dest -Recurse -Force
$cutoff = (Get-Date).AddDays(-$KeepDays)
Get-ChildItem -Path $ArchiveRoot -Directory -Filter 'logs_*' |
Where-Object { $_.CreationTime -lt $cutoff } |
ForEach-Object {
Write-Log "Удаляю старый архив: $($_.FullName)"
Remove-Item -LiteralPath $_.FullName -Recurse -Force
}
Write-Log "Успешно завершено."
exit 0
}
catch {
Write-Log "ОШИБКА: $($_.Exception.Message)"
exit 1
}
Запуск вручную (после Set-ExecutionPolicy RemoteSigned -Scope CurrentUser, см. выше):
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Sync-ProjectLogs.ps1" -SourcePath "C:\App\logs"
Планировщик заданий Windows — типичные настройки:
| Вкладка | Значение |
|---|---|
| Действие | Программа: powershell.exe |
| Аргументы | -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Sync-ProjectLogs.ps1" -SourcePath "C:\App\logs" |
| Рабочая папка | C:\Scripts (необязательно, но удобно для относительных путей) |
| Триггер | Ежедневно, 03:00 |
| Условия | При питании от сети (для ноутбуков) |
Проверка последнего кода выхода в планировщике: в истории запусков смотрите код 0 / 1; в скрипте exit 1 при ошибке — планировщик может настроить повтор или оповещение.
Для задач сложнее архивации логов тот же каркас переносится: param → try/catch → Write-Log → exit с кодом. В BAT аналог — %ERRORLEVEL% и перенаправление в .log.
Триггеры автоматизации — расписание и наблюдатели
Скрипт .ps1 — это действия в модели автоматизации. Запускает его триггер. Концепция целиком — в 124 PowerShell; углублённо — Триггеры — расписание и наблюдатели. Здесь — практика в Windows.
| Тип триггера | Суть | Типичный инструмент в Windows |
|---|---|---|
| Расписание | Скрипт стартует по календарю, условие не проверяется | Планировщик заданий, Register-ScheduledTask (ниже) |
| Наблюдатель | Ждёт условие — новый файл, порог диска, строка в логе | FileSystemWatcher, цикл с Start-Sleep |
| Событие | Внешний сигнал — веб-хук, CI, ручной запуск | GitHub Actions, Jenkins, вызов из другого скрипта |
Расписание подходит для очистки, синхронизации и отчётов "раз в ночь". Наблюдатель — когда реагировать нужно на появление файла в папке, а не на время суток. Интервал опроса выбирают под задачу: если данные приходят раз в час, проверка каждую минуту лишняя нагрузка.
Минимальный наблюдатель за папкой (скрипт-исполнитель вызывают отдельно — так проще тестировать):
$folder = 'C:\Inbound'
$filter = '*.csv'
$action = {
param($sender, $eventArgs)
$path = $eventArgs.FullPath
Write-Host "Новый файл: $path"
# Start-Process pwsh -ArgumentList '-File C:\Scripts\Process-Inbound.ps1', $path
}
$watcher = New-Object System.IO.FileSystemWatcher $folder, $filter
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true
Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action
Write-Host "Наблюдатель за $folder ($filter). Ctrl+C для остановки."
while ($true) { Start-Sleep -Seconds 5 }
Долгоживущий наблюдатель удобнее оформить как службу Windows или задачу планировщика с частым перезапуском; для простых сценариев достаточно cron-подобного "опроса" — Get-ChildItem + сравнение с прошлым состоянием. На Linux тот же паттерн — inotify и systemd — см. скрипты Unix.
Регистрация задачи из PowerShell — Register-ScheduledTask
GUI планировщика удобен для разовой настройки; тот же результат воспроизводим в коде — удобно для образов ПК, onboarding и DevOps.
$scriptPath = 'C:\Scripts\Sync-ProjectLogs.ps1'
$source = 'C:\App\logs'
$action = New-ScheduledTaskAction `
-Execute 'powershell.exe' `
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`" -SourcePath `"$source`"" `
-WorkingDirectory 'C:\Scripts'
$trigger = New-ScheduledTaskTrigger -Daily -At '03:00'
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-StartWhenAvailable
$principal = New-ScheduledTaskPrincipal `
-UserId "$env:USERDOMAIN\$env:USERNAME" `
-LogonType S4U `
-RunLevel Limited
Register-ScheduledTask `
-TaskName 'ITUniverse-SyncProjectLogs' `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description 'Архив логов проекта (пример из энциклопедии)'
Get-ScheduledTask -TaskName 'ITUniverse-SyncProjectLogs' | Get-ScheduledTaskInfo
| Параметр | Смысл |
|---|---|
-RunLevel Limited | Без прав администратора (для задач в профиле пользователя) |
-RunLevel Highest | Как "с наивысшими правами" в GUI — только если скрипту это нужно |
-StartWhenAvailable | Догнать пропуск, если ПК был выключен в 03:00 |
Unregister-ScheduledTask -TaskName '...' -Confirm:$false | Удалить задачу |
Проверка вручную без ожидания триггера: Start-ScheduledTask -TaskName 'ITUniverse-SyncProjectLogs', затем журнал в C:\Scripts или Event Viewer → Task Scheduler.
Экспорт для другого ПК: Export-ScheduledTask -TaskName 'ITUniverse-SyncProjectLogs' -Path .\task.xml (импорт — Register-ScheduledTask -Xml).
Удалённое выполнение на Windows — PowerShell Remoting
Автоматизация редко ограничивается одним компьютером. PowerShell умеет запускать команды на других Windows-машинах по WinRM (WS-Management), а в PowerShell 7+ есть режим по SSH.
Базовый сценарий через WinRM:
$cred = Get-Credential
Invoke-Command -ComputerName SRV-APP-01 -Credential $cred -ScriptBlock {
Get-Service -Name wuauserv | Select-Object Name, Status
}
Постоянная сессия (удобно для серии команд):
$s = New-PSSession -ComputerName SRV-APP-01 -Credential $cred
Invoke-Command -Session $s -ScriptBlock { hostname; Get-Date }
Copy-Item -Path "C:\Scripts\Sync-ProjectLogs.ps1" -ToSession $s -Destination "C:\Scripts\"
Remove-PSSession $s
| Команда | Назначение |
|---|---|
Enable-PSRemoting -Force | Включить WinRM и правила firewall на целевой машине |
Invoke-Command | Выполнить блок кода удалённо |
New-PSSession | Открыть постоянную удалённую сессию |
Enter-PSSession | Интерактивно "войти" в удалённый PowerShell |
Минимальные требования для remoting по WinRM:
- сеть и firewall позволяют порты WinRM (обычно 5985 HTTP / 5986 HTTPS);
- целевой хост доверяет вашей аутентификации (домен или настроенный TrustedHosts);
- учётная запись имеет права на удалённой машине;
- при работе вне домена желательно использовать HTTPS или remoting по SSH.
Для PowerShell 7 можно использовать SSH-транспорт:
Invoke-Command -HostName srv-app-01 -UserName admin -ScriptBlock { Get-Process | Select-Object -First 5 }
Этот путь удобен в гибридных средах с Linux и Windows, где SSH уже стандарт.
Распространённые задачи
Скрипты PowerShell находят применение в десятках сценариев. Ниже — разбор типичных задач с пояснением логики, структуры и масштабируемости решений. Каждый пример можно использовать как шаблон и адаптировать под свои нужды.
1. Резервное копирование файлов и папок
Резервное копирование — одна из самых частых задач. Простой скрипт копирует папку с отметкой времени в имени архива:
param(
[string]$SourcePath = "C:\Projects",
[string]$BackupRoot = "D:\Backups"
)
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$backupName = "Backup_$timestamp.zip"
$backupPath = Join-Path -Path $BackupRoot -ChildPath $backupName
# Создаём папку для бэкапов, если её нет
if (-not (Test-Path $BackupRoot)) {
New-Item -Path $BackupRoot -ItemType Directory -Force
}
# Используем встроенный .NET-метод для архивации
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::CreateFromDirectory($SourcePath, $backupPath)
Write-Host "Резервная копия создана: $backupPath"
Этот скрипт:
- принимает параметры
SourcePathиBackupRoot, задаёт значения по умолчанию; - генерирует уникальное имя с точной датой и временем;
- проверяет существование целевой папки и создаёт её при необходимости;
- использует класс
ZipFileиз .NET — это надёжнее вызова внешних утилит вроде7z.exe; - выводит подтверждение.
Его можно расширить:
- добавить проверку свободного места на диске (
Get-PSDrive D | Select-Object Free); - включить сжатие с уровнем (
CompressionLevel::Optimal); - отправить уведомление по электронной почте (
Send-MailMessage); - удалить старые копии старше 30 дней (
Get-ChildItem -Path $BackupRoot -Filter *.zip | Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-30) } | Remove-Item).
Такой скрипт легко интегрируется в Планировщик заданий Windows — ежедневное, еженедельное или по триггеру (например, после завершения сборки проекта).
2. Управление правами доступа (ACL)
В Windows права доступа к файлам и папкам задаются через списки контроля доступа (ACL). Их настройка вручную — трудоёмкий процесс. Скрипт позволяет массово изменить права:
param(
[string]$Path = "C:\Shared",
[string]$User = "DOMAIN\Developers",
[string[]]$Permissions = @("ReadAndExecute", "Write")
)
$acl = Get-Acl -Path $Path
# Создаём правило доступа
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$User,
$Permissions -join ",",
"ContainerInherit,ObjectInherit",
"None",
"Allow"
)
# Добавляем правило в ACL
$acl.SetAccessRule($accessRule)
# Применяем обновлённый ACL
Set-Acl -Path $Path -AclObject $acl
Write-Host "Права для '$User' назначены на '$Path'."
Скрипт:
- получает текущий ACL через
Get-Acl; - создаёт объект
FileSystemAccessRuleс указанием пользователя, прав (Read,Write,FullControlи др.), наследования и типа (разрешение/запрет); - добавляет правило в ACL;
- применяет изменения.
Важные детали:
"ContainerInherit,ObjectInherit"означает, что права распространяются на подпапки и файлы.- Можно заменить
SetAccessRuleнаAddAccessRule, если нужно добавить правило, не затирая существующие. - Для удаления прав используется
RemoveAccessRule.
Такой подход исключает ошибки при ручной настройке и гарантирует единообразие политик безопасности.
3. Мониторинг использования ресурсов
Скрипт может отслеживать нагрузку на компьютер и реагировать на отклонения:
param(
[int]$CpuThreshold = 90,
[int]$MemoryThreshold = 85,
[int]$CheckIntervalSeconds = 60
)
while ($true) {
$cpu = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
$mem = (Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory /
(Get-CimInstance Win32_OperatingSystem).TotalVisibleMemorySize * 100
$freeMemPercent = 100 - $mem
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] CPU: $([int]$cpu)% | Память: $([int]$freeMemPercent)% свободно"
if ($cpu -gt $CpuThreshold) {
Write-Warning "Высокая загрузка CPU: $([int]$cpu)%"
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 | Format-Table Id, Name, CPU
}
if ($freeMemPercent -lt (100 - $MemoryThreshold)) {
Write-Warning "Низкий уровень свободной памяти: $([int]$freeMemPercent)%"
}
Start-Sleep -Seconds $CheckIntervalSeconds
}
Этот скрипт:
- использует
Get-Counterдля получения точных данных счётчиков производительности (в отличие от приблизительных значений в диспетчере задач); - вычисляет процент свободной памяти на основе CIM-модели;
- выводит текущую статистику с отметкой времени;
- при превышении порогов — показывает топ-5 процессов по CPU;
- работает в бесконечном цикле с паузой через
Start-Sleep.
Его можно доработать:
- записывать лог в файл (
Out-File -Append); - отправлять оповещение в Telegram через
Invoke-RestMethod; - автоматически завершать "прожорливые" процессы по правилам.
4. Массовая установка программ через Chocolatey
Chocolatey — менеджер пакетов для Windows. Скрипт позволяет развернуть стандартный набор ПО на новом компьютере:
# Установка Chocolatey (если отсутствует)
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
}
$packages = @(
"googlechrome",
"firefox",
"vscode",
"7zip",
"git",
"nodejs",
"python3",
"docker-desktop"
)
foreach ($pkg in $packages) {
Write-Host "Устанавливаю $pkg..."
choco install $pkg -y --no-progress
}
Скрипт:
- проверяет наличие
choco; - при необходимости устанавливает его с правильным протоколом безопасности;
- перебирает список пакетов и устанавливает их без подтверждения (
-y); - отключает прогресс-бар для автоматизации.
Это решение ускоряет подготовку рабочих станций в корпоративной среде, обеспечивает единообразие версий и исключает "ручной" поиск установщиков.
Модули и реиспользуемость кода
Один и тот же код не должен дублироваться в десятках скриптов. PowerShell предлагает механизм модулей — логических единиц, объединяющих связанные функции, переменные, классы и данные.
Структура модуля
Модуль — это папка с именем MyTools, содержащая как минимум один файл .psm1:
MyTools/
├── MyTools.psd1 # манифест (опционально, но рекомендуется)
└── MyTools.psm1 # основной код
Файл .psm1 содержит функции:
# MyTools.psm1
function Get-FreeSpace {
param([string]$Drive = "C")
$info = Get-PSDrive $Drive
[PSCustomObject]@{
Drive = $Drive
FreeGB = [math]::Round($info.Free / 1GB, 2)
UsedGB = [math]::Round($info.Used / 1GB, 2)
TotalGB = [math]::Round(($info.Free + $info.Used) / 1GB, 2)
}
}
function Test-Url {
param([string]$Url)
try {
$request = Invoke-WebRequest -Uri $Url -Method Head -TimeoutSec 10
$request.StatusCode -eq 200
} catch {
$false
}
}
Export-ModuleMember -Function Get-FreeSpace, Test-Url
Export-ModuleMemberуказывает, какие функции будут доступны после импорта модуля.- Внутри модуля можно определять приватные вспомогательные функции — они не будут экспортированы.
Использование модуля
-
Поместите папку
MyToolsв одну из стандартных директорий модулей:- Для текущего пользователя:
~\Documents\PowerShell\Modules\ - Для всех пользователей:
$env:ProgramFiles\PowerShell\Modules\
- Для текущего пользователя:
-
Импортируйте модуль:
Import-Module MyTools
- Используйте функции:
Get-FreeSpace -Drive D
Test-Url "https://spirzen.ru"
Преимущества модулей
- Инкапсуляция — внутренняя логика скрыта, интерфейс чётко определён.
- Версионность — в
.psd1можно указатьModuleVersion = '1.2.0', что позволяет управлять обновлениями. - Зависимости — модуль может требовать другие модули (
RequiredModules = @('ActiveDirectory')). - Автозагрузка — начиная с PowerShell 3.0, модули загружаются автоматически при вызове экспортируемой функции.
Модули — основа для построения библиотек внутренних инструментов в крупных организациях. Например, модуль ADTools для работы с Active Directory, BackupSystem для управления архивами, ReportGenerator для формирования отчётов в Excel или PDF.
Лучшие практики написания скриптов
Качественный скрипт — это не только рабочий код. Это документ, который другие могут читать, поддерживать и расширять.
1. Именование
- Файлы скриптов и модулей — в стиле PascalCase:
Backup-Database.ps1,NetworkTools.psm1. - Функции — Глагол-Существительное, согласно утверждённому списку глаголов:
Get-LogEntry,Set-Configuration,Test-Connection. - Переменные — camelCase —
$inputPath,$userList,$maxRetries.
2. Безопасность
- Избегайте
Set-ExecutionPolicy Unrestrictedв продакшене. ИспользуйтеRemoteSignedили цифровую подпись. - Не храните пароли в открытом виде. Используйте
Get-Credential,ConvertFrom-SecureString, или менеджеры секретов (Azure Key Vault, HashiCorp Vault). - Запускайте скрипты с минимально необходимыми правами. Для административных задач — отдельная учётная запись.
- Не копируйте
Invoke-Expressionиcurl | iexиз чатов без разбора — опасные скрипты.
Цифровая подпись скриптов (Authenticode)
Подпись подтверждает, что файл .ps1 не меняли после выпуска и (для доверенного издателя) кто его подписал. Политика AllSigned требует подпись для каждого скрипта; RemoteSigned — для скачанных из интернета, локальные можно без подписи.
Просмотр статуса:
Get-AuthenticodeSignature -FilePath 'C:\Scripts\Sync-ProjectLogs.ps1'
Подписать (нужен сертификат Code Signing в хранилище Cert:\CurrentUser\My или LocalMachine\My):
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert |
Sort-Object NotAfter -Descending |
Select-Object -First 1
if (-not $cert) {
throw 'Нет сертификата подписи кода. В учебной среде: New-SelfSignedCertificate -Type CodeSigningCert ...'
}
Set-AuthenticodeSignature `
-FilePath 'C:\Scripts\Sync-ProjectLogs.ps1' `
-Certificate $cert `
-TimestampServer 'http://timestamp.digicert.com'
| Тип сертификата | Где применяют |
|---|---|
| Самоподписанный (лаборатория) | Свой ПК, после Set-ExecutionPolicy и доверия к отпечатку |
| Корпоративный CA | Домен Windows, GPO раздаёт доверие |
| Публичный Code Signing | Софт для внешних клиентов |
Самоподписанный сертификат не делает скрипт безопасным для всех — он лишь привязывает хеш файла к ключу. В организации подпись сочетают с контролем доступа к папке C:\Scripts и ревью изменений, как для кода приложения.
После подписи в планировщике можно убрать -ExecutionPolicy Bypass из аргументов — достаточно -File, если политика домена доверяет издателю.
3. Тестирование
PowerShell имеет встроенную систему тестирования — Pester. Пример теста:
# Backup-Database.Tests.ps1
Describe "Backup-Database" {
It "Создаёт ZIP-файл в указанной папке" {
$backupPath = "TestDrive:\backup.zip"
Backup-Database -Source "TestDrive:\Данные" -Destination $backupPath
$backupPath | Should -Exist
(Get-Item $backupPath).Length | Should -BeGreaterThan 0
}
}
Pester позволяет писать unit-тесты, интеграционные тесты, проверять исключения, параметры, выходные объекты. Это гарантирует, что изменения не ломают существующую функциональность.
4. Логирование
Всегда записывайте ключевые этапы выполнения:
$LogPath = "C:\Logs\Backup_$(Get-Date -Format 'yyyyMMdd').log"
Start-Transcript -Path $LogPath -Append
# ... основной код ...
Stop-Transcript
Или используйте Write-Information, Write-Verbose, Write-Debug с параметром -InformationAction Continue. Это позволяет включать/выключать уровни детализации без изменения кода.
PowerShell в Windows Terminal и VS Code
Хотя ISE остаётся в системе, новые проекты лучше разрабатывать в современных средах.
Windows Terminal
Это центральный терминал для Windows 10/11. Он поддерживает вкладки, профили, настраиваемые шрифты (включая Nerd Fonts), темы, прозрачность, анимации курсора. PowerShell автоматически становится одним из профилей:
- Откройте Windows Terminal.
- Нажмите стрелку вниз → "Настройки".
- В
settings.jsonможно добавить кастомную команду, переменные окружения, начальную директорию.
Пример профиля для PowerShell 7:
{
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"name": "PowerShell 7",
"commandline": "pwsh.exe",
"hidden": false,
"colorScheme": "One Half Dark"
}
Visual Studio Code + расширение PowerShell
VS Code — рекомендуемая Microsoft среда для PowerShell-разработки. После установки расширения PowerShell появляются:
- Интеллектуальное завершение кода (IntelliSense) с подсказками по параметрам.
- Отладчик с точками останова, просмотром переменных, стеком вызовов.
- Встроенный терминал с поддержкой нескольких сессий.
- Анализ кода (PSScriptAnalyzer) — выявляет стилевые и потенциальные ошибки.
- Поддержка Jupyter-ноутбуков (
.ipynb) с ячейками PowerShell.
Преимущества VS Code:
- Кроссплатформенность — один и тот же интерфейс на Windows, Linux, macOS.
- Интеграция с Git — просмотр изменений, коммиты, ветвление прямо в редакторе.
- Поддержка Remote-SSH — написание скриптов для Linux-серверов с той же средой.
Официальная документация Microsoft
| Ссылка | Содержание |
|---|---|
| Документация PowerShell | Хаб Learn: начало работы, установка, примеры |
| Что такое PowerShell? | Оболочка, язык и платформа управления |
| Установка PowerShell | pwsh на всех ОС |
| Примеры для администрирования | Готовые сценарии под типовые задачи |
| PowerShell Gallery | Поиск и установка модулей (Find-Module, Install-Module) |
Углублённый раздел языка в энциклопедии: 5.26 PowerShell.
Смежные материалы
Раздел "Терминал" — оглавление, знаки препинания и конвейеры, чек-лист.
Windows — BAT-сценарии (legacy и простые задачи), справочник команд.
Linux — скрипты Bash, удалённый SSH.
Инфраструктура — основы DevOps и CI/CD, системное администрирование.
Безопасность — опасные скрипты; политика выполнения не заменяет проверку содержимого файла.
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.