Для командлетов PowerShell я всегда могу передать блок скрипта в строковый параметр? - PullRequest
0 голосов
/ 14 октября 2018

Я смотрю на документ Rename-Item, и есть пример, подобный этому.

PS C:\>Get-ChildItem *.txt | Rename-Item -NewName { $_.name -Replace '\.txt','.log' }

В этом примере показано, как использовать оператор Replace для переименования нескольких файлов, даже если параметр NewName не принимает символы подстановки.

Эта команда переименовывает все символы.TXT файлы в текущем каталоге в .log.

Команда использует командлет Get-ChildItem для получения всех файлов в текущей папке, которые имеют расширение имени файла .txt.Затем он использует оператор конвейера (|) для отправки этих файлов в Rename-Item.

Значением NewName является блок сценария, который выполняется перед передачей значения в параметр NewName.

Обратите внимание на последнее предложение:

Значение NewName - это блок сценария, который выполняется до того, как значение передается в параметр NewName .

Фактически NewName это строка:

[-NewName] <String>

Значит ли это, что я всегда могу использовать блок скрипта, когда требуемый тип параметра - строка?

Ответы [ 3 ]

0 голосов
/ 14 октября 2018

При использовании Delay Binding параметр может получать значение из конвейера, используя блок скриптов вместо фактического типа данных параметра.

В блоке скриптов $ _ обозначает значение, переданное по конвейеру.

Доступно только при поступлении входных данных по конвейеру.

0 голосов
/ 15 октября 2018

Delay-bind аргументы блока скрипта являются неявной функцией , которая:

  • только работает с параметрами, предназначенными для ввода данных конвейера ,

    • из любого типа кроме следующего , в этом случае обычное связывание параметров происходит [1] :

      • [scriptblock]
      • [object] (однако [psobject], однако, работает и, следовательно, [pscustomobject] тоже)
      • (тип не указан), что фактически совпадает с [object]
    • , могут ли такие параметры принимать входные данные конвейера по значению (ValueFromPipelineBy) или по имени свойства (ValueFromPipelineByPropertyName), не имеет значения.

  • включает для каждого объекта ввода преобразования с помощью блока сценария пройдено вместо аргумента, соответствующего типу ;блок сценария оценивается для каждого объекта конвейера, который, как обычно, доступен внутри блока сценария как $_, а вывод блока * сценария блока сценария, который предполагается соответствующим типу для параметра, равениспользуется в качестве аргумента.

    • Поскольку такие блоки специальных сценариев по определению не соответствуют типу целевого параметра, вы всегда должны явно использовать имя параметра при их передаче.

    • Блоки сценариев с задержкой привязки безоговорочно предоставляют доступ к входным объектам конвейера, даже если параметр обычно не быть привязанным к данному объекту конвейера, если он определен как ValueFromPipelineByPropertyName, и у объекта отсутствует свойство с таким именем.

      • Это позволяет использовать такие методы, как следующий вызов Rename-Item,где вход конвейера из Get-Item, как обычно, привязан к параметру -LiteralPath, но передает блок скрипта в -NewName, который обычно связывается только с объектами вводасо свойством .NewName - разрешает доступ к тому же объекту конвейера и, таким образом, выводит имя файла назначения из имени входного файла:
        • Get-Item file | Rename-Item -NewName { $_.Name + '1' } # renames 'file' to 'file1';вход связывается с и -LiteralPath (неявно) и блоком сценария -NewName.
    • Примечание. В отличие от блоков сценариев, передаваемых в ForEach-Object или Where-Object, например, блоки сценариев с привязкой с задержкой выполняются в child scope переменной [2] , что означает, что вы не можете напрямую изменять переменные вызывающего , например, увеличивая счетчик для входных объектов.
      В качестве обходного пути используйте переменную типа [ref], объявленную в области действия вызывающего и доступего свойство .Value внутри блока скрипта - см. этот ответ для примера.


[1]Условия ошибки:

  • Если вы по ошибке попытаетесь передать блок скрипта параметру, который не привязан к конвейеру или имеет значение [scriptblock] - или [object]-типированный (нетипизированный) , обычный происходит привязка параметров :

    • Блок сценария передается один раз , befoПовторная обработка ввода-ввода начинается, если таковая имеется.
      То есть, блок сценария передается как (возможно преобразованный) значение , и без оценки не происходит.
      • Для параметров типа [object] или [scriptblock] / типа делегата, например System.Func, который можно преобразовать в блок скрипта, блок скрипта будет связывать как есть .
      • В случае параметра (без привязки к конвейеру) [string] тип буквенного содержимого блока сценария передается как строковое значение.
      • Для всехдругие типы, привязка параметров - и, следовательно, команда в целом - будут просто терпеть неудачу , поскольку преобразование из блока скрипта невозможно.
  • Если вы пренебрегаете вводом конвейера при передаче блока сценария с задержкой привязки в параметр привязки конвейера, который поддерживает , вы получите следующее ошибка :

    • Cannot evaluate parameter '<name>' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input.

[2] Это расхождение обсуждается в этот выпуск GitHub .

0 голосов
/ 14 октября 2018

Значит ли это, что я всегда могу использовать блок скрипта, когда требуемый тип параметра - строка?: NO

Здесь этот метод называется Задержка привязки , что очень полезно в этом сценарии.

Что происходит, когдаВы делаете задержку привязки?

PowerShell ParameteBinder поймет использование привязки задержки и сначала выполнит ScriptBlock, а затем результат преобразуется в ожидаемый тип соответствующего параметра, здесь это строка.

Ниже приведен пример.

#Working one
'Path'|Join-Path -Path {$_} -ChildPath 'File'  

#Not working one
Join-Path -Path {'path'} -ChildPath 'File'
Join-Path : Cannot evaluate parameter 'Path' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input.

Чтобы узнать больше о ParameterBinding, вы можете сделать Trace-Command, как показано ниже.

Trace-Command ParameterBinding -Expression {'Path'|Join-Path -Path {$_} -ChildPath 'File'} -PSHost
...