Создать обработчик протокола для скрипта Powershell - PullRequest
1 голос
/ 27 октября 2019

Как я могу создать обработчик протокола для сценария powershell и заставить целевой сценарий powershell получать аргументы командной строки?

И каковы при этом проблемы безопасности?

Ответы [ 2 ]

2 голосов
/ 28 октября 2019

В дополнение к вашему полезному руководству с примером кода , который автоматизирует создание обработчика пользовательского протокола :

Следующее:

  • Создает пользовательский протокол URI custom: (вместо pwsh:, учитывая, что PowerShell просто используется для реализации протокола), которому может передаваться неограниченное число аргументов.

  • Действует только для текущего пользователя (HKEY_CURRENT_USER\Software\Classes) по умолчанию;тем не менее, легко настроить код для реализации пользовательского протокола для всех пользователей (HKEY_LOCAL_MACHINE\Software\Classes), хотя вам нужно будет выполнить код с повышением прав (от имени администратора)затем.

    • Сценарий обработчика *.ps1 создается автоматически:

      • При $env:USERPROFILE\customUriHandler.ps1 в сценарии текущего пользователя.

      • В $env:ALLUSERPROFILE\customUriHandler.ps1 в сценарии для всех пользователей.

    • Сценарий-обработчик просто повторяет переданные ему аргументы, ион вызывается в окне скрипта PowerShell, которое остается открытым после выполнения скрипта (-NoExit);при необходимости настройте команду PowerShell.

  • Протокол ожидает свои аргументы, как если бы это была команда оболочки , т. е. как разделенный пробелами список аргументов, с аргументами-индивидуальными "..." в кавычках, если необходимо.

    • Пример команды в конце использует Start-Process для вызова следующего URI, который вы также можете отправить из диалогового окна Run ( WinKey-R ), которое передает аргументы one, two & three, four:

      • URI:custom:one "two & three" four
      • Вызов через Start-Process: Start-Process 'custom:one "two & three" four'
    • Предупреждение : если вы отправите этот URI через * 1088адресная строка * web browser , она экранирована URI, и вместо нее передается один аргумент one%20%22two%20&%20three%22%20four, который потребует пользовательского анализа;аналогично, отправка из адресной строки File Explorer проходит one%20two%20&%20three%20four, хотя обратите внимание, что символы ". как ни странно - потерялись в процессе.

# Determine the scope:
# Set to $false to install machine-wide (for all users)
# Note: Doing so then requires running with ELEVATION.
$currentUserOnly = $true

if (-not $currentUserOnly) {
  net session *>$null
  if ($LASTEXITCODE) { Throw "You must run this script as administrator (elevated)." }
}

$ErrorActionPreference = 'Stop'

# The name of the new protocol scheme
$schemeName = 'custom'

$pwshPathEscaped = (Get-Process -Id $PID).Path -replace '\\', '\\'

$handlerScript = ($env:ALLUSERSPROFILE, $env:USERPROFILE)[$currentUserOnly] + "\${schemeName}UriHandler.ps1"
$handlerScriptEscaped = $handlerScript -replace '\\', '\\'

# Create the protocol handler script.
@'

# Remove the protocol scheme name from the 1st argument.
$argArray = $args.Clone()
$argArray[0] = $argArray[0] -replace '^[^:]+:'
# If the 1st argument is now empty, remove it.
if ('' -eq $argArray[0]) { $argArray = $argArray[1..($argArray.Count-1)] }

"Received $($argArray.Count) arguments."

$i = 0
foreach ($arg in $argArray) {
  # Remote the protocol scheme name from the 1st argument.
  if ($i -eq 0) { $arg = $arg -replace '^[^:]+:' }
  "#$((++$i)): [$arg]"
}

'@ > $handlerScript

# Construct a temp. *.reg file.
# Target the scope-appropriate root registrykey.
$rootKey = ('HKEY_LOCAL_MACHINE\Software\Classes', 'HKEY_CURRENT_USER\Software\Classes')[$currentUserOnly]
# Determine a temp. file path.
$tempFile = [IO.Path]::GetTempPath() + [IO.Path]::GetRandomFileName() + '.reg'
@"
Windows Registry Editor Version 5.00

[$rootKey\$schemeName]
@="URL:$schemeName"
"URL Protocol"=""

[$rootKey\$schemeName\DefaultIcon]
@="$pwshPathEscaped"

[$rootKey\$schemeName\shell]
@="open"

[$rootKey\$schemeName\shell\open\command]
; === Tweak the PowerShell command line here: ===
@="\"$pwshPathEscaped\" -ExecutionPolicy Bypass -NoProfile -NoExit -File \"$handlerScriptEscaped\" %1"

"@ > $tempFile

# Import the *.reg file into the registry.
& {
  $ErrorActionPreference = 'Continue'
  reg.exe import $tempFile 2>$null
  if ($LASTEXITCODE) { Throw "Importing with reg.exe failed: $tempFile"}
}

# Remove the temp. *.reg file.
Remove-Item -ErrorAction Ignore -LiteralPath $tempFile

# ---

# Sample invocation of the new protocol with 3 arguments:
$uri = "$schemeName`:one `"two & three`" four"
Write-Verbose -Verbose "Invoking the following URI: $uri"
Start-Process $uri
2 голосов
/ 27 октября 2019

Я подумал, что напишу приличное руководство по этому вопросу, поскольку в информации, которую я нашел в Интернете, не хватает некоторых деталей.

https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85)

Прежде всего, из соображений безопасности

  1. Любая программа, веб-сайт, скрипт и т. Д., Работающие на вашем компьютере, могут отключить протокол. Нет никаких проверок авторизации.

  2. Вы НЕ должны создавать универсальный обработчик протокола. Это было бы серьезной проблемой безопасности. Я имею в виду, что это позволит программе, веб-сайту, сценарию и т. Д. Запускать на вашем компьютере любой сценарий или команду powershell.

Создание обработчика протокола в реестре Windows протокол должен быть зарегистрирован в реестре Windows. Это простая задача.

Я вызываю мой обработчик протокола powershell для pwsh

Шаг 1: Откройте редактор реестра и перейдите к Computer\HKEY_CLASSES_ROOT

. Для вдохновения вы можете посмотреть на Computer\HKEY_CLASSES_ROOT\http, чтобы посмотреть, как сделан этот обработчик протокола.

Шаг 2: Создайте следующую иерархию:

Создайте ключ pwsh: [Computer\HKEY_CLASSES_ROOT\pwsh]

Измените значение по умолчанию от (Default) до URL:pwsh. Помните, что я вызываю мой обработчик протокола для pwsh, пишите, как называется ваш.

Добавьте строковое значение с именем URL Protocol и пустыми данными.

Теперь это должно выглядеть следующим образом: Registry entry for pwsh

Создатьновый ключ в pwsh, DefaultIcon: Computer\HKEY_CLASSES_ROOT\pwsh\DefaultIcon. Задайте для поля данных (Default) путь к файлу, который ведет к значку или изображению. Я использовал значок powershell для Powershell 7 C:\Program Files (x86)\PowerShell\7-preview\assets\ps_black_32x32.ico.

. Затем создайте ключи shell -> open -> command, как показано на рисунке выше.

Включ command изменить значение данных (Default) на то место, где установлен powershell, а затем запустить скрипт powershell.

При тестировании я делаю это: "C:\Program Files\PowerShell\6\pwsh.exe" -noexit -executionpolicy bypass -Command {Write-Host %1} Примечание. Я используюPowerShell Core 6 и ваш путь к PowerShell, вероятно, отличается. Вы можете проверить работоспособность, открыв программу run в Windows (Windows + R).

Run program with the protocol

Ожидаемое поведение - окно PowerShell, которое открывается с напечатанным текстом pwsh:Hello Stackoverflow.

Powershell printing out text

Шаг 3: Создайте скрипт powershell для обработки входящих действий по протоколу. Значение данных готовности к работе для клавиши command: "C:\Program Files\PowerShell\6\pwsh.exe" -noexit -File C:\handleActions.ps1 %1

Param($Argument="") # If the protocol is ran you always at least get the protocol name as an argument. (if using the %1)
[String]
$Argument 

function Handle-Actions { # The cmdlet 'Handle-Actions' uses an unapproved verb. 
    [cmdletBinding()]
    param(
        [Parameter(Mandatory=$false, Position=0)]
        [String]
        $Argument 
    )
    $Argumuments = $Argument.Split([Char]0x003F) # Splits by `?`
    #Argumnets is now in an array, do whatever you need to next.
    $Argumuments | %{
        Write-Host $_ # Writes each argument that was seperated by ? to a line
    }
}

Handle-Actions -Argument $Argument

При наличии команды запуска pwsh:?firstArgument?SecondArgument скрипт выдаст:

pwsh:
firstArgument
SecondArgument
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...