Ответ 1
Если вам нужна обложка для ввода для ls, вы должны написать правильную прокси-функцию. Есть несколько версий генератора на PoshCode.org, в том числе тот, что из Cookbook PowerShell от Lee Holmes
Я пытаюсь написать некоторые функции PowerShell, которые делают некоторые вещи, а затем прозрачно переходят к существующим встроенным функциям. Я хочу передать все аргументы нетронутыми. Я не хочу знать какие-либо подробности аргументов.
Я устал использовать "splat", чтобы сделать это с помощью @args
, но это не сработало, как я ожидал.
В приведенном ниже примере я написал игрушечную функцию под названием myls
, которая должна печатать привет! а затем вызовите ту же встроенную функцию Get-ChildItem
, что встроенный псевдоним ls
вызывает с остальной частью строки аргумента неповрежденной. То, что я до сих пор работает очень хорошо:
function myls
{
Write-Output "hello!"
# $MyInvocation | Format-List # <-- uncomment this line for debug info
Invoke-Expression ("Get-ChildItem " + $MyInvocation.UnboundArguments -join " ")
}
Правильная версия myls
должна обрабатывать вызовы без аргументов с одним аргументом с именованными аргументами из строки, содержащей несколько команд с разделителями с запятой и с переменными в аргументах, включая строковые переменные, содержащие пространства. В принципе, он должен быть альтернативой ls
.
В приведенных ниже тестах сравните myls
и встроенный ls
:
[ПРИМЕЧАНИЕ: выход удаляется и/или уплотняется для экономии места]
PS> md C:\p\d\x, C:\p\d\y, C:\p\d\"jay z"
PS> cd C:\p\d
PS> ls # no args
PS> myls # pass
PS> cd ..
PS> ls d # one arg
PS> myls d # pass
PS> $a="A"; $z="Z"; $y="y"; $jz="jay z"
PS> $a; ls d; $z # multiple statements
PS> $a; myls d; $z # pass
PS> $a; ls d -Exclude x; $z # named args
PS> $a; myls d -Exclude x; $z # pass
PS> $a; ls d -Exclude $y; $z # variables in arg-line
PS> $a; myls d -Exclude $y; $z # pass
PS> $a; ls d -Exclude $jz; $z # variables containing spaces in arg-line
PS> $a; myls d -Exclude $jz; $z # FAIL!
Есть ли способ переписать myls
, чтобы получить нужное поведение?
Короткий ответ: Да, это возможно. Плохая новость: для этого требуется код, который знает подробности параметров и других метаданных о функции, к которой вы хотите позвонить. Хорошие новости: не нужно писать все это. Эти метаданные доступны программно и существуют доступные модули, которые можно использовать для автоматического генерации скелетного прокси-кода (см. Ниже @Jaykul ответ). Я решил использовать модуль под названием "MetaProgramming" . После импортирования создание drop-in myls
script мертво просто:
New-ProxyCommand ls > .\myls.ps1
Затем можно начать настройку вновь созданного myls.ps1
script, например:
...
begin
{
Write-Output "hello!" # <-- add this line
try {
$outBuffer = $null
...
Voila! Эта новая версия проходит все тесты.
Если вам нужна обложка для ввода для ls, вы должны написать правильную прокси-функцию. Есть несколько версий генератора на PoshCode.org, в том числе тот, что из Cookbook PowerShell от Lee Holmes
Создание обертки должным образом не так просто, к сожалению. Прежде всего, оператор splat должен быть предположительно применен к хэш-таблице (например, автоматический PSBoundParameters
или другой), а не к массиву $args
.
Есть как минимум два варианта (оба не идеальны) и хак (см. раздел обновления).
Вариант 1. Используйте "классический" способ создания обертки. Пример: посмотрите, как это делается для функции help
, которая является оболочкой командлета Get-Help
:
Get-Content function:\help
Вы можете видеть, что функция-оболочка объявляет all параметры, которые имеет завершенный командлет, чтобы иметь PSBoundParameters
, ограниченный существующими параметрами функции.. p >
Ваш пример. Если ваша функция объявляет параметр Exclude
, тогда примерный код начинает работать. Но он работает только для Exclude
, а не Force
, хотя Force
также передается в:
function myls($Exclude) {
# only Exclude is in $PSBoundParameters even though we send Force, too:
$PSBoundParameters | Out-String | Out-Host
Write-Output "hello!"
Get-ChildItem @PSBoundParameters
}
cd d
myls -Exclude b -Force
Вариант 2. Теоретически в теории можно было бы построить хэш-таблицу из массива $args
вручную и применить к ней оператор splat. Но эта задача не выглядит практически привлекательной.
UPDATE
Ну, на самом деле есть еще один вариант ad-hoc (чистый взлом!), который требует минимальных усилий и будет работать в некоторых тривиальных, в основном интерактивных сценариях. Это не для какого-то серьезного кода!
function myls {
# extra job
Write-Output "hello!"
# invoke/repeat the calling code line with myls "replaced" with Get-ChildItem
Set-Alias myls Get-ChildItem
Invoke-Expression $MyInvocation.Line
}
cd d
# variables can be used as the parameter values, too
$exclude = 'b'
myls -Exclude $exclude -Force
Я верю в это:
функция myls {Write-Output "привет!"; iex "Get-ChildItem @args" }
приблизится к ожидаемому результату.
Обновление. По-видимому, существует известная ошибка с использованием @args таким образом, чтобы передать именованные параметры:
Я бы прекратил использовать это, пока не решит.