Если вы когда-нибудь сталкивались с ошибками в PowerShell из-за локализации системы, вы знаете, как это раздражает. Строки вроде Enabled или Disabled могут внезапно превратиться в Включено на русском или Activé на французском – и ваш скрипт сломается. Но есть способ обойти эту проблему, работая с числовыми значениями (enum) вместо текстовых статусов. Давайте разберёмся, как это сделать без головной боли.
Почему enum надёжнее строк (и как это работает)
Числовые значения – это универсальный язык. Даже если система переведена на другой язык, код 4 всегда будет означать одно и то же. Например, статус службы Running в PowerShell соответствует числу 4, и это значение не зависит от локализации. Но где взять эти магические числа?
Вот пример: когда вы получаете статус службы через (Get-Service ‘WinDefend’).Status, PowerShell возвращает объект типа ServiceControllerStatus. Чтобы увидеть его числовое значение, используйте свойство value__:
$service = Get-Service 'WinDefend'
$service.Status.value__ # Вернёт 4 для состояния 'Running'
Проблема в том, что не все объекты так очевидны. Например, при работе с функцией Get-WindowsOptionalFeature, её свойство State возвращает строки вроде Disabled или Enabled, но их числовые эквиваленты не документированы явно.
Совет: Если вы видите свойство с текстовым значением, проверьте его тип через
Get-Member
. Это поможет найти связанный enum.
Как получить список enum-значений для любого свойства
Допустим, вы работаете с Get-WindowsOptionalFeature и хотите узнать, какие числа скрываются за State. Вот пошаговый алгоритм:
1. Получите объект для анализа:
$feature = Get-WindowsOptionalFeature -Online | Select-Object -First 1
2. Определите тип свойства State:
$feature.State | Get-Member
В первой строке вывода вы увидите что-то вроде:
TypeName: Microsoft.Dism.Commands.FeatureState
3. Извлеките все возможные значения enum:
[enum]::GetValues([Microsoft.Dism.Commands.FeatureState])
Это вернёт массив:
Disabled
DisablePending
Enabled
EnablePending
...
4. Используйте числовые индексы:
Каждому элементу массива соответствует число, начиная с 0. Например:
Get-WindowsOptionalFeature -Online | Where-Object { $_.State -eq 0 } # Найдёт все отключённые функции
Но есть нюанс: если enum определён в сборке, которая не загружена в текущую сессию, PowerShell выдаст ошибку. В таком случае попробуйте явно импортировать модуль, например:
Import-Module Dism
Кстати, иногда разработчики забывают документировать enum. Если
[enum]::GetValues()
не работает, проверьте, не является ли свойство простой строкой без привязки к перечислению.
Состояние | Числовое значение |
Disabled | 0 |
DisablePending | 1 |
Enabled | 2 |
… | … |
Частые ошибки и как их избежать
– Ошибка: «Не удаётся найти тип [Microsoft.Dism.Commands.FeatureState]».
– Решение: Убедитесь, что модуль Dism загружен. Выполните Import-Module Dism перед использованием enum.
– Ошибка: Числовые значения не совпадают с ожидаемыми.
– Причина: Некоторые enums начинаются с 1 вместо 0. Всегда проверяйте вывод [enum]::GetValues().
– Лайфхак: Если не хочется запоминать числа, используйте сам enum в сравнениях:
Get-WindowsOptionalFeature -Online | Where-Object {
$_.State -eq [Microsoft.Dism.Commands.FeatureState]::Enabled
}
Этот код будет работать даже при смене числовых значений в будущих версиях Windows (хотя такое случается редко).
И напоследок: не все свойства в PowerShell используют enum. Если Get-Member показывает тип string, придётся мириться с рисками локализации – или искать альтернативные API. Но в 90% случаев метод с enum сработает, сделав ваши скрипты надёжнее.
P.S. Если вдруг застряли – посмотрите документацию .NET. Многие enum-ы из PowerShell берутся именно оттуда (например, System.ServiceProcess.ServiceControllerStatus). Просто введите в Google «<название_свойства> enum dotnet», и вы найдёте нужную таблицу.