Создание параметризованных однострочников PowerShell | Кодементор
вступление
Приходя из мира Unix, мне очень нравятся так называемые однострочники — легко запоминающиеся команды, которые выполняют полезную загрузку.
Несколько примеров из моих точечных файлов:
Дескать, если я хочу настроить свою любимую оболочку на какой-нибудь новый VPS
curl -sSL > getmyshell.sh && chmod +x getmyshell.sh && ./getmyshell.sh
curl -sSL | bash -s
или настроить мою конфигурацию dotfiles на более постоянный ящик
curl -sSL > bootstrap.sh && chmod +x bootstrap.sh
./bootstrap.sh <optional: simple | full | docker>
Этот подход очень хорошо работает в Linux, поэтому, когда у меня есть работа, связанная с Windows, я пытаюсь повторно использовать аналогичный подход.
Несколько примеров из моих winfiles: приведенный ниже сценарий настраивает мой профиль PowerShell на новом сервере Windows и дополнительно устанавливает мой набор инструментов «швейцарский нож» для системы Windows.
Set-ExecutionPolicy Bypass -Scope Process -Force;
iex ((New-Object System.Net.WebClient).DownloadString('https://bit.ly/winfiles'))
Иногда в Windows требуется дополнительно предварительно настроить скрипт начальной загрузки. Эта статья на самом деле заметка для себя, как сделать это быстро в следующий раз
Определение задачи
Предположим, у нас есть некоторая логика начальной загрузки, реализованная в PowerShell, загруженная в какое-то общедоступное место, и нам нужен однострочный код для упрощения установки.
Для демонстрации — это может быть скрипт, который устанавливает некий пользовательский артефакт MSI:
param (
[Parameter(Mandatory = $true)]
[string]$requiredParam = "THIS_PARAM_IS_REQUIRED",
[string]$optionalParamWithDefault = "",
[string]$optionalParamFromEnvironment = $env:computername
)
Write-Host "About to execute some bootstrap logic with params $requiredParam $optionalParamWithDefault on $optionalParamFromEnvironment"
Function Download_MSI_Installer {
Write-Host "For example, we download smth from internet"
}
Function Install_Script {
$msifile = "c:\some.msi"
$DataStamp = get-date -Format yyyyMMddTHHmmss
$logFile = 'somelog-{0}.log' -f $DataStamp
$MSIArguments = @(
"/i"
('"{0}"' -f $msifile)
"/qn"
"/norestart"
"/L*v"
$logFile
" REQUIRED_PARAM=$requiredParam OPTIONAL_PARAM_WITH_DEFAULT=$optionalParamWithDefault OPTIONAL_PARAM_FROM_ENVIRONMENT=$optionalParamFromEnvironment"
)
write-host "About to install msifile with arguments "$MSIArguments
}
Download_MSI_Installer
Install_Script
пользователь может настроить следующие параметры скрипта:
[Parameter(Mandatory = $true)]
[string]$requiredParam = "THIS_PARAM_IS_REQUIRED",
[string]$optionalParamWithDefault = "",
[string]$optionalParamFromEnvironment = $env:computername
Вариант А — почти ручной «bootstrap.ps1 -значение параметра»
Плюсы: на самом деле ничего не нужно, просто работает
Минусы: сложнее настроить параметры программно
(new-object net.webclient).DownloadFile('https://raw.githubusercontent.com/Voronenko/ps_oneliners/master/bootstrap.ps1','c:\bootstrap.ps1')
c:\bootstrap.ps1 -requiredParam AAA -optionalParamWithDefault BBB -optionalParamFromEnvironment CCC
Валидация — без переопределений
PS C:\> c:\bootstrap.ps1
cmdlet bootstrap.ps1 at command pipeline position 1
Supply values for the following parameters:
requiredParam: RRR
About to execute some bootstrap logic with params RRR on EC2AMAZ-9A8TRAV
For example, we download smth from internet
About to install msifile with arguments /i "c:\some.msi" /qn /norestart /L*v c:\some.msi-20190205T221234.log REQUIRED_PARAM=RRR OPTIONAL_PARAM_WITH_DEFAULT= OPTIONAL_PARAM_FROM_ENVIRONMENT=EC2AMAZ-9A8TRAV
Валидация — с переопределениями
PS C:\> c:\bootstrap.ps1 -requiredParam AAA -optionalParamWithDefault BBB -optionalParamFromEnvironment CCC
About to execute some bootstrap logic with params AAA BBB on CCC
For example, we download smth from internet
About to install msifile with arguments /i "c:\some.msi" /qn /norestart /L*v c:\some.msi-20190205T221400.log REQUIRED_PARAM=AAA OPTIONAL_PARAM_WITH_DEFAULT=BBB OPTIONAL_PARAM_FROM_ENVIRONMENT=CCC
Принятие: ПРИНЯТО
Вариант Б — X-Liner из заранее скачанного скрипта
Поместите переопределения только в $overrideParams, остальные будут выбраны из значений по умолчанию в сценарии установки.
Плюсы — вы можете обнаружить и программно изменить параметры переопределения.
$overrideParams = @{
requiredParam = 'AAAA'
optionalParamWithDefault='BBB'
optionalParamFromEnvironment='CCC'
}
$ScriptPath = 'c:\bootstrap.ps1'
$sb = [scriptblock]::create(".{$(get-content $ScriptPath -Raw)} $(&{$args} @overrideParams)")
Invoke-Command -ScriptBlock $sb
About to execute some bootstrap logic with params RRR on EC2AMAZ-9A8TRAV
$overrideParamsNone = @{
requiredParam = 'RRR'
}
$sb = [scriptblock]::create(".{$(get-content $ScriptPath -Raw)} $(&{$args} @overrideParamsNone)")
Invoke-Command -ScriptBlock $sb
About to execute some bootstrap logic with params AAAA BBB on CCC
Принятие: ПРИНЯТО
Вариант C — X-Liner выполняет скрипт из удаленного места
Поместите переопределения только в $overrideParams , остальные будут выбраны из значений по умолчанию в сценарии установки, загруженном из удаленного места.
Плюсы: вы можете обнаружить и программно изменить параметры переопределения, скрипт начальной загрузки может быть расположен в месте загрузки.
$overrideParams = @{
requiredParam = 'AAAA'
optionalParamWithDefault='BBB'
optionalParamFromEnvironment='CCC'
}
$ScriptPath = ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/Voronenko/ps_oneliners/master/bootstrap.ps1'))
$sb = [scriptblock]::create(".{$($ScriptPath)} $(&{$args} @overrideParams)")
Invoke-Command -ScriptBlock $sb
About to execute some bootstrap logic with params AAAA BBB on CCC
$overrideParamsNone = @{
requiredParam = 'RRR'
}
$ScriptPath = ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/Voronenko/ps_oneliners/master/bootstrap.ps1'))
$sb = [scriptblock]::create(".{$($ScriptPath)} $(&{$args} @overrideParamsNone)")
Invoke-Command -ScriptBlock $sb
About to execute some bootstrap logic with params RRR on EC2AMAZ-9A8TRAV
For example, we download smth from internet
Принятие: ПРИНЯТО
Вариант D — настоящий однострочный с использованием модуля PowerShell и iwr + iex
Как уже говорилось, требуется логика установки, упакованная в виде модуля PowerShell (см. bootstrap-module.ps1
)
. { iwr -useb } | iex; function -param value
. { iwr -useb https://raw.githubusercontent.com/Voronenko/ps_oneliners/master/bootstrap-module.ps1 } | iex; install -requiredParam AAA -optionalParamWithDefault BBB -optionalParamFromEnvironment CCC
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 CustomInstaller {Install-Project, install}
About to execute some bootstrap logic with params AAA BBB on CCC
. { iwr -useb https://raw.githubusercontent.com/Voronenko/ps_oneliners/master/bootstrap-module.ps1 } | iex; install
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 CustomInstaller {Install-Project, install}
cmdlet Install-Project at command pipeline position 1
Supply values for the following parameters:
requiredParam: RRR
Принятие: ПРИНЯТО
где bootstrap-module.ps1 — наш исходный файл начальной загрузки, но запакованный в модуль.
new-module -name CustomInstaller -scriptblock {
[Console]::OutputEncoding = New-Object -typename System.Text.ASCIIEncoding
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'
function Install-Project {
param (
[Parameter(Mandatory = $true)]
[string]$requiredParam = "THIS_PARAM_IS_REQUIRED",
[string]$optionalParamWithDefault = "",
[string]$optionalParamFromEnvironment = $env:computername
)
Write-Host "About to execute some bootstrap logic with params $requiredParam $optionalParamWithDefault on $optionalParamFromEnvironment"
Function Download_MSI_Installer {
Write-Host "For example, we download smth from internet"
}
Function Install_Script {
$DataStamp = get-date -Format yyyyMMddTHHmmss
$logFile = '{0}-{1}.log' -f $msifile.fullname, $DataStamp
$MSIArguments = @(
"/i"
('"{0}"' -f $msifile)
"/qn"
"/norestart"
"/L*v"
$logFile
" REQUIRED_PARAM=$requiredParam OPTIONAL_PARAM_WITH_DEFAULT=$optionalParamWithDefault OPTIONAL_PARAM_FROM_ENVIRONMENT=$optionalParamFromEnvironment"
)
write-host "About to install msifile with arguments "$MSIArguments
}
Download_MSI_Installer
Install_Script
}
set-alias install -value Install-Project
export-modulemember -function 'Install-Project' -alias 'install'
}
Пока вариант D самый односторонний
Ознакомьтесь с примерами из статьи.
Теперь у нас есть несколько подходов на выбор, чтобы реализовать короткие «однострочники» для загрузки некоторой логики с помощью PowerShell.