Заметки · 14.11.2025

Мы где-то встречались…

Внезапный, но очевидный дисклеймер: хранение авторизационных данных в любом виде (даже зашифрованном) заведомо отвратительная идея. Это даже хуже оставленной без присмотра административной сессии. Впрочем, если временно отбросить здравую паранойю и использовать метод «слепой» авторизации только в целях оправданной автоматизации…

Так вот! Спустя дебри дисклеймера, который пришлось нагородить чуть выше, поведаю триллер.

Функция Get-AdminCredential появилась на свет в муках. Изначально она умещалась в две куцые строчки в скрипте, с помощью которого (как я предполагал) можно пролечить оборванные связи между целевым хостом и контроллером домена. Тот скрипт помог. Частично. Да и то не сразу и далеко не всем.

Основная идея работы с credentials упомянутого скрипта заключалась в единоразовом вводе учётных данных профиля с правами администратора домена. Далее скрипт должен был сохранить авторизационные данные в xml-файл и больше никому не докучать расспросами, черпая всё, что нужно из него. По-крайней мере, этот функционал работал максимально безотказно и, признаться, очень радовал.

Чуть позже я решил развить идею и, пожертвовав количеством строк, перековать те самые две строки в универсальную функцию, которая бы могла работать с учётными данными в последующих проектах. Получилось вот это:

function Get-AdminCredential 
{
    # Имя файла для хранения учетных данных
    param (
        [string]$FileName = "credentials.xml"
    )

    # Проверяем, если функция вызывается в контексте скрипта
    $scriptPath = if ($MyInvocation.MyCommand.Path) 
    {
        Split-Path -Parent $MyInvocation.MyCommand.Path
    } 
    else 
    {
        # Если нет, используем текущую директорию
        Get-Location
    }

    # Формируем полный путь к файлу с учетными данными
    $credFile = Join-Path -Path $scriptPath -ChildPath $FileName

    # Проверяем, существует ли файл с учетными данными
    if (Test-Path -Path $credFile) 
    {
        # Если файл существует, импортируем учетные данные из него
        $credential = Import-CliXml -Path $credFile
    } 
    else 
    {
        # Если файл не найден, запрашиваем у пользователя учетные данные
        $credential = Get-Credential -Message "Введите учетные данные администратора"

        # Сохраняем введенные пользователем учетные данные в файл для будущего использования
        $credential | Export-CliXml -Path $credFile
    }

    # Возвращаем учетные данные
    return $credential
}

Структура файла credentials.xml выглядит так:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>System.Management.Automation.PSCredential</T>
      <T>System.Object</T>
    </TN>
    <ToString>System.Management.Automation.PSCredential</ToString>
    <Props>
      <S N="UserName">user</S>
      <SS N="Password">А ЗДЕСЬ ЗАШИФРОВАННЫЙ ПАРОЛЬ!</SS>
    </Props>
  </Obj>
</Objs>

Функция ищет файл credentials.xml или же иной файл заданный с помощью параметра -FileName, если файла не оказывается по указанным координатам — запрашивает пару Username/Password. Если же файл найден — забирает учётные данные оттуда и возвращает в виде $credential.

Функция отлично работает в скомпилированных с помощью утилиты PS2EXE скриптах.

Не могу сказать, что Get-AdminCredential мною полностью протестирована, но в условиях запроса учётных данных для командлетов с параметром -Credentials ведёт себя так, как и ожидалось.