Перейти к содержимому

6. Скрипты PowerShell

PowerShell скрипты сохраняются с расширением .ps1. Это полноценный язык программирования: переменные, условия, циклы, функции, классы, обработка ошибок.

По умолчанию Windows блокирует запуск скриптов. Нужно настроить политику:

Окно терминала
# Посмотреть текущую политику
Get-ExecutionPolicy
Get-ExecutionPolicy -List # все уровни
# Изменить политику
Set-ExecutionPolicy RemoteSigned # рекомендуется для разработки
Set-ExecutionPolicy Unrestricted # без ограничений (не рекомендуется)
Set-ExecutionPolicy Restricted # только интерактивный режим (по умолчанию)
# Для текущего пользователя (без прав администратора)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# Временно обойти при запуске
powershell -ExecutionPolicy Bypass -File script.ps1

Политики:

  • Restricted — скрипты запрещены
  • RemoteSigned — локальные скрипты OK, загруженные требуют подписи
  • Unrestricted — всё разрешено (с предупреждением для загруженных)
  • Bypass — без ограничений и предупреждений
Окно терминала
# Создать скрипт
New-Item -Path "myscript.ps1" -ItemType File
# Содержимое скрипта
Write-Output "Hello, PowerShell!"
# Запустить
.\myscript.ps1 # всегда с .\
powershell -File .\myscript.ps1
& ".\myscript.ps1" # оператор вызова &
Окно терминала
# Типы переменных
$name = "PowerShell" # String
$version = 7.4 # Double
$count = 42 # Int
$enabled = $true # Boolean
$nothing = $null # Null
$today = Get-Date # DateTime
# Явное указание типа
[string]$text = "hello"
[int]$number = 42
[bool]$flag = $false
[datetime]$date = "2024-01-01"
# Массивы
$fruits = @("apple", "banana", "cherry")
$numbers = @(1, 2, 3, 4, 5)
$fruits[0] # apple
$fruits[-1] # cherry
$fruits.Count # 3
$fruits += "mango" # добавить элемент
# Хеш-таблицы (словари)
$person = @{
Name = "Alice"
Age = 30
City = "Moscow"
}
$person.Name # Alice
$person["Age"] # 30
$person.Keys # все ключи
Окно терминала
$age = 25
if ($age -ge 18) {
Write-Output "Совершеннолетний"
} elseif ($age -ge 14) {
Write-Output "Подросток"
} else {
Write-Output "Ребёнок"
}
# Switch
$day = "Monday"
switch ($day) {
"Monday" { Write-Output "Понедельник" }
"Tuesday" { Write-Output "Вторник" }
"Saturday" { Write-Output "Суббота! Выходной!" }
"Sunday" { Write-Output "Воскресенье! Выходной!" }
default { Write-Output "Рабочий день" }
}
# Тернарный оператор (PS 7+)
$result = $age -ge 18 ? "Взрослый" : "Несовершеннолетний"
Окно терминала
# foreach по коллекции
$fruits = @("apple", "banana", "cherry")
foreach ($fruit in $fruits) {
Write-Output "Фрукт: $fruit"
}
# for с счётчиком
for ($i = 1; $i -le 5; $i++) {
Write-Output "Итерация: $i"
}
# while
$count = 1
while ($count -le 10) {
Write-Output $count
$count++
}
# do-while (выполнится хотя бы раз)
do {
$input = Read-Host "Введите 'quit' для выхода"
} while ($input -ne "quit")
# ForEach-Object через pipeline
1..10 | ForEach-Object { $_ * 2 }
# break и continue
foreach ($item in 1..10) {
if ($item -eq 5) { continue } # пропустить 5
if ($item -eq 8) { break } # остановиться на 8
Write-Output $item
}
Окно терминала
# Базовая функция
function Say-Hello {
Write-Output "Привет!"
}
Say-Hello
# Функция с параметрами
function Get-Greeting {
param (
[string]$Name,
[int]$Age = 0 # параметр с дефолтным значением
)
if ($Age -gt 0) {
Write-Output "Привет, $Name! Тебе $Age лет."
} else {
Write-Output "Привет, $Name!"
}
}
Get-Greeting -Name "Alice"
Get-Greeting -Name "Bob" -Age 25
# Продвинутые параметры
function Deploy-App {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$Environment,
[Parameter(Mandatory=$false)]
[ValidateSet("staging", "production")]
[string]$Target = "staging",
[switch]$DryRun # флаг без значения
)
if ($DryRun) {
Write-Output "DRY RUN: деплой $Environment в $Target"
} else {
Write-Output "Деплой $Environment в $Target..."
}
}
Deploy-App -Environment "v1.2.3" -Target "production" -DryRun
# Возврат значения
function Add-Numbers {
param ([int]$A, [int]$B)
return $A + $B # или просто $A + $B
}
$result = Add-Numbers -A 10 -B 20
Write-Output "Сумма: $result"
try/catch/finally
try {
$content = Get-Content "nonexistent.txt" -ErrorAction Stop
Write-Output "Содержимое: $content"
}
catch [System.IO.FileNotFoundException] {
Write-Output "Файл не найден!"
}
catch {
Write-Output "Ошибка: $($_.Exception.Message)"
}
finally {
Write-Output "Это выполнится в любом случае"
}
# $ErrorActionPreference
$ErrorActionPreference = "Stop" # остановить скрипт при ошибке
# -ErrorAction параметр для отдельных команд
Get-Item "missing.txt" -ErrorAction SilentlyContinue # игнорировать
Get-Item "missing.txt" -ErrorAction Stop # остановить
Get-Item "missing.txt" -ErrorAction Continue # продолжить (по умолчанию)
#!/usr/bin/env pwsh
# backup-logs.ps1 — скрипт для архивации логов
[CmdletBinding()]
param (
[Parameter(Mandatory=$false)]
[string]$LogDir = "C:\Logs",
[Parameter(Mandatory=$false)]
[string]$BackupDir = "C:\Backup",
[Parameter(Mandatory=$false)]
[int]$DaysOld = 7,
[switch]$WhatIf
)
function Write-Log {
param ([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Output "[$timestamp] [$Level] $Message"
}
# Проверки
if (-not (Test-Path $LogDir)) {
Write-Log "Директория логов не найдена: $LogDir" "ERROR"
exit 1
}
New-Item -Path $BackupDir -ItemType Directory -Force | Out-Null
# Найти старые логи
$oldLogs = Get-ChildItem -Path $LogDir -Filter "*.log" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$DaysOld) }
Write-Log "Найдено $($oldLogs.Count) файлов для архивации"
foreach ($log in $oldLogs) {
$dest = Join-Path $BackupDir $log.Name
if ($WhatIf) {
Write-Log "WhatIf: переместить $($log.FullName)"
} else {
Move-Item -Path $log.FullName -Destination $dest
Write-Log "Перемещён: $($log.Name)"
}
}
Write-Log "Готово!"

PowerShell — мощный язык для автоматизации Windows. Инвестиции в его изучение окупаются на любом корпоративном проекте!