Хорошая административная функция имеет проверяемый контракт: какие параметры принимаются, какие объекты возвращаются, какие изменения выполняются и как проявляется ошибка. Это позволяет использовать один код интерактивно, в конвейере и в задании по расписанию.
Определить интерфейс до реализации
Имя строится из утверждённого глагола и существительного. Посмотрите Get-Verb и выберите действие, соответствующее поведению. Значения передаются через param, а не читаются из случайных глобальных переменных. Обязательные аргументы, допустимые значения и типы нужно описать явно.
function Get-RunSummary {
[CmdletBinding()]
param(
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$Name,
[ValidateRange(0, 1000000)][int]$Processed = 0
)
Write-Verbose "Подготовка результата для $Name"
[pscustomobject]@{ Name = $Name; Processed = $Processed; CheckedAt = Get-Date }
}
Get-RunSummary -Name 'Inventory' -Processed 12 -VerboseРезультат — объект, а не красиво выровненная строка. Format-Table и Format-List выполняются у потребителя результата. Внутри функции форматирование заменит полезные данные объектами форматирования и затруднит экспорт.
Контролировать поток вывода
В PowerShell в success stream попадают все непоглощённые выражения, а не только выражение после return. Диагностическая строка в этом потоке может неожиданно превратить один результат в массив.
Для сообщений о ходе работы используйте Write-Verbose, для предупреждений — Write-Warning. return завершает выполнение, но не отменяет объекты, уже выведенные ранее. Если вспомогательная команда возвращает ненужный объект, явно присвойте его $null или отправьте в Out-Null.
Обработать каждую запись конвейера
function ConvertTo-ServiceSummary {
[CmdletBinding()]
param([Parameter(Mandatory, ValueFromPipeline)][object]$InputObject)
process {
[pscustomobject]@{
Name = $InputObject.Name
Status = [string]$InputObject.Status
}
}
}
Get-Service | ConvertTo-ServiceSummary | Select-Object -First 5process обрабатывает отдельную входную запись. begin подходит для общей подготовки, end — для завершения. Если нужна конкретная структура входа, используйте точный тип или проверку полей вместо универсального object из учебного примера.
Изменения через ShouldProcess
Функция с побочным эффектом должна поддерживать WhatIf и Confirm. Для этого нужны и SupportsShouldProcess, и фактический вызов ShouldProcess до изменения.
function Set-CheckedText {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$LiteralPath,
[Parameter(Mandatory)][AllowEmptyString()][string]$Value
)
$exists = Test-Path -LiteralPath $LiteralPath -PathType Leaf
$current = if ($exists) { [string](Get-Content -LiteralPath $LiteralPath -Raw -ErrorAction Stop) } else { '' }
if ($exists -and $current -ceq $Value) {
return [pscustomobject]@{ Path = $LiteralPath; Changed = $false }
}
if ($PSCmdlet.ShouldProcess($LiteralPath, 'Записать текст')) {
Set-Content -LiteralPath $LiteralPath -Value $Value -NoNewline `
-Encoding utf8 -ErrorAction Stop
[pscustomobject]@{ Path = $LiteralPath; Changed = $true }
}
}
# Сначала увидеть план без записи:
Set-CheckedText -LiteralPath '.\pilot.txt' -Value 'готово' -WhatIfLiteralPath не интерпретирует квадратные скобки и другие символы как маску. Пример не создаёт родительские каталоги и не решает блокировки файла: эти условия должен определить вызывающий сценарий. Повторная запись того же текста не нужна, что помогает сделать функцию идемпотентной.
Проверить контракт
- Обычный вызов возвращает объекты ожидаемой формы.
- Неверный аргумент отклоняется до побочного эффекта.
- Конвейер не теряет элементы.
- WhatIf не создаёт и не меняет файл.
- Повторная операция с тем же состоянием не делает лишнюю запись.
- Ошибка файловой системы не маскируется успешным результатом.
Не добавляйте универсальный catch, который только печатает ошибку и продолжает работу: вызывающий процесс тогда не сможет отличить успех от неудачи.
Документация: параметры advanced functions, вывод функций, ShouldProcess.
Иллюстрации к инструкции



Материал подготовлен самостоятельно на русском языке. Исходная тема и иллюстрации: LazyAdmin. Технические сведения сверены с документацией, указанной выше, 11 октября 2026 года. Интерфейсы и версии модулей могут отличаться от показанных примеров.