Возможно ли, чтобы блок сценариев оценивался внутри строки?

#powershell

#powershell

Вопрос:

Я бы хотел, чтобы результирующее значение в $ s было «сейчас, тогда на сегодня»

 PS H:> $s = "now is $({if (1 -eq 1){'then'}}) for today"
PS H:> $s
now is if (1 -eq 1){'then'} for today
  

Комментарии:

1. Что не так с $s = "now is $(if (1 -eq 1){'then'}) for today" ?

Ответ №1:

Это определенно возможно и довольно просто с подвыражениями

Вы были близки, просто нужно удалить внешний набор фигурных скобок

 $s = "now is $(if (1 -eq 1){'then'}) for today"
$s
  

Комментарии:

1. Большое спасибо. «Закрыть, но без сигары». Я думал, что внешние фигурные скобки будут указывать на то, что это scriptblock . Я должен стараться не быть таким умным.

Ответ №2:

Аргументы скриптового блока с задержкой привязки являются неявной функцией, которая:

 only works with parameters that are designed to take pipeline input,

    of any type except the following, in which case regular parameter binding happens[1]:
        [scriptblock]
        [object] ([psobject], however, does work, and therefore [pscustomobject] too)
        (no type specified), which is effectively the same as [object]

    whether such parameters accept pipeline input by value (ValueFromPipelineBy) or by property name (ValueFromPipelineByPropertyName), is irrelevant.

enables per-input-object transformations via a script block passed instead of a type-appropriate argument; the script block is evaluated for each pipeline object, which is accessible inside the script block as $_, as usual, and the script block's output - which is assumed to be type-appropriate for the parameter - is used as the argument.

    Since such ad-hoc script blocks by definition do not match the type of the parameter you're targeting, you must always use the parameter name explicitly when passing them.

    Delay-bind script blocks unconditionally provide access to the pipeline input objects, even if the parameter would ordinarily not be bound by a given pipeline object, if it is defined as ValueFromPipelineByPropertyName and the object lacks a property by that name.
        This enables techniques such as the following call to Rename-Item, where the pipeline input from Get-Item is - as usual - bound to the -LiteralPath parameter, but passing a script block to -NewName - which would ordinarily only bind to input objects with a .NewName property - enables access to the same pipeline object and thus deriving the destination filename from the input filename:
            Get-Item file | Rename-Item -NewName { $_.Name   '1' }  # renames 'file' to 'file1'; input binds to both -LiteralPath (implicitly) and the -NewName script block.

    Note: Unlike script blocks passed to ForEach-Object or Where-Object, for example, delay-bind script blocks run in a child variable scope[2], which means that you cannot directly modify the caller's variables, such as incrementing a counter across input objects.
    As a workaround, use a [ref]-typed variable declared in the caller's scope and access its .Value property inside the script block - see this answer for an example.