<p>Сервер ночью сам не почистит логи. Учётки в AD сами себя не заведут. Бэкапы не сделаются по щелчку пальца — если, конечно, вы не написали скрипт. <strong>PowerShell скрипты</strong> — это не просто удобство, это разница между «я администратор» и «я автоматизатор, который уходит домой вовремя».</p>
<p>В этом гайде — всё по делу: как создать PowerShell <a class="wpil_keyword_link" href="https://it-apteka.com/category/scripts/" target="_blank" rel="noopener" title="Скрипты" data-wpil-keyword-link="linked" data-wpil-monitor-id="804">скрипт</a> с нуля, как разрешить его выполнение, как передавать параметры, запускать от имени администратора, настраивать через GPO и планировщик задач. Плюс — типичные ошибки и как их лечить. После прочтения у вас будет готовая база для автоматизации любой рутины в <a class="wpil_keyword_link" href="https://it-apteka.com/category/windows-server/" target="_blank" rel="noopener" title="Windows Server" data-wpil-keyword-link="linked" data-wpil-monitor-id="807">Windows</a>-инфраструктуре.</p>
<h2>Что такое PowerShell скрипт и зачем он вам нужен</h2>
<p>PowerShell — это не просто командная строка на стероидах. Это полноценная среда автоматизации с доступом к .NET, WMI, COM-объектам и REST API. <strong>Файл скрипта PowerShell</strong> — это текстовый файл с расширением <code>.ps1</code>, содержащий набор команд (командлетов), которые выполняются последовательно.</p>
<p>Где применяются PowerShell скрипты в реальной жизни:</p>
<ul>
<li>Автоматическое создание и настройка учётных записей пользователей в Active Directory</li>
<li>Мониторинг состояния служб и автоматический рестарт при падении</li>
<li>Резервное копирование файлов и баз данных по расписанию</li>
<li>Инвентаризация оборудования и ПО по всему парку машин</li>
<li>Настройка Windows при развёртывании через GPO</li>
<li>Генерация отчётов и рассылка их на email</li>
</ul>
<p>Одна правильно написанная автоматизация экономит часы ежедневной рутины. Начнём с основ.</p>
<h2>Расширение и файл PowerShell скрипта: где хранить и как называть</h2>
<p><strong>Расширение PowerShell скрипта</strong> — всегда <code>.ps1</code>. Без вариантов. Именно по этому расширению Windows понимает, что файл нужно запускать через PowerShell, а не открывать блокнотом.</p>
<h3>Где хранить скрипты</h3>
<p>Хаотичное хранение скриптов по рабочему столу и папке «Загрузки» — первый признак будущей катастрофы. Используйте структурированный <strong>каталог скриптов PowerShell</strong>:</p>
<pre><code class="language-bash">
# Рекомендуемая структура папок
C:\Scripts\ # корневая папка
C:\Scripts\AD\ # скрипты для Active Directory
C:\Scripts\Backup\ # резервное копирование
C:ScriptsMonitoring # <a class="wpil_keyword_link" href="https://it-apteka.com/category/monitoring/" target="_blank" rel="noopener" title="Мониторинг" data-wpil-keyword-link="linked" data-wpil-monitor-id="808">мониторинг</a>
C:\Scripts\Maintenance\ # обслуживание системы
</code></pre>
<p>Для корпоративной среды используйте сетевой ресурс: <code>\\server\scripts\</code>. Это упрощает централизованное управление и обновление скриптов на всех машинах.</p>
<h3>Как создать файл скрипта PowerShell</h3>
<p>Три способа — выбирайте под ситуацию:</p>
<pre><code class="language-bash">
# Способ 1: Через блокнот
notepad C:\Scripts\test.ps1
# Способ 2: Через PowerShell (создаёт пустой файл)
New-Item -Path C:\Scripts\test.ps1 -ItemType File
# Способ 3: Создать и сразу записать содержимое
Set-Content -Path C:\Scripts\test.ps1 -Value 'Write-Host "Hello IT World"'
</code></pre>
<p>Для серьёзной работы используйте <strong>PowerShell ISE</strong> (встроен в Windows) или <strong>VS Code с расширением PowerShell</strong> — там есть подсветка синтаксиса, автодополнение и отладчик.</p>
<h2>Как написать PowerShell скрипт: от Hello World до боевого примера</h2>
<p>Начнём с простого и сразу перейдём к полезному.</p>
<h3>Простейший скрипт</h3>
<pre><code class="language-bash">
# Файл: C:\Scripts\hello.ps1
Write-Host "Hello IT World" -ForegroundColor Green
Write-Host "Текущая дата: $(Get-Date)"
</code></pre>
<h3>Скрипт для мониторинга служб</h3>
<pre><code class="language-bash">
# Файл: C:\Scripts\Monitoring\check-services.ps1
# Получаем все запущенные службы
$runningServices = Get-Service | Where-Object {$_.Status -eq "Running"}
Write-Host "Запущенных служб: $($runningServices.Count)" -ForegroundColor Cyan
# Проверяем критически важные службы
$criticalServices = @("wuauserv", "WinDefend", "Spooler")
foreach ($serviceName in $criticalServices) {
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($service.Status -ne "Running") {
Write-Host "ВНИМАНИЕ: Служба $serviceName не запущена!" -ForegroundColor Red
} else {
Write-Host "OK: $serviceName работает" -ForegroundColor Green
}
}
</code></pre>
<h3>Скрипт инвентаризации</h3>
<pre><code class="language-bash">
# Файл: C:\Scripts\inventory.ps1
$report = [PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
OS = (Get-WmiObject Win32_OperatingSystem).Caption
RAM_GB = [math]::Round((Get-WmiObject Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)
CPU = (Get-WmiObject Win32_Processor).Name
IPAddress = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -notlike "*Loopback*"}).IPAddress
}
$report | Format-Table -AutoSize
$report | Export-Csv -Path "C:\Scripts\inventory_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8
</code></pre>
<p>Последний скрипт — уже боевое оружие. Запустите его на 100 машинах через GPO, соберите CSV-файлы в одно место — и у вас готовая инвентаризация всего парка.</p>
<h2>Как запустить скрипт в PowerShell: все способы</h2>
<p>Написать скрипт — полдела. Нужно ещё уметь его запустить. Вот все рабочие варианты:</p>
<h3>Запуск из текущей папки</h3>
<pre><code class="language-bash">
# Перейти в папку со скриптом
cd C:\Scripts
# Запустить скрипт (точка-слэш обязательны!)
.\script.ps1
</code></pre>
<p><strong>Важно:</strong> точка и слэш перед именем файла — это не опечатка. Так PowerShell понимает, что запускать нужно файл из текущей директории, а не искать команду с таким именем.</p>
<h3>Запуск по полному пути</h3>
<pre><code class="language-bash">
# Полный путь без необходимости переходить в папку
C:\Scripts\script.ps1
# Или через оператор вызова &
& "C:\Scripts\My Script.ps1" # & нужен, если в пути есть пробелы
</code></pre>
<h3>Запуск через powershell.exe (из CMD или других программ)</h3>
<pre><code class="language-bash">
# Запуск из командной строки CMD
powershell.exe -File "C:\Scripts\script.ps1"
# С параметрами
powershell.exe -File "C:\Scripts\script.ps1" -param1 Value1
# Запуск команды напрямую без файла
powershell.exe -Command "Get-Process | Sort-Object CPU -Descending | Select-Object -First 10"
# Без окна (для планировщика задач)
powershell.exe -WindowStyle Hidden -File "C:\Scripts\backup.ps1"
</code></pre>
<h2>Разрешение выполнения скриптов: Execution Policy</h2>
<p>Вы написали скрипт, запускаете — и получаете красную надпись. Знакомо? Это <strong>Execution Policy</strong> — политика выполнения скриптов PowerShell, которая по умолчанию запрещает запуск всех <code>.ps1</code> файлов.</p>
<p>Это не баг, это фича безопасности. Но её нужно правильно настроить.</p>
<h3>Проверить текущую политику</h3>
<pre><code class="language-bash">
Get-ExecutionPolicy
# Проверить политику для всех областей
Get-ExecutionPolicy -List
</code></pre>
<h3>Уровни Execution Policy</h3>
<table>
<thead>
<tr>
<th>Политика</th>
<th>Описание</th>
<th>Когда использовать</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Restricted</strong></td>
<td>Скрипты запрещены полностью</td>
<td>По умолчанию на клиентах</td>
</tr>
<tr>
<td><strong>AllSigned</strong></td>
<td>Только подписанные скрипты</td>
<td>Корпоративная среда с PKI</td>
</tr>
<tr>
<td><strong>RemoteSigned</strong></td>
<td>Локальные скрипты без подписи, скачанные — с подписью</td>
<td>Оптимально для администраторов</td>
</tr>
<tr>
<td><strong>Unrestricted</strong></td>
<td>Всё разрешено</td>
<td>Только для тестов</td>
</tr>
<tr>
<td><strong>Bypass</strong></td>
<td>Полный обход политики</td>
<td>Разовый запуск в сессии</td>
</tr>
</tbody>
</table>
<h3>Как разрешить выполнение скриптов PowerShell</h3>
<pre><code class="language-bash">
# Рекомендуемая настройка для администраторов
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
# Только для текущего пользователя
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# Только для текущей сессии (не сохраняется, безопасно для тестов)
Set-ExecutionPolicy Bypass -Scope Process
# Разблокировать конкретный скрипт, скачанный из интернета
Unblock-File -Path "C:\Scripts\downloaded-script.ps1"
</code></pre>
<p><strong>Совет для корпоративной среды:</strong> не меняйте политику вручную на каждой машине — используйте GPO. Путь: <em>Computer Configuration → Windows Settings → Security Settings → Software Restriction Policies</em>. Или через параметры PowerShell в GPO.</p>
<h2>Передача параметров в PowerShell скрипт</h2>
<p>Скрипт без параметров <a title="Запуск скрипта установки Microsoft DirectX, .NET Framework и VC++ в Steam - что это и как исправить зависание" href="https://it-apteka.com/zapusk-skripta-ustanovki-microsoft-directx-net-framework-i-vc-v-steam-chto-jeto-i-kak-ispravit-zavisanie/" target="_blank" rel="noopener" data-wpil-monitor-id="797">—</a> это скрипт для одной задачи. Скрипт с параметрами — это инструмент. Научитесь использовать блок <code>param()</code> — и ваши скрипты станут универсальными.</p>
<h3>Базовый пример с параметрами</h3>
<pre><code class="language-bash">
# Файл: C:\Scripts\create-user.ps1
param(
[Parameter(Mandatory=$true)]
[string]$Username,
[Parameter(Mandatory=$true)]
[string]$Department,
[string]$Manager = "admin", # значение по умолчанию
[switch]$SendEmail # флаг (true/false)
)
Write-Host "Создаём пользователя: $Username"
Write-Host "Отдел: $Department"
Write-Host "Руководитель: $Manager"
if ($SendEmail) {
Write-Host "Уведомление будет отправлено"
}
</code></pre>
<h3>Запуск скрипта с параметрами</h3>
<pre><code class="language-bash">
# Запуск с именованными параметрами (рекомендуется)
.\create-user.ps1 -Username "ivanov" -Department "IT" -SendEmail
# Запуск по позиции (если параметры объявлены в нужном порядке)
.\create-user.ps1 "ivanov" "IT"
# Передача параметров через powershell.exe
powershell.exe -File "C:\Scripts\create-user.ps1" -Username "petrov" -Department "HR"
</code></pre>
<h3>Продвинутая валидация параметров</h3>
<pre><code class="language-bash">
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$ServerName,
[Parameter(Mandatory=$true)]
[ValidateRange(1, 65535)]
[int]$Port = 80,
[ValidateSet("HTTP", "HTTPS", "FTP")]
[string]$Protocol = "HTTPS"
)
Write-Host "Проверяем $Protocol://${ServerName}:$Port"
</code></pre>
<p>Атрибут <code>ValidateSet</code> не только проверяет значение, но и обеспечивает автодополнение в PowerShell ISE и VS Code. Используйте его везде, где возможно.</p>
<h2>Запуск PowerShell скрипта от имени администратора</h2>
<p>Многие операции требуют прав администратора: изменение реестра, управление службами, работа с сетевыми адаптерами. Вот как это правильно организовать.</p>
<h3>Запуск с повышенными правами вручную</h3>
<pre><code class="language-bash">
# Запустить новый сеанс PowerShell от имени администратора
Start-Process powershell -Verb runAs
# Запустить конкретный скрипт от имени администратора
Start-Process powershell -Verb runAs -ArgumentList "-File C:\Scripts\script.ps1"
</code></pre>
<h3>Проверка прав внутри скрипта</h3>
<pre><code class="language-bash">
# Добавьте это в начало скриптов, требующих прав администратора
#Requires -RunAsAdministrator
# Или проверка вручную с автоперезапуском
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "Требуются права администратора. Перезапускаем..." -ForegroundColor Yellow
Start-Process powershell -Verb runAs -ArgumentList "-File `"$PSCommandPath`""
exit
}
Write-Host "Права администратора подтверждены. Продолжаем..." -ForegroundColor Green
# Основной код скрипта здесь
</code></pre>
<p>Директива <code>#Requires -RunAsAdministrator</code> — самый чистый способ. PowerShell автоматически откажет в запуске с понятным сообщением об ошибке, если права недостаточны.</p>
<h2>Автоматизация через планировщик задач Windows</h2>
<p>Скрипт, который запускается руками — это полуавтоматизация. Настоящая <a href="https://it-apteka.com/avtomatizacija-ssl-dlja-desjatkov-domenov-cherez-acme-sh-i-dns-api-bez-certbot/" target="_blank" rel="noopener" data-wpil-monitor-id="864">автоматизация — это когда скрипт</a> работает сам, пока вы спите.</p>
<h3>Настройка через графический интерфейс</h3>
<p>Открываем <strong>Task Scheduler</strong> (taskschd.msc) → Create Task → вкладка Actions → New:</p>
<ul>
<li>Program/script: <code>powershell.exe</code></li>
<li>Add arguments: <code>-WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Scripts\backup.ps1"</code></li>
</ul>
<h3>Создание задачи через PowerShell (правильный путь)</h3>
<pre><code class="language-bash">
# Создаём задачу для ежедневного резервного копирования в 2:00
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"C:Scripts<a class="wpil_keyword_link" href="https://it-apteka.com/category/rezervnoe-kopirovanie/" target="_blank" rel="noopener" title="Резервное копирование" data-wpil-keyword-link="linked" data-wpil-monitor-id="809">Backup</a>daily-backup.ps1`""
$trigger = New-ScheduledTaskTrigger `
-Daily `
-At "02:00AM"
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Hours 2) `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 5)
$principal = New-ScheduledTaskPrincipal `
-UserId "SYSTEM" `
-RunLevel Highest
Register-ScheduledTask `
-TaskName "DailyBackup" `
-TaskPath "\IT-Scripts\" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description "Ежедневное резервное копирование данных"
Write-Host "Задача 'DailyBackup' успешно создана!" -ForegroundColor Green
</code></pre>
<h3>Полезные сценарии для планировщика</h3>
<table>
<thead>
<tr>
<th>Задача</th>
<th>Расписание</th>
<th>Скрипт</th>
</tr>
</thead>
<tbody>
<tr>
<td>Резервное копирование</td>
<td>Ежедневно в 02:00</td>
<td>backup.ps1</td>
</tr>
<tr>
<td>Очистка логов</td>
<td>Еженедельно в воскресенье</td>
<td>cleanup-logs.ps1</td>
</tr>
<tr>
<td>Проверка служб</td>
<td>Каждые 15 минут</td>
<td>check-services.ps1</td>
</tr>
<tr>
<td>Инвентаризация</td>
<td>Ежемесячно 1-го числа</td>
<td>inventory.ps1</td>
</tr>
<tr>
<td>Обновление отчётов</td>
<td>По рабочим дням в 08:00</td>
<td>generate-report.ps1</td>
</tr>
</tbody>
</table>
<h2>PowerShell скрипты через GPO: автоматизация в домене</h2>
<p>Если у вас домен Active Directory — GPO превращает PowerShell в инструмент массового развёртывания. Один скрипт, запущенный при входе пользователей или старте компьютеров, может настроить всю инфраструктуру.</p>
<h3>Где настраивается запуск скриптов через GPO</h3>
<p>В Group Policy Management Console (gpmc.msc) существует два основных места:</p>
<ul>
<li><strong>Startup/Shutdown скрипты (компьютерные):</strong><br />
Computer Configuration → Windows Settings → Scripts (Startup/Shutdown)</li>
<li><strong>Logon/Logoff скрипты (пользовательские):</strong><br />
User Configuration → Windows Settings → Scripts (Logon/Logoff)</li>
</ul>
<h3>Добавление PowerShell скрипта в GPO</h3>
<ol>
<li>Создайте или откройте GPO в Group Policy Management</li>
<li>Перейдите: Computer Configuration → Windows Settings → Scripts → Startup</li>
<li>Нажмите Add → Browse → выберите <code>.ps1</code> файл</li>
<li>В поле «Script Parameters» укажите параметры при необходимости</li>
<li>Примените GPO к нужным OU</li>
</ol>
<h3>Пример скрипта для GPO (маппинг сетевых дисков)</h3>
<pre><code class="language-bash">
# Файл: \\domain\sysvol\domain\Policies\{GUID}\User\Scripts\Logon\map-drives.ps1
# Запускается при входе пользователя через GPO
param(
[string]$UserGroup = $env:USERNAME
)
# Подключаем сетевые диски в зависимости от группы пользователя
$userGroups = (New-Object System.DirectoryServices.DirectorySearcher(
"(&(objectCategory=user)(sAMAccountName=$env:USERNAME))"
)).FindOne().Properties.memberof
# Общий диск для всех
if (!(Test-Path "Z:")) {
New-PSDrive -Name "Z" -PSProvider FileSystem -Root "\\fileserver\shared" -Persist
}
# Диск для IT-отдела
if ($userGroups -like "*IT-Department*") {
if (!(Test-Path "Y:")) {
New-PSDrive -Name "Y" -PSProvider FileSystem -Root "\\fileserver\IT" -Persist
}
}
Write-Host "Сетевые диски подключены" -ForegroundColor Green
</code></pre>
<h3>Примеры реальных задач для GPO-скриптов</h3>
<ul>
<li>Автоматическая установка и обновление программного обеспечения</li>
<li><a href="https://it-apteka.com/nastrojka-rdp-udaljonnyj-rabochij-stol-na-windows-linux-i-mac-ot-vkljuchenija-do-pervogo-seansa/" target="_blank" rel="noopener" data-wpil-monitor-id="1264">Настройка параметров безопасности Windows</a></li>
<li>Очистка временных файлов при выходе пользователя</li>
<li>Инвентаризация оборудования при старте ПК</li>
<li>Настройка принтеров по умолчанию</li>
<li>Установка политик брандмауэра</li>
</ul>
<p><strong>Важно для GPO:</strong> скрипты должны быть размещены в SYSVOL (<code>\\domain\sysvol\domain\Scripts\</code>) для автоматической репликации на все контроллеры домена.</p>
<h2>Подпись PowerShell скриптов</h2>
<p>В корпоративной среде с политикой <code>AllSigned</code> неподписанный скрипт просто не запустится. Цифровая подпись гарантирует, что скрипт не был изменён после подписания.</p>
<h3>Создание самоподписанного сертификата (для тестов)</h3>
<pre><code class="language-bash">
# Создаём сертификат для подписи кода
$cert = New-SelfSignedCertificate `
-Type CodeSigningCert `
-Subject "CN=PowerShell Code Signing" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-FriendlyName "PS Code Signing"
Write-Host "Сертификат создан: $($cert.Thumbprint)"
</code></pre>
<h3>Подписать PowerShell скрипт</h3>
<pre><code class="language-bash">
# Получаем сертификат
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
# Подписываем скрипт
$result = Set-AuthenticodeSignature `
-FilePath "C:\Scripts\script.ps1" `
-Certificate $cert `
-TimestampServer "http://timestamp.digicert.com"
if ($result.Status -eq "Valid") {
Write-Host "Скрипт успешно подписан!" -ForegroundColor Green
} else {
Write-Host "Ошибка подписания: $($result.StatusMessage)" -ForegroundColor Red
}
# Проверить подпись скрипта
Get-AuthenticodeSignature -FilePath "C:\Scripts\script.ps1"
</code></pre>
<p><strong>Для продакшена</strong> используйте сертификат от корпоративного CA (Certificate Authority) или коммерческого издателя — самоподписанные сертификаты нужно дополнительно добавлять в доверенные хранилища.</p>
<hr />
<h2>⚡ Где запускать скрипты: облако или свой сервер?</h2>
<p>Если вы запускаете PowerShell-автоматизацию для облачной инфраструктуры или хотите иметь надёжный сервер для расписания задач — вопрос выбора VPS встаёт ребром. Вот быстрое сравнение популярных платформ:</p>
<table>
<thead>
<tr>
<th>Провайдер</th>
<th>Минимальный тариф</th>
<th>Windows Server</th>
<th>SLA</th>
</tr>
</thead>
<tbody>
<tr>
<td>Timeweb Cloud</td>
<td>от 199 руб/мес</td>
<td>✅ Есть</td>
<td>99.95%</td>
</tr>
<tr>
<td>Selectel</td>
<td>от 230 руб/мес</td>
<td>✅ Есть</td>
<td>99.95%</td>
</tr>
<tr>
<td>Cloud.ru</td>
<td>от 150 руб/мес</td>
<td>✅ Есть</td>
<td>99.95%</td>
</tr>
<tr>
<td>Reg.ru</td>
<td>от 179 руб/мес</td>
<td>✅ Есть</td>
<td>99.9%</td>
</tr>
</tbody>
</table>
<p>Для запуска PowerShell-скриптов по расписанию достаточно минимального VPS с <a href="https://it-apteka.com/powershell-skripty-na-kazhdyj-den-dlya-setevogo/" title="PowerShell-скрипты на каждый день для сетевого инженера" target="_blank" rel="noopener" data-wpil-monitor-id="2008">Windows Server</a>. Главное — выбирайте провайдера с поддержкой Windows Server 2019/2022 и SLA не ниже 99.9%.</p>
<hr />
<h2>Готовые примеры PowerShell скриптов для ежедневной работы</h2>
<h3>Получить IP-адреса сервера</h3>
<pre><code class="language-bash">
# Все IPv4 адреса, кроме loopback
Get-NetIPAddress -AddressFamily IPv4 |
Where-Object {$_.InterfaceAlias -notlike "*Loopback*"} |
Select-Object InterfaceAlias, IPAddress, PrefixLength |
Format-Table -AutoSize
</code></pre>
<h3>Список процессов с высоким потреблением CPU</h3>
<pre><code class="language-bash">
# Топ-10 процессов по CPU
Get-Process |
Sort-Object CPU -Descending |
Select-Object -First 10 Name, CPU, WorkingSet |
Format-Table -AutoSize
</code></pre>
<h3>Проверка и перезапуск службы</h3>
<pre><code class="language-bash">
# Функция для проверки и перезапуска службы
function Ensure-ServiceRunning {
param([string]$ServiceName)
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($null -eq $service) {
Write-Host "Служба '$ServiceName' не найдена!" -ForegroundColor Red
return
}
if ($service.Status -ne "Running") {
Write-Host "Служба $ServiceName остановлена. Запускаем..." -ForegroundColor Yellow
Start-Service -Name $ServiceName
Start-Sleep -Seconds 3
$service.Refresh()
if ($service.Status -eq "Running") {
Write-Host "Служба $ServiceName успешно запущена!" -ForegroundColor Green
} else {
Write-Host "Не удалось запустить службу $ServiceName!" -ForegroundColor Red
}
} else {
Write-Host "Служба $ServiceName работает нормально." -ForegroundColor Green
}
}
# Использование
Ensure-ServiceRunning -ServiceName "Spooler"
Ensure-ServiceRunning -ServiceName "wuauserv"
</code></pre>
<h3>Скрипт резервного копирования</h3>
<pre><code class="language-bash">
# Файл: C:\Scripts\Backup\daily-backup.ps1
param(
[string]$SourcePath = "C:\Data",
[string]$BackupRoot = "D:\Backups",
[int]$RetentionDays = 30
)
$date = Get-Date -Format "yyyy-MM-dd_HH-mm"
$backupPath = Join-Path $BackupRoot $date
# Создаём папку для бэкапа
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null
# Копируем файлы
Write-Host "Начинаем резервное копирование: $SourcePath -> $backupPath"
Copy-Item -Path $SourcePath -Destination $backupPath -Recurse -Force
# Архивируем
$archivePath = "$backupPath.zip"
Compress-Archive -Path $backupPath -DestinationPath $archivePath -Force
Remove-Item -Path $backupPath -Recurse -Force
# Удаляем старые бэкапы
$oldBackups = Get-ChildItem $BackupRoot -Filter "*.zip" |
Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-$RetentionDays)}
if ($oldBackups.Count -gt 0) {
$oldBackups | Remove-Item -Force
Write-Host "Удалено старых бэкапов: $($oldBackups.Count)" -ForegroundColor Yellow
}
$archiveSize = [math]::Round((Get-Item $archivePath).Length / 1MB, 2)
Write-Host "Бэкап создан: $archivePath ($archiveSize MB)" -ForegroundColor Green
</code></pre>
<h2>Типичные ошибки при запуске PowerShell скриптов и как их лечить</h2>
<h3>Ошибка: «running scripts is disabled on this system»</h3>
<p><strong>Причина:</strong> Execution Policy запрещает запуск скриптов.<br />
<strong>Лечение:</strong></p>
<pre><code class="language-bash">
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# или для текущей сессии:
Set-ExecutionPolicy Bypass -Scope Process
</code></pre>
<h3>Ошибка: «File cannot be loaded because the file is not digitally signed»</h3>
<p><strong>Причина:</strong> Политика AllSigned, скрипт не подписан.<br />
<strong>Лечение:</strong></p>
<pre><code class="language-bash">
# Вариант 1: подписать скрипт (рекомендуется для корпоративной среды)
Set-AuthenticodeSignature -FilePath .\script.ps1 -Certificate $cert
# Вариант 2: разблокировать файл (для скачанных скриптов)
Unblock-File -Path .\script.ps1
# Вариант 3: изменить политику (только при наличии прав)
Set-ExecutionPolicy RemoteSigned
</code></pre>
<h3>Ошибка: «Access to the path is denied»</h3>
<p><strong>Причина:</strong> Недостаточно прав для выполнения операции.<br />
<strong>Лечение:</strong></p>
<pre><code class="language-bash">
# Запустить PowerShell от имени администратора и повторить
# Или добавить в начало скрипта:
#Requires -RunAsAdministrator
</code></pre>
<h3>Ошибка: «The term ‘X’ is not recognized»</h3>
<p><strong>Причина:</strong> <a title="Docker Compose - установка, команды и настройка контейнеров" href="https://it-apteka.com/docker-compose-ustanovka-komandy-i-nastrojka-kontejnerov/" target="_blank" rel="noopener" data-wpil-monitor-id="798">Команда не найдена —</a> не установлен модуль или опечатка.<br />
<strong>Лечение:</strong></p>
<pre><code class="language-bash">
# Поиск нужного командлета
Get-Command *keyword*
# Установка модуля (например, для работы с AD)
Install-Module -Name ActiveDirectory
# Импорт модуля
Import-Module ActiveDirectory
</code></pre>
<h3>Ошибка: Кодировка — кириллица отображается кракозябрами</h3>
<pre><code class="language-bash">
# Установить правильную кодировку в начале скрипта
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
# Сохранять .ps1 файлы в кодировке UTF-8 with BOM через VS Code или ISE
</code></pre>
<h2>Профилактика и лучшие практики: пишем скрипты как профи</h2>
<p>Хороший <a href="https://it-apteka.com/rezervnoe-kopirovanie-mikrotik-routeros-7-v-telegram-avtomatizacija-za-20-minut/" title="Резервное копирование MikroTik RouterOS 7 в Telegram: рабочий скрипт и разбор ошибок" target="_blank" rel="noopener" data-wpil-monitor-id="2189">скрипт — это не только рабочий</a> код. Это код, который понятен через 6 месяцев и не сломает систему при ошибке.</p>
<h3>Обязательные элементы каждого скрипта</h3>
<pre><code class="language-bash">
<#
.SYNOPSIS
Краткое описание скрипта
.DESCRIPTION
Подробное описание того, что делает скрипт
.PARAMETER ServerName
Имя сервера для проверки
.EXAMPLE
.\script.ps1 -ServerName "webserver01"
.NOTES
Автор: Ivan Ivanov
Дата: 2024-01-15
Версия: 1.0
#>
#Requires -Version 5.1
#Requires -RunAsAdministrator
param(
[Parameter(Mandatory=$true)]
[string]$ServerName
)
# Включить строгий режим - поймает необъявленные переменные
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# Логирование
$logFile = "C:\Scripts\Logs\$(Split-Path $PSCommandPath -Leaf)_$(Get-Date -Format 'yyyyMMdd').log"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp [$Level] $Message" | Tee-Object -FilePath $logFile -Append
}
# Основной код в блоке try-catch
try {
Write-Log "Скрипт запущен. Параметры: ServerName=$ServerName"
# Ваш код здесь
Write-Log "Скрипт выполнен успешно"
}
catch {
Write-Log "ОШИБКА: $_" -Level "ERROR"
exit 1
}
</code></pre>
<h3>Чеклист качества PowerShell скрипта</h3>
<ul>
<li>✅ Есть блок <code>param()</code> с типизированными параметрами</li>
<li>✅ Есть документация в формате <code>.SYNOPSIS</code> / <code>.DESCRIPTION</code></li>
<li>✅ Код обёрнут в <code>try-catch</code> с обработкой ошибок</li>
<li>✅ Есть логирование в файл</li>
<li>✅ Указаны зависимости через <code>#Requires</code></li>
<li>✅ Файл сохранён в кодировке UTF-8</li>
<li>✅ Скрипт протестирован с параметром <code>-WhatIf</code> перед боевым запуском</li>
<li>✅ Хранится в системе контроля версий (<a class="wpil_keyword_link" href="https://it-apteka.com/tag/git/" target="_blank" rel="noopener" title="Git" data-wpil-keyword-link="linked" data-wpil-monitor-id="805">Git</a>)</li>
</ul>
<h2>Итог: ваш PowerShell арсенал готов к бою</h2>
<p>Мы прошли полный путь: от создания первого <code>.ps1</code> файла до корпоративного развёртывания через GPO. Теперь у вас есть:</p>
<ul>
<li>Понимание структуры и лучших практик написания скриптов</li>
<li>Все способы запуска — вручную, через планировщик, через GPO</li>
<li>Готовые шаблоны для мониторинга, бэкапа и управления службами</li>
<li>Методы решения типичных ошибок</li>
<li>Основы подписи скриптов для корпоративной среды</li>
</ul>
<p><strong>PowerShell — это инвестиция.</strong> Потратьте день на написание правильных скриптов и сэкономьте недели рутинной работы в течение года.</p>
<p>Если возникли вопросы или нужна помощь с конкретным скриптом — пишите в комментарии. Разберём вместе. Подпишитесь на наш <a class="wpil_keyword_link" href="https://t.me/it_apteka_com/34" target="_blank" rel="noopener" title="Telegram" data-wpil-keyword-link="linked" data-wpil-monitor-id="806">Telegram</a>-канал, чтобы не пропустить следующие рецепты из IT-аптеки.</p>
Сервер ночью сам не почистит логи. Учётки в AD сами себя не заведут. Бэкапы не сделаются по щелчку пальца — если, конечно, вы не написали скрипт. PowerShell скрипты — это не просто удобство, это разница между «я администратор» и «я автоматизатор, который уходит домой вовремя».
В этом гайде — всё по делу: как создать PowerShell скрипт с нуля, как разрешить его выполнение, как передавать параметры, запускать от имени администратора, настраивать через GPO и планировщик задач. Плюс — типичные ошибки и как их лечить. После прочтения у вас будет готовая база для автоматизации любой рутины в Windows-инфраструктуре.
Что такое PowerShell скрипт и зачем он вам нужен
PowerShell — это не просто командная строка на стероидах. Это полноценная среда автоматизации с доступом к .NET, WMI, COM-объектам и REST API. Файл скрипта PowerShell — это текстовый файл с расширением .ps1, содержащий набор команд (командлетов), которые выполняются последовательно.
Где применяются PowerShell скрипты в реальной жизни:
- Автоматическое создание и настройка учётных записей пользователей в Active Directory
- Мониторинг состояния служб и автоматический рестарт при падении
- Резервное копирование файлов и баз данных по расписанию
- Инвентаризация оборудования и ПО по всему парку машин
- Настройка Windows при развёртывании через GPO
- Генерация отчётов и рассылка их на email
Одна правильно написанная автоматизация экономит часы ежедневной рутины. Начнём с основ.
Расширение и файл PowerShell скрипта: где хранить и как называть
Расширение PowerShell скрипта — всегда .ps1. Без вариантов. Именно по этому расширению Windows понимает, что файл нужно запускать через PowerShell, а не открывать блокнотом.
Где хранить скрипты
Хаотичное хранение скриптов по рабочему столу и папке «Загрузки» — первый признак будущей катастрофы. Используйте структурированный каталог скриптов PowerShell:
# Рекомендуемая структура папок
C:\Scripts\ # корневая папка
C:\Scripts\AD\ # скрипты для Active Directory
C:\Scripts\Backup\ # резервное копирование
C:ScriptsMonitoring # мониторинг
C:\Scripts\Maintenance\ # обслуживание системы
Для корпоративной среды используйте сетевой ресурс: \\server\scripts\. Это упрощает централизованное управление и обновление скриптов на всех машинах.
Как создать файл скрипта PowerShell
Три способа — выбирайте под ситуацию:
# Способ 1: Через блокнот
notepad C:\Scripts\test.ps1
# Способ 2: Через PowerShell (создаёт пустой файл)
New-Item -Path C:\Scripts\test.ps1 -ItemType File
# Способ 3: Создать и сразу записать содержимое
Set-Content -Path C:\Scripts\test.ps1 -Value 'Write-Host "Hello IT World"'
Для серьёзной работы используйте PowerShell ISE (встроен в Windows) или VS Code с расширением PowerShell — там есть подсветка синтаксиса, автодополнение и отладчик.
Как написать PowerShell скрипт: от Hello World до боевого примера
Начнём с простого и сразу перейдём к полезному.
Простейший скрипт
# Файл: C:\Scripts\hello.ps1
Write-Host "Hello IT World" -ForegroundColor Green
Write-Host "Текущая дата: $(Get-Date)"
Скрипт для мониторинга служб
# Файл: C:\Scripts\Monitoring\check-services.ps1
# Получаем все запущенные службы
$runningServices = Get-Service | Where-Object {$_.Status -eq "Running"}
Write-Host "Запущенных служб: $($runningServices.Count)" -ForegroundColor Cyan
# Проверяем критически важные службы
$criticalServices = @("wuauserv", "WinDefend", "Spooler")
foreach ($serviceName in $criticalServices) {
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($service.Status -ne "Running") {
Write-Host "ВНИМАНИЕ: Служба $serviceName не запущена!" -ForegroundColor Red
} else {
Write-Host "OK: $serviceName работает" -ForegroundColor Green
}
}
Скрипт инвентаризации
# Файл: C:\Scripts\inventory.ps1
$report = [PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
OS = (Get-WmiObject Win32_OperatingSystem).Caption
RAM_GB = [math]::Round((Get-WmiObject Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)
CPU = (Get-WmiObject Win32_Processor).Name
IPAddress = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -notlike "*Loopback*"}).IPAddress
}
$report | Format-Table -AutoSize
$report | Export-Csv -Path "C:\Scripts\inventory_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8
Последний скрипт — уже боевое оружие. Запустите его на 100 машинах через GPO, соберите CSV-файлы в одно место — и у вас готовая инвентаризация всего парка.
Как запустить скрипт в PowerShell: все способы
Написать скрипт — полдела. Нужно ещё уметь его запустить. Вот все рабочие варианты:
Запуск из текущей папки
# Перейти в папку со скриптом
cd C:\Scripts
# Запустить скрипт (точка-слэш обязательны!)
.\script.ps1
Важно: точка и слэш перед именем файла — это не опечатка. Так PowerShell понимает, что запускать нужно файл из текущей директории, а не искать команду с таким именем.
Запуск по полному пути
# Полный путь без необходимости переходить в папку
C:\Scripts\script.ps1
# Или через оператор вызова &
& "C:\Scripts\My Script.ps1" # & нужен, если в пути есть пробелы
Запуск через powershell.exe (из CMD или других программ)
# Запуск из командной строки CMD
powershell.exe -File "C:\Scripts\script.ps1"
# С параметрами
powershell.exe -File "C:\Scripts\script.ps1" -param1 Value1
# Запуск команды напрямую без файла
powershell.exe -Command "Get-Process | Sort-Object CPU -Descending | Select-Object -First 10"
# Без окна (для планировщика задач)
powershell.exe -WindowStyle Hidden -File "C:\Scripts\backup.ps1"
Разрешение выполнения скриптов: Execution Policy
Вы написали скрипт, запускаете — и получаете красную надпись. Знакомо? Это Execution Policy — политика выполнения скриптов PowerShell, которая по умолчанию запрещает запуск всех .ps1 файлов.
Это не баг, это фича безопасности. Но её нужно правильно настроить.
Проверить текущую политику
Get-ExecutionPolicy
# Проверить политику для всех областей
Get-ExecutionPolicy -List
Уровни Execution Policy
| Политика |
Описание |
Когда использовать |
| Restricted |
Скрипты запрещены полностью |
По умолчанию на клиентах |
| AllSigned |
Только подписанные скрипты |
Корпоративная среда с PKI |
| RemoteSigned |
Локальные скрипты без подписи, скачанные — с подписью |
Оптимально для администраторов |
| Unrestricted |
Всё разрешено |
Только для тестов |
| Bypass |
Полный обход политики |
Разовый запуск в сессии |
Как разрешить выполнение скриптов PowerShell
# Рекомендуемая настройка для администраторов
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
# Только для текущего пользователя
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# Только для текущей сессии (не сохраняется, безопасно для тестов)
Set-ExecutionPolicy Bypass -Scope Process
# Разблокировать конкретный скрипт, скачанный из интернета
Unblock-File -Path "C:\Scripts\downloaded-script.ps1"
Совет для корпоративной среды: не меняйте политику вручную на каждой машине — используйте GPO. Путь: Computer Configuration → Windows Settings → Security Settings → Software Restriction Policies. Или через параметры PowerShell в GPO.
Передача параметров в PowerShell скрипт
Скрипт без параметров — это скрипт для одной задачи. Скрипт с параметрами — это инструмент. Научитесь использовать блок param() — и ваши скрипты станут универсальными.
Базовый пример с параметрами
# Файл: C:\Scripts\create-user.ps1
param(
[Parameter(Mandatory=$true)]
[string]$Username,
[Parameter(Mandatory=$true)]
[string]$Department,
[string]$Manager = "admin", # значение по умолчанию
[switch]$SendEmail # флаг (true/false)
)
Write-Host "Создаём пользователя: $Username"
Write-Host "Отдел: $Department"
Write-Host "Руководитель: $Manager"
if ($SendEmail) {
Write-Host "Уведомление будет отправлено"
}
Запуск скрипта с параметрами
# Запуск с именованными параметрами (рекомендуется)
.\create-user.ps1 -Username "ivanov" -Department "IT" -SendEmail
# Запуск по позиции (если параметры объявлены в нужном порядке)
.\create-user.ps1 "ivanov" "IT"
# Передача параметров через powershell.exe
powershell.exe -File "C:\Scripts\create-user.ps1" -Username "petrov" -Department "HR"
Продвинутая валидация параметров
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$ServerName,
[Parameter(Mandatory=$true)]
[ValidateRange(1, 65535)]
[int]$Port = 80,
[ValidateSet("HTTP", "HTTPS", "FTP")]
[string]$Protocol = "HTTPS"
)
Write-Host "Проверяем $Protocol://${ServerName}:$Port"
Атрибут ValidateSet не только проверяет значение, но и обеспечивает автодополнение в PowerShell ISE и VS Code. Используйте его везде, где возможно.
Запуск PowerShell скрипта от имени администратора
Многие операции требуют прав администратора: изменение реестра, управление службами, работа с сетевыми адаптерами. Вот как это правильно организовать.
Запуск с повышенными правами вручную
# Запустить новый сеанс PowerShell от имени администратора
Start-Process powershell -Verb runAs
# Запустить конкретный скрипт от имени администратора
Start-Process powershell -Verb runAs -ArgumentList "-File C:\Scripts\script.ps1"
Проверка прав внутри скрипта
# Добавьте это в начало скриптов, требующих прав администратора
#Requires -RunAsAdministrator
# Или проверка вручную с автоперезапуском
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "Требуются права администратора. Перезапускаем..." -ForegroundColor Yellow
Start-Process powershell -Verb runAs -ArgumentList "-File `"$PSCommandPath`""
exit
}
Write-Host "Права администратора подтверждены. Продолжаем..." -ForegroundColor Green
# Основной код скрипта здесь
Директива #Requires -RunAsAdministrator — самый чистый способ. PowerShell автоматически откажет в запуске с понятным сообщением об ошибке, если права недостаточны.
Автоматизация через планировщик задач Windows
Скрипт, который запускается руками — это полуавтоматизация. Настоящая автоматизация — это когда скрипт работает сам, пока вы спите.
Настройка через графический интерфейс
Открываем Task Scheduler (taskschd.msc) → Create Task → вкладка Actions → New:
- Program/script:
powershell.exe
- Add arguments:
-WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Scripts\backup.ps1"
Создание задачи через PowerShell (правильный путь)
# Создаём задачу для ежедневного резервного копирования в 2:00
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"C:ScriptsBackupdaily-backup.ps1`""
$trigger = New-ScheduledTaskTrigger `
-Daily `
-At "02:00AM"
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Hours 2) `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 5)
$principal = New-ScheduledTaskPrincipal `
-UserId "SYSTEM" `
-RunLevel Highest
Register-ScheduledTask `
-TaskName "DailyBackup" `
-TaskPath "\IT-Scripts\" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description "Ежедневное резервное копирование данных"
Write-Host "Задача 'DailyBackup' успешно создана!" -ForegroundColor Green
Полезные сценарии для планировщика
| Задача |
Расписание |
Скрипт |
| Резервное копирование |
Ежедневно в 02:00 |
backup.ps1 |
| Очистка логов |
Еженедельно в воскресенье |
cleanup-logs.ps1 |
| Проверка служб |
Каждые 15 минут |
check-services.ps1 |
| Инвентаризация |
Ежемесячно 1-го числа |
inventory.ps1 |
| Обновление отчётов |
По рабочим дням в 08:00 |
generate-report.ps1 |
PowerShell скрипты через GPO: автоматизация в домене
Если у вас домен Active Directory — GPO превращает PowerShell в инструмент массового развёртывания. Один скрипт, запущенный при входе пользователей или старте компьютеров, может настроить всю инфраструктуру.
Где настраивается запуск скриптов через GPO
В Group Policy Management Console (gpmc.msc) существует два основных места:
- Startup/Shutdown скрипты (компьютерные):
Computer Configuration → Windows Settings → Scripts (Startup/Shutdown)
- Logon/Logoff скрипты (пользовательские):
User Configuration → Windows Settings → Scripts (Logon/Logoff)
Добавление PowerShell скрипта в GPO
- Создайте или откройте GPO в Group Policy Management
- Перейдите: Computer Configuration → Windows Settings → Scripts → Startup
- Нажмите Add → Browse → выберите
.ps1 файл
- В поле «Script Parameters» укажите параметры при необходимости
- Примените GPO к нужным OU
Пример скрипта для GPO (маппинг сетевых дисков)
# Файл: \\domain\sysvol\domain\Policies\{GUID}\User\Scripts\Logon\map-drives.ps1
# Запускается при входе пользователя через GPO
param(
[string]$UserGroup = $env:USERNAME
)
# Подключаем сетевые диски в зависимости от группы пользователя
$userGroups = (New-Object System.DirectoryServices.DirectorySearcher(
"(&(objectCategory=user)(sAMAccountName=$env:USERNAME))"
)).FindOne().Properties.memberof
# Общий диск для всех
if (!(Test-Path "Z:")) {
New-PSDrive -Name "Z" -PSProvider FileSystem -Root "\\fileserver\shared" -Persist
}
# Диск для IT-отдела
if ($userGroups -like "*IT-Department*") {
if (!(Test-Path "Y:")) {
New-PSDrive -Name "Y" -PSProvider FileSystem -Root "\\fileserver\IT" -Persist
}
}
Write-Host "Сетевые диски подключены" -ForegroundColor Green
Примеры реальных задач для GPO-скриптов
- Автоматическая установка и обновление программного обеспечения
- Настройка параметров безопасности Windows
- Очистка временных файлов при выходе пользователя
- Инвентаризация оборудования при старте ПК
- Настройка принтеров по умолчанию
- Установка политик брандмауэра
Важно для GPO: скрипты должны быть размещены в SYSVOL (\\domain\sysvol\domain\Scripts\) для автоматической репликации на все контроллеры домена.
Подпись PowerShell скриптов
В корпоративной среде с политикой AllSigned неподписанный скрипт просто не запустится. Цифровая подпись гарантирует, что скрипт не был изменён после подписания.
Создание самоподписанного сертификата (для тестов)
# Создаём сертификат для подписи кода
$cert = New-SelfSignedCertificate `
-Type CodeSigningCert `
-Subject "CN=PowerShell Code Signing" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-FriendlyName "PS Code Signing"
Write-Host "Сертификат создан: $($cert.Thumbprint)"
Подписать PowerShell скрипт
# Получаем сертификат
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
# Подписываем скрипт
$result = Set-AuthenticodeSignature `
-FilePath "C:\Scripts\script.ps1" `
-Certificate $cert `
-TimestampServer "http://timestamp.digicert.com"
if ($result.Status -eq "Valid") {
Write-Host "Скрипт успешно подписан!" -ForegroundColor Green
} else {
Write-Host "Ошибка подписания: $($result.StatusMessage)" -ForegroundColor Red
}
# Проверить подпись скрипта
Get-AuthenticodeSignature -FilePath "C:\Scripts\script.ps1"
Для продакшена используйте сертификат от корпоративного CA (Certificate Authority) или коммерческого издателя — самоподписанные сертификаты нужно дополнительно добавлять в доверенные хранилища.
⚡ Где запускать скрипты: облако или свой сервер?
Если вы запускаете PowerShell-автоматизацию для облачной инфраструктуры или хотите иметь надёжный сервер для расписания задач — вопрос выбора VPS встаёт ребром. Вот быстрое сравнение популярных платформ:
| Провайдер |
Минимальный тариф |
Windows Server |
SLA |
| Timeweb Cloud |
от 199 руб/мес |
✅ Есть |
99.95% |
| Selectel |
от 230 руб/мес |
✅ Есть |
99.95% |
| Cloud.ru |
от 150 руб/мес |
✅ Есть |
99.95% |
| Reg.ru |
от 179 руб/мес |
✅ Есть |
99.9% |
Для запуска PowerShell-скриптов по расписанию достаточно минимального VPS с Windows Server. Главное — выбирайте провайдера с поддержкой Windows Server 2019/2022 и SLA не ниже 99.9%.
Готовые примеры PowerShell скриптов для ежедневной работы
Получить IP-адреса сервера
# Все IPv4 адреса, кроме loopback
Get-NetIPAddress -AddressFamily IPv4 |
Where-Object {$_.InterfaceAlias -notlike "*Loopback*"} |
Select-Object InterfaceAlias, IPAddress, PrefixLength |
Format-Table -AutoSize
Список процессов с высоким потреблением CPU
# Топ-10 процессов по CPU
Get-Process |
Sort-Object CPU -Descending |
Select-Object -First 10 Name, CPU, WorkingSet |
Format-Table -AutoSize
Проверка и перезапуск службы
# Функция для проверки и перезапуска службы
function Ensure-ServiceRunning {
param([string]$ServiceName)
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($null -eq $service) {
Write-Host "Служба '$ServiceName' не найдена!" -ForegroundColor Red
return
}
if ($service.Status -ne "Running") {
Write-Host "Служба $ServiceName остановлена. Запускаем..." -ForegroundColor Yellow
Start-Service -Name $ServiceName
Start-Sleep -Seconds 3
$service.Refresh()
if ($service.Status -eq "Running") {
Write-Host "Служба $ServiceName успешно запущена!" -ForegroundColor Green
} else {
Write-Host "Не удалось запустить службу $ServiceName!" -ForegroundColor Red
}
} else {
Write-Host "Служба $ServiceName работает нормально." -ForegroundColor Green
}
}
# Использование
Ensure-ServiceRunning -ServiceName "Spooler"
Ensure-ServiceRunning -ServiceName "wuauserv"
Скрипт резервного копирования
# Файл: C:\Scripts\Backup\daily-backup.ps1
param(
[string]$SourcePath = "C:\Data",
[string]$BackupRoot = "D:\Backups",
[int]$RetentionDays = 30
)
$date = Get-Date -Format "yyyy-MM-dd_HH-mm"
$backupPath = Join-Path $BackupRoot $date
# Создаём папку для бэкапа
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null
# Копируем файлы
Write-Host "Начинаем резервное копирование: $SourcePath -> $backupPath"
Copy-Item -Path $SourcePath -Destination $backupPath -Recurse -Force
# Архивируем
$archivePath = "$backupPath.zip"
Compress-Archive -Path $backupPath -DestinationPath $archivePath -Force
Remove-Item -Path $backupPath -Recurse -Force
# Удаляем старые бэкапы
$oldBackups = Get-ChildItem $BackupRoot -Filter "*.zip" |
Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-$RetentionDays)}
if ($oldBackups.Count -gt 0) {
$oldBackups | Remove-Item -Force
Write-Host "Удалено старых бэкапов: $($oldBackups.Count)" -ForegroundColor Yellow
}
$archiveSize = [math]::Round((Get-Item $archivePath).Length / 1MB, 2)
Write-Host "Бэкап создан: $archivePath ($archiveSize MB)" -ForegroundColor Green
Типичные ошибки при запуске PowerShell скриптов и как их лечить
Ошибка: «running scripts is disabled on this system»
Причина: Execution Policy запрещает запуск скриптов.
Лечение:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# или для текущей сессии:
Set-ExecutionPolicy Bypass -Scope Process
Ошибка: «File cannot be loaded because the file is not digitally signed»
Причина: Политика AllSigned, скрипт не подписан.
Лечение:
# Вариант 1: подписать скрипт (рекомендуется для корпоративной среды)
Set-AuthenticodeSignature -FilePath .\script.ps1 -Certificate $cert
# Вариант 2: разблокировать файл (для скачанных скриптов)
Unblock-File -Path .\script.ps1
# Вариант 3: изменить политику (только при наличии прав)
Set-ExecutionPolicy RemoteSigned
Ошибка: «Access to the path is denied»
Причина: Недостаточно прав для выполнения операции.
Лечение:
# Запустить PowerShell от имени администратора и повторить
# Или добавить в начало скрипта:
#Requires -RunAsAdministrator
Ошибка: «The term ‘X’ is not recognized»
Причина: Команда не найдена — не установлен модуль или опечатка.
Лечение:
# Поиск нужного командлета
Get-Command *keyword*
# Установка модуля (например, для работы с AD)
Install-Module -Name ActiveDirectory
# Импорт модуля
Import-Module ActiveDirectory
Ошибка: Кодировка — кириллица отображается кракозябрами
# Установить правильную кодировку в начале скрипта
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
# Сохранять .ps1 файлы в кодировке UTF-8 with BOM через VS Code или ISE
Профилактика и лучшие практики: пишем скрипты как профи
Хороший скрипт — это не только рабочий код. Это код, который понятен через 6 месяцев и не сломает систему при ошибке.
Обязательные элементы каждого скрипта
<#
.SYNOPSIS
Краткое описание скрипта
.DESCRIPTION
Подробное описание того, что делает скрипт
.PARAMETER ServerName
Имя сервера для проверки
.EXAMPLE
.\script.ps1 -ServerName "webserver01"
.NOTES
Автор: Ivan Ivanov
Дата: 2024-01-15
Версия: 1.0
#>
#Requires -Version 5.1
#Requires -RunAsAdministrator
param(
[Parameter(Mandatory=$true)]
[string]$ServerName
)
# Включить строгий режим - поймает необъявленные переменные
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# Логирование
$logFile = "C:\Scripts\Logs\$(Split-Path $PSCommandPath -Leaf)_$(Get-Date -Format 'yyyyMMdd').log"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp [$Level] $Message" | Tee-Object -FilePath $logFile -Append
}
# Основной код в блоке try-catch
try {
Write-Log "Скрипт запущен. Параметры: ServerName=$ServerName"
# Ваш код здесь
Write-Log "Скрипт выполнен успешно"
}
catch {
Write-Log "ОШИБКА: $_" -Level "ERROR"
exit 1
}
Чеклист качества PowerShell скрипта
- ✅ Есть блок
param() с типизированными параметрами
- ✅ Есть документация в формате
.SYNOPSIS / .DESCRIPTION
- ✅ Код обёрнут в
try-catch с обработкой ошибок
- ✅ Есть логирование в файл
- ✅ Указаны зависимости через
#Requires
- ✅ Файл сохранён в кодировке UTF-8
- ✅ Скрипт протестирован с параметром
-WhatIf перед боевым запуском
- ✅ Хранится в системе контроля версий (Git)
Итог: ваш PowerShell арсенал готов к бою
Мы прошли полный путь: от создания первого .ps1 файла до корпоративного развёртывания через GPO. Теперь у вас есть:
- Понимание структуры и лучших практик написания скриптов
- Все способы запуска — вручную, через планировщик, через GPO
- Готовые шаблоны для мониторинга, бэкапа и управления службами
- Методы решения типичных ошибок
- Основы подписи скриптов для корпоративной среды
PowerShell — это инвестиция. Потратьте день на написание правильных скриптов и сэкономьте недели рутинной работы в течение года.
Если возникли вопросы или нужна помощь с конкретным скриптом — пишите в комментарии. Разберём вместе. Подпишитесь на наш Telegram-канал, чтобы не пропустить следующие рецепты из IT-аптеки.