Powershell color formatting with format operator

我的梦境 提交于 2020-07-03 04:22:13

问题


I'm using a format operator inside a script with a following example:

$current = 1
$total   = 1250
$userCN  = "contoso.com/CONTOSO/Users/Adam Smith"

"{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN

This excpectedly shows the following output:

SUCCESS: Updated user 1/1250 : contoso.com/CONTOSO/Users/Adam Smith

The format operator is there to keep the targeted output text in place with current / total running numbers varying between 1-99999. Without the format operator I could highlight the success line like this:

Write-Host -BackgroundColor Black -ForegroundColor Green "SUCCESS: Updated user $current/$total: $userCN"

But the question is how could I use the highlight-colors combined with the format operator? There's only the -f parameter and it doesn't allow the color parameters because, well, it's not the same thing as Write-Host in the first place.


回答1:


Unlike other shells, PowerShell allows you to pass commands and expressions as command arguments simply by enclosing them in parentheses (...).

When calling PowerShell commands (cmdlets, scripts, functions), the output is passed as-is as an argument, as its original output type.

Therefore, Theo's solution from a comment is correct:

Write-Host -BackgroundColor Black -ForegroundColor Green `
           ("{0, -35}: {1}" -f "SUCCESS: Updated user $current/$total", $userCN) 

That is, the -f expression inside (...) is executed and its output - a single string in this case - is passed as a positional argument to Write-Host (implicitly binds to the -Object parameter).


Note that you do not need, $(...), the subexpression operator, in this case.

In fact, in certain cases $(...) can inadvertently modify your argument, because it unwraps single-element arrays:

# Pass a single-element array to a script block (which acts like a function).
# (...) preserves the array as-is.
PS> & { param($array) $array.GetType().Name } -array ([array] 1)
Object[]  # OK - single-element array was passed as-is

# $(...) unwraps it.
PS> & { param($array) $array.GetType().Name } -array $([array] 1)
Int32  # !! Single-element array was unwrapped.

The primary use of $(...) is:

  • expanding the output from expressions or commands inside expandable strings (string interpolation)

  • To send the output of compound statements such as foreach (...) { ... } and if (...) { ... } directly through the pipeline, after collecting the output up front; however, you can alternatively wrap such statements in . { ... } (to execute in the same scope) or . { ... } (to execute in a child scope) in order to get the usual streaming behavior (one-by-one passing of output) in the pipeline.

    • Taking a step back: Given that you already can use compound statements as expressions in variable assignments - e.g., $evenNums = foreach ($num in 1..3) { $num * 2 } - and expressions generally are accepted as the first segment of a pipeline - e.g., 'hi' | Write-Host -Fore Yellow - it is surprising that that currently doesn't work with compound statements; this GitHub issue asks if this limitation can be lifted.

In the context of passing arguments to commands:

  • Use $(...), the subexpression operator only if you want to pass the output from multiple commands or (one or more) compound statements as an argument and/or, if the output happens to be a single object, you want that object to be used as-is or, if it happens to be a single-element array (enumerable), you want it to be unwrapped (pass the element itself, not the array.

    • Of course, if you're constructing a string argument, $(...) can be useful inside that string, for string interpolation - e.g., Write-Host "1 + 1 = $(1 + 1)"
  • Use @(...), the array subexpression operator only if you want to pass the output from multiple commands as an argument and/or you want to ensure that the output becomes a array; that is, the output is returned as a (regular PowerShell) array, of type [object[]], even if it happens to comprise just one object. In a manner of speaking it is the inverse of $(...)'s behavior in the single-object output case: it ensures that single-object output too becomes an array.



来源:https://stackoverflow.com/questions/58247606/powershell-color-formatting-with-format-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!