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

Конфигурация и адаптивные скрипты

Разработчику Архитектору Инженеру

Play ITЗагрузка интерактивного демо…


Зачем выносить данные из кода

Жёстко прошитые пути, списки серверов и пороги в .ps1 заставляют править код при каждом изменении инфраструктуры. Адаптивный скрипт читает данные конфигурации и применяет одну и ту же логику к разным окружениям (dev/stage/prod, филиалы, клиенты).

Разделение:

СлойСодержимоеГде хранить
КодАлгоритм, проверки, обработка ошибок.ps1, .psm1 в Git
КонфигПути, списки, пороги, имена секретов (не сами секреты)JSON/YAML рядом или в share
СекретыПароли, ключиСекреты и безопасная автоматизация — SecretManagement

JSON-конфигурация

Файл config.json рядом со скриптом:

{
"LogFolder": "C:\\App\\logs",
"ArchiveFolder": "D:\\Archives",
"OlderThanDays": 30,
"ArchivePrefix": "logs_",
"SecretNameSql": "SqlMonitor",
"NotifyEmail": "ops@example.com"
}

Загрузка и валидация:

Код ITЗагрузка примера кода…

ПрактикаЗачем
$PSScriptRoot для пути к конфигуРаботает из планировщика с -WorkingDirectory
-Encoding utf8Кириллица в путях и письмах
Явная проверка обязательных ключейРанний понятный сбой вместо $null в середине
Отдельный config.prod.jsonПараметр -ConfigPath при деплое

Секреты в JSON не кладут — только имя в SecretStore: "SecretNameSql": "SqlMonitor".


Data-driven функции

Одна функция обрабатывает запись конфигурации — объект или hashtable:

Код ITЗагрузка примера кода…

Конфиг со списком серверов:

{
"Servers": [
{ "Name": "web-01", "Host": "web-01.corp.local", "Port": 443 },
{ "Name": "db-01", "Host": "db-01.corp.local", "Port": 1433 }
]
}

Оркестратор:

$config = Get-Content "$PSScriptRoot\servers.json" -Raw | ConvertFrom-Json
$report = foreach ($srv in $config.Servers) {
Test-ServerHealth -Server $srv
}
$report | Where-Object { -not $_.Ok } | ForEach-Object { Write-Warning "$($_.Name): $($_.Detail)" }

Классы PowerShell

Для стабильной структуры данных в PowerShell 5+ / 7 можно объявить class:

class ServerRecord {
[string]$Name
[string]$HostName
[int]$Port = 443

[bool] TestPort() {
(Test-NetConnection -ComputerName $this.HostName -Port $this.Port -WarningAction SilentlyContinue).TcpTestSucceeded
}
}

$s = [ServerRecord]@{ Name = 'web-01'; HostName = 'web-01.corp.local' }
$s.TestPort()

Классы удобны в модулях с большим числом полей; для простых скриптов достаточно pscustomobject и JSON.


Конфиг внутри модуля

Константы уровня модуля (паттерн из практики работы с SQL через dbatools):

# Inside MyModule.psm1
$_SqlInstance = 'SRV-SQL\SQLEXPRESS'
$_Database = 'PoshAssetMgmt'

function Get-ModuleDatabase {
[CmdletBinding()]
param()
@{ SqlInstance = $_SqlInstance; Database = $_Database }
}

Имена с префиксом $script: или $_ показывают, что это настройки модуля, а не параметры каждого вызова. Для мультисредовых деплоев конфиг модуля генерируют при установке (DSC, Ansible, setup.ps1).


Чего не кладут в конфиг

НеприемлемоАльтернатива
Invoke-Sqlcmd как строка в JSONИмя функции + switch в коде или отдельные ключи Action: "SqlCheck"
Пароль в JSONSecretNameGet-Secret
Произвольный PowerShell в JSONРасширяемый набор известных действий в коде

Конфиг описывает что делать; код — как.


Идempotency и повторный запуск

Скрипт идемпотентен, если повторный запуск не ломает состояние: второй раз создаёт тот же результат, а не дубликаты.

Приёмы:


Конфиг vs база данных

JSON / YAMLSQL
Мало записей, редкие правки, один админМного объектов, concurrent update, отчёты
Версионирование в GitЦентральный реестр серверов, CMDB

PowerShell + SQL (модуль dbatools) — для инвентаризации и отчётов; теория SQL — 3.07. Для десятков серверов в JSON хватает; для тысяч — БД или API.


Пример структуры проекта

Deploy-App/
├── Deploy-App.ps1 # оркестратор
├── config.json # пути, флаги (в Git)
├── config.local.json # переопределения (в .gitignore)
└── lib/
└── AppTools.psm1 # функции из [125]

Запуск:

.\Deploy-App.ps1 -ConfigPath .\config.local.json

Чек-лист

#Вопрос
1Секреты только по имени, не по значению в конфиге?
2Конфиг валидируется при старте?
3Повторный запуск безопасен (идемпотентность)?
4Окружения различаются файлом конфига, а не правкой .ps1?
5В JSON нет исполняемого кода?

Дальше

ТемаМатериал
Ошибки, таймауты службОбработка ошибок и стратегии отладки
Azure Automation + конфиг в переменныхЭкосистема автоматизации на PowerShell
Возобновляемые длинные задачиРекомендации по написанию PowerShell-скриптов
Pester для конфигафаза 4 — статья 129