Заметки · 22.12.2023

От скрипта до модуля

Сегодня речь пойдёт про самодельные модули PowerShell и их установку в систему, чтобы не выполнять каждый раз Import-Module с ручной пропиской в параметр path координатов файла. Кстати, это последний пост в этом году, если не считать традиционного поздравления с наступающими праздниками. Это я к тому, что повествование может быть сумбурным, предпраздничным и суетливым. В общем, поскакали!

Где-то здесь я уже рассказывал про подключение к удалённому хосту с помощью PSRemoting. Штука отличная, если нужно провернуть что-то на удалённом хосте, не трогая пользователя и не занимая rdp. В моём случае, на момент публикации того поста, была проблема с падением службы WinRM на удалённых хостах, которую нужно было запускать вручную, а уже потом обращаться к командлету Enter-PSSession. Конечно, впоследствии эта проблема была решена, но даже до сих пор встречаются машины, на которых, в силу тех или иных факторов, упомянутая служба может быть выключена.

Для создания модуля, я взял именно кусок кода с запуском службы WinRM, который приходилось всегда держать под рукой в среде сценариев ISE. В итоге, получилась вот такая простенькая функция:

function PSConnection
{
  Param(
         [Parameter(Mandatory=$true)]
         $ComputerName
       )

  try {
        Set-Service -ComputerName $ComputerName -Name WinRM -Status Running -ErrorAction Stop -PassThru | Out-Null
        Enter-PSSession -ComputerName $ComputerName -ErrorAction Stop
      }
  catch { return "Сonnection refused" }
}

Предсказуемо, у функции PSConnection только один принимаемый параметр — ComputerName. Просто говоришь куда хочешь подключиться и функция всё сделает за тебя. Если подключение будет невозможно — вернётся Сonnection refused.

Теперь эту функцию нужно сохранить в файл с расширением psm1. В принципе, модуль уже готов и его можно импортировать в консольную сессию PowerShell, но, как я и сказал выше, нужно автономное решение без дополнительных командлетов. Попробуем установить получившийся модуль. Кстати, для пытливых умов есть хорошая документация на эту тему.

Установка модуля, в том числе и кастомного, минуя галерею — весьма простая задача. Достаточно только получить папку с уже установленными модулями и поместить туда папку с нашим модулем, следуя внутренней иерархии. В среде PowerShell для данных целей предусмотрена отличная переменная $env:PSModulePath, которая выводит в одну строку с разделителем в виде «;» список директорий с модулями. Чтобы отмахнуться от разделителя, попробуем рассплитовать выдачу:

$env:PSModulePath -split ";"

Устанавливать модули я предпочёл в директорию:

C:\Program Files\WindowsPowerShell\Modules

Здесь нужно создать папку с именем нашего модуля и положить внутрь сам файл psm1. В принципе, установка завершена. Теперь давайте автоматизируем и эту задачу.

Для установки кастомных модулей я написал вот такую функцию:

function InstallCustomModule
{
    Param(
         [Parameter(Mandatory=$true)]
         $ModulePath
       )

    $installpath = "$env:ProgramFiles\WindowsPowerShell\Modules"
    $modulename = (Get-Item $ModulePath).Basename
    $modulefile = (Get-Item $ModulePath).Name

    try
    {
        New-Item -Name $modulename -Path $installpath -ItemType Directory -ErrorAction Stop -Force | Out-Null
        Copy-Item -Path $ModulePath -Destination $installpath\$modulename\$modulefile -ErrorAction Stop -Force | Out-Null
        return "Module $modulename installed!"
    }
    catch { return "Something wrong..." }
}

Которую, кстати, тоже можно запихнуть в файл psm1 и установить, как модуль.