Статья

Как создать скрипт PowerShell: первый .ps1, запуск и проверка ошибок

После истории с HTTPS захотелось рассказать не только о результате, но и об инструменте. Скрипты PowerShell помогали нам проверять настройки и восстанавливать работу сайтов. Но сначала мы сами получили несколько уроков: от неправильной кодировки до команды, которая завершилась, а задачу не решила. Начнём с простого примера, который только читает файлы.

Скрипты PowerShell: окно терминала и файл .ps1 с отметкой проверки

После истории с HTTPS захотелось рассказать не только о результате, но и об инструменте. Скрипты PowerShell помогали нам проверять настройки и восстанавливать работу сайтов. Но сначала мы сами получили несколько уроков: от неправильной кодировки до команды, которая завершилась, а задачу не решила. Начнём с простого примера, который только читает файлы.

Что такое скрипт PowerShell и зачем нужен файл .ps1

Скрипт PowerShell – текстовый файл с командами и расширением .ps1. Вместо длинной цепочки действий в консоли можно сохранить последовательность, дать ей понятное имя и запускать с нужными параметрами. Например, получить список файлов, подготовить отчёт или проверить состояние сервисов.

Для первого опыта выберите задачу без изменений: прочитать сведения и показать результат. Когда станет понятно, что именно обрабатывает скрипт, можно добавлять запись отчёта и другие действия. Проверять первый сценарий на рабочем сервере с массового изменения настроек – плохая отправная точка.

В примерах ниже используется синтаксис, совместимый с Windows PowerShell 5.1 и PowerShell 7. О формате файлов и запуске подробнее рассказывает документация Microsoft о скриптах.

Шаг 1. Узнайте, в какой версии вы работаете

Откройте PowerShell и выполните:

$PSVersionTable.PSVersion

Windows PowerShell запускается командой powershell.exe, а установленный отдельно PowerShell 7 – командой pwsh. Это важно: способы сохранения текста и доступные возможности могут отличаться. Проверять скрипт нужно в той версии, в которой он будет работать, в том числе по расписанию.

Шаг 2. Создайте первый скрипт PowerShell

Создайте отдельную учебную папку. В текстовом редакторе сохраните следующий код в файл Get-FolderReport.ps1. Проверьте, что редактор не добавил второе расширение .txt. В качестве входных данных используйте обычную папку с несколькими тестовыми файлами.

#Requires -Version 5.1
[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$FolderPath
)

$ErrorActionPreference = 'Stop'

try {
    $folder = Get-Item -LiteralPath $FolderPath
    if (-not $folder.PSIsContainer) {
        throw 'Укажите папку, а не файл.'
    }

    $files = @(Get-ChildItem -LiteralPath $folder.FullName -File)
    $totalBytes = ($files | Measure-Object -Property Length -Sum).Sum

    [PSCustomObject]@{
        Folder = $folder.FullName
        FileCount = $files.Count
        SizeMB = [math]::Round(([double]$totalBytes / 1MB), 2)
    }
}
catch {
    throw ('Не удалось подготовить отчёт: ' + $_.Exception.Message)
}

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

Get-ChildItem получает файлы только из выбранной папки. Подпапки не обходятся, скрытые файлы без -Force не включаются. Поэтому результат – размер выбранного набора файлов, а не полный размер каталога на диске. Конструкция @() сохраняет результат как массив даже при нуле или одном файле.

PSCustomObject возвращает структурированный результат: путь, количество файлов и размер. Это удобнее готовой текстовой строки: позже такой объект можно отфильтровать или передать в экспорт. Блок catch добавляет контекст к ошибке и повторно сообщает о неудаче, вместо ложного «Всё готово».

Шаг 3. Сохраните русские буквы без сюрпризов

В нашей работе файл содержал русские названия сайтов. Windows PowerShell прочитал его с неверной кодировкой, и вместо понятного текста появились «Р…С…» и ошибки разбора. Исправлять команды в такой ситуации бессмысленно, пока не исправлено чтение файла.

Для скрипта с кириллицей, который будут запускать в Windows PowerShell 5.1, выберите в редакторе UTF-8 с BOM. В PowerShell 7 UTF-8 без BOM обычно не вызывает этой проблемы, но для совместимости с 5.1 здесь сохраняем BOM. Само наличие BOM не восстановит уже испорченные буквы: сначала убедитесь, что исходный текст читается правильно.

В разных версиях параметр -Encoding UTF8 ведёт себя по-разному: в Windows PowerShell 5.1 он записывает BOM, в PowerShell 7 – нет. Поэтому лучше явно проверить кодировку в редакторе. См. описание кодировок Microsoft.

Шаг 4. Проверьте синтаксис до запуска

В консоли перейдите в учебную папку и выполните проверку ниже. Она разбирает файл, но не выполняет его команды. Имена tokens и parseErrors здесь обычные переменные для результата проверки.

$scriptPath = (Resolve-Path -LiteralPath '.\Get-FolderReport.ps1').Path
$tokens = $null
$parseErrors = $null
$null = [System.Management.Automation.Language.Parser]::ParseFile(
    $scriptPath, [ref]$tokens, [ref]$parseErrors
)
if ($parseErrors.Count -gt 0) {
    $parseErrors | Select-Object Message, Extent
} else {
    'Ошибок синтаксиса не найдено.'
}

Такая проверка находит, например, незакрытые кавычки или скобки. Она не доказывает, что папка существует, хватает прав или логика верна. После неё нужен пробный запуск на тестовых данных. Саму проверку тоже выполняйте в целевой версии PowerShell.

Шаг 5. Запустите .ps1 одной понятной командой

Из папки со скриптом выполните команду ниже. Вместо C:\TestFiles укажите существующую тестовую папку. Обычных прав пользователя для чтения доступных ему файлов достаточно.

.\Get-FolderReport.ps1 -FolderPath 'C:\TestFiles'

Или запустите файл отдельным процессом Windows PowerShell 5.1. Здесь оба пути примерные, замените их своими:

powershell.exe -NoProfile -File "C:\PS-Lab\Get-FolderReport.ps1" -FolderPath "C:\TestFiles"

Не копируйте из переписки приглашение PS C:\…> и символы продолжения >>. Если консоль ждёт окончания случайно вставленной команды, нажмите Ctrl+C. В нашей истории незавершённый конвейер | связал команды, которые должны были выполняться отдельно. Сохранённый файл проще проверить, чем длинную вставку в консоль.

Если система сообщает, что выполнение сценариев запрещено, сначала посмотрите действующие политики:

Get-ExecutionPolicy -List

Для собственного проверенного локального скрипта на личном компьютере можно разрешить RemoteSigned только в текущем процессе. Выполняйте следующую команду лишь при такой блокировке, затем запускайте .\Get-FolderReport.ps1 в том же окне:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned

Политики организации могут иметь приоритет. Для скачанных файлов RemoteSigned также учитывает происхождение и подпись. Не меняйте настройки наугад и не добавляйте Bypass ко всем инструкциям. Подробности: политики выполнения PowerShell.

Какие ошибки ищут в Яндексе

Чтобы выбрать полезные примеры, 2 октября 2026 года я проверила запросы в Яндекс Вордстате. За 1–30 сентября 2026 года при настройках «Все регионы» и все устройства сервис показал: «выполнение сценариев отключено в этой системе» – 1 855, «powershell выполнение сценариев отключено» – 116, «ошибка при запуске powershell» – 76, «powershell код ошибки» – 31.

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

Ещё один практический вопрос – «не открывается сайт что делать»: 5 390 запросов в том же срезе. В нём могут быть самые разные причины, от настроек устройства до недоступности чужого сервера. Ниже покажу, какую часть диагностики можно выполнить средствами PowerShell.

Ошибка при запуске PowerShell: что проверить по тексту сообщения

«Выполнение сценариев отключено в этой системе», PSSecurityException. Файл ещё не начал выполнять вашу задачу: его запуск ограничен политикой. Посмотрите Get-ExecutionPolicy -List и вернитесь к шагу 5. Не путайте это с ошибкой внутри сценария. Для npm.ps1 сначала проверьте, что сообщение действительно относится к политике запуска этого файла, а не к установке пакетов.

«Имя … не распознано», CommandNotFoundException. Проверьте написание команды, текущую папку и наличие нужной программы или модуля. Для своего файла в текущей папке используйте .\Get-FolderReport.ps1. Если не находится команда стороннего инструмента, сначала проверьте его установку; добавлять случайные папки в PATH не нужно. См. правила поиска команд Microsoft.

«Не удаётся найти путь», ItemNotFoundException. Убедитесь, что путь существует именно на том компьютере, где запущен скрипт. Для проверки используйте Test-Path -LiteralPath. В примере Get-FolderReport.ps1 ошибка будет перехвачена и получит пояснение. В задании планировщика относительный путь может указывать не туда, куда в вашей интерактивной консоли.

Get-Location
Test-Path -LiteralPath 'C:\TestFiles' -PathType Container
Get-Command Get-ChildItem

«Отказано в доступе», Access denied. Проверьте, от какой учётной записи выполняется сценарий и какие права нужны конкретному файлу или сервису. Скрипт может показать проблемный шаг, но не выдаёт себе права. Запуск от администратора нужен только для действий, которым действительно требуется повышение прав; для учебного отчёта выберите доступную вам папку.

«Непредвиденная лексема», ParserError, UnexpectedToken. Проверьте кавычки, скобки и кодировку по шагам 3–4. Если вместо кириллицы видны «Р…С…», восстановите правильный текст и сохраните его в нужной кодировке. Не запускайте файл повторно в надежде, что синтаксическая ошибка исчезнет сама.

«Не удаётся привязать объект ввода», ParameterBindingException. Проверьте, поддерживает ли следующая команда данные из конвейера | и совпадает ли тип передаваемых значений. В нашей истории в Start-Website случайно попали результаты другой команды. Исправление состояло в разделении независимых действий, а не в отключении сообщений об ошибках.

Сайт не открывается: проверяем DNS и порт HTTPS

Следующие команды предназначены для Windows с доступными модулями DnsClient и NetTCPIP. Они выполняют диагностические запросы и не меняют настройки сайта. В примере указан HODWEB; для своей проверки замените домен на нужный, без https:// и без пути страницы.

$siteName = 'hodweb.ru'
Resolve-DnsName -Name $siteName -ErrorAction Stop
Test-NetConnection -ComputerName $siteName -Port 443

Ошибка разрешения имени. Если Resolve-DnsName не получает DNS-ответ, проверьте написание домена, доступность DNS-сервера и записи домена. Скрипт помогает воспроизвести проблему и собрать результат. Он не доказывает, что виноват именно хостинг или регистратор.

TcpTestSucceeded: False. TCP-соединение с портом 443 не установлено с этого компьютера. Возможны ограничения сети, фильтрация или недоступность сервера. Значение True означает лишь успешное TCP-подключение: оно не подтверждает исправность сертификата, HTTP-ответа или формы заявки. Отдельный неудачный PingSucceeded тоже не равен недоступности HTTPS.

Если сбой наблюдается только через мобильный интернет, сравните результаты из разных сетей. Успешная проверка с сервера не опровергает проблему у посетителя. О командах: Resolve-DnsName и Test-NetConnection.

Ошибки 404, 500, 503 и сертификата: получаем ответ сайта

После проверки соединения можно запросить страницу. Этот пример рассчитан на Windows PowerShell 5.1 и обычный публичный адрес без авторизации. Он запрашивает только указанную страницу, а не проверяет все ссылки на сайте.

try {
    $response = Invoke-WebRequest -Uri 'https://hodweb.ru/' -UseBasicParsing -TimeoutSec 20 -ErrorAction Stop
    [PSCustomObject]@{
        StatusCode = [int]$response.StatusCode
        CheckedAt = Get-Date
    }
}
catch {
    if ($null -ne $_.Exception.Response) {
        'HTTP: ' + [int]$_.Exception.Response.StatusCode
    }
    'Ошибка запроса: ' + $_.Exception.Message
}

404 – по этому адресу ресурс не найден. Проверяйте путь страницы, публикацию и маршрутизацию. 500 – сервер столкнулся с внутренней ошибкой; нужны журналы приложения. 503 – сервис недоступен; проверяйте состояние приложения, обслуживание и нагрузку. Один код ответа не определяет точную причину.

Ошибка доверия сертификату или защищённого соединения требует проверки срока сертификата, имени домена, цепочки доверия, времени на устройстве и настроек TLS. Не отключайте проверку сертификата ради зелёного результата. О том, как мы разбирались с сертификатами и IIS, есть отдельная история про HTTPS.

Даже HTTP 200 не доказывает, что пользователь может отправить заявку: сервер мог вернуть заглушку, а форма – сломаться в браузере. Catch в этом диагностическом фрагменте выводит результат для человека; если превращаете его в задание планировщика, добавьте явный сигнал неуспеха, например повторный throw. Параметры запроса описаны в документации Invoke-WebRequest.

Мало места на диске: обнаруживаем проблему до отказа записи

Когда отчёт, журнал или резервная копия не записывается, одна из возможных причин – нехватка свободного места. Сначала посмотрите объём файловых дисков:

Get-PSDrive -PSProvider FileSystem |
    Select-Object Name,
        @{Name='FreeGB'; Expression={[math]::Round($_.Free / 1GB, 2)}},
        @{Name='UsedGB'; Expression={[math]::Round($_.Used / 1GB, 2)}}

Затем учебный Get-FolderReport.ps1 поможет оценить файлы непосредственно в выбранной папке. Он не ищет все крупные папки на диске и ничего не удаляет. По результату можно отдельно спланировать архивирование или очистку с понятными правилами хранения. Нехватка места и повреждение файловой системы – разные проблемы: этот пример не исправляет ошибки диска. См. Get-PSDrive.

Так скрипты помогают бороться с ошибками: воспроизводят проверку, показывают конкретный сбой и позволяют заметить его раньше. Автоматическое исправление добавляется только после установления причины. Наши учебные примеры не перезапускают службы, не меняют DNS и не обновляют сертификаты.

Как понять, что скрипт действительно сработал

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

$ErrorActionPreference = 'Stop' помогает превращать нетерминирующие ошибки командлетов в ошибки, которые попадут в catch. Но в Windows PowerShell 5.1 это не делает неудачный запуск внешней .exe автоматически исключением. После такой программы нужно сразу проверить $LASTEXITCODE и сравнить его с документированными кодами именно этой программы. У некоторых утилит ненулевые коды не означают отказ.

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

Когда скрипт начинает что-то менять

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

В PowerShell есть механизм ShouldProcess. Вот отдельный учебный скрипт New-LabFolder.ps1: он создаёт только подпапку ps-demo рядом с собой и поддерживает предварительный просмотр:

[CmdletBinding(SupportsShouldProcess = $true)]
param()

$ErrorActionPreference = 'Stop'
$demoPath = Join-Path $PSScriptRoot 'ps-demo'
if (Test-Path -LiteralPath $demoPath) {
    throw 'Объект ps-demo уже существует. Выберите другую учебную папку.'
}
if ($PSCmdlet.ShouldProcess($demoPath, 'Создать учебную папку')) {
    New-Item -Path $demoPath -ItemType Directory | Out-Null
}
.\New-LabFolder.ps1 -WhatIf

С -WhatIf папка не создаётся: вы увидите предполагаемое действие. Без этого параметра скрипт создаст папку. Само объявление SupportsShouldProcess не защищает произвольные команды: изменение должно находиться внутри проверки ShouldProcess. Подробности: рекомендации Microsoft по ShouldProcess.

Если скрипт написал ИИ

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

Наш случай показал: даже правдоподобный код может ошибаться в кодировке, путях и предположениях о сервере. Проверка синтаксиса, тестовые данные и чтение отчёта остаются нужны независимо от того, кто написал скрипт. Хук слева ошибке – проверка до запуска. Хук справа – проверка результата. А победа только тогда, когда задача действительно выполнена.

Короткий чек-лист перед рабочим запуском

  • Понятно, какую задачу решает скрипт и какие объекты он затрагивает.
  • Файл имеет расширение .ps1; кодировка подходит целевой версии PowerShell.
  • Синтаксис проверен, пробные запуски выполнены на обычных, пустых и ошибочных данных.
  • Для изменений предусмотрены проверка цели, резервная копия и понятный способ восстановления.
  • Внешние программы проверяются по их кодам завершения; секреты не попадают в журналы.
  • После запуска проверяется реальный результат, а не только отсутствие красных строк.

Остался вопрос? Давайте разберёмся

Не получается запустить скрипт или непонятна ошибка? Напишите в сообщения сообщества ВКонтакте. Укажите версию PowerShell, текст ошибки и приложите ссылку на эту статью, чтобы я сразу поняла, о каком примере речь.

Задать вопрос во ВКонтакте

Отвечаю лично. Пожалуйста, не присылайте пароли и ключи доступа.

Что посмотреть дальше

По теме полезны: история исправления HTTPS, техническая поддержка сайта.

Есть повторяющаяся задача по сайту?

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

Обсудить задачу