将列添加到 Powershell 显示输出
Add Column to Powershell Display Output
我正在编写一个脚本来审计我们虚拟环境中的磁盘分区类型。我得到了产生以下输出的代码:
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText {Get-Disk | select Number, @{name='Size (GB)';expr={[int]($_.Size/1GB)}}, PartitionStyle} -VM $vmName -GuestUser $Username -GuestPassword $Password
$output.ScriptOutput | FT -AutoSize
输出:
Number Size (GB) PartitionStyle
------- --------- --------------
0 160 MBR
这本身就很好,但是我还想添加 VM 的名称,因为这将循环遍历数千个 VM。我试过了,但它为 ComputerName:
产生了空白输出
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText {Get-Disk | select @{l="ComputerName";e={$vmName}}, Number, @{name='Size (GB)';expr={[int]($_.Size/1GB)}}, PartitionStyle} -VM $vmName -GuestUser $Username -GuestPassword $Password
$output.ScriptOutput | FT -AutoSize
输出:
ComputerName Number Size (GB) PartitionStyle
------------ ------ --------- --------------
0 160 MBR
关于如何使这项工作有任何想法吗?
作为奖励,关于如何在其中添加 VM 的实际名称的任何想法,因为 vSphere 名称可能不是机器的实际名称?
tl;dr
Invoke-VMScript -ScriptText
accepts only a string containing PowerShell commands, not a script block ({...}
).
由于没有单独的参数用于将 arguments 传递给 -ScriptText
代码,唯一的方法是包含 - 总是stringified - 来自 caller's 范围的值是使用 string 插值 ,如图所示在下一节中。
- 值得注意的是,通常的基于脚本块的机制使用
$using:
范围来嵌入来自调用者的值不工作。
将脚本块文字 { ... }
传递给 -ScriptText
技术上 有效,因为在转换为字符串时 verbatim 使用了 {
和 }
之间的内容,但是 最好避免,以避免概念混淆.
注:
下面是对您的问题的解释以及对您原来的方法.
的修复
您可以绕过您的问题如果您添加计算列 通过 select
(Select-Object
) on the caller's side (as hinted at by iRon), using the VM
property of the object output by Invoke-VMScript
, which contains the remote computer name (which Lee_Dailey 帮助发现):
$vmName = "VM NAME"
# Only run `Get-Disk` remotely, and run the `select` (`Select-Object`)
# command *locally*:
# Note the need to extract the actual script output via the .ScriptOutput
# property and the use of the .VM property to get the computer name.
$output = Invoke-VMScript -ScriptText { Get-Disk } -VM $vmName -GuestUser $Username -GuestPassword $Password |
select -ExpandProperty ScriptOutput -Property VM |
select @{l="ComputerName";e='VM'}, Number, @{name='Size (GB)';expr={[int]($_.Size/1GB)}}, PartitionStyle
您通过 -ScriptText
传递给 Invoke-VMScript
的命令是在 另一台机器 上执行的,它对您的命令一无所知本地 $vmName
变量。
在 PowerShell remoting commands such as Invoke-Command
中,$using:
范围将是解决方案:... | select @{l="ComputerName";e={$using:vmName}}, ...
但是,$using:
只能用于脚本块 ({ ... }
)。
当您 尝试 将脚本块传递给 Invoke-VMScript -ScriptText
时,它实际上在提交给 VM 之前转换为 字符串 , 因为 Invoke-VMScript
的 -ScriptText
参数是 [string]
类型的 .
由于 Invoke-VMScript
没有用于从调用者范围传递参数的单独参数,从调用者范围包含值的唯一方法是使用 字符串插值:
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText @"
Get-Disk |
select @{ l="ComputerName"; e={ '$vmName' } },
Number,
@{ name='Size (GB)'; expr={[int](`$_.Size/1GB)} },
PartitionStyle
"@ -VM $vmName -GuestUser $Username -GuestPassword $Password
注意这里使用了可扩展字符串 (@"<newline>...<newline>"@
); 重要:结束分隔符 "@
必须 在行的最开始 (甚至不允许在它之前有空格) ;有关 PowerShell 中字符串文字的更多信息,请参阅 this answer。
$vmName
现在 在调用者的作用域中预先扩展 ;要使生成的 e={ ... }
脚本块在语法上有效,扩展的 $vmName
值必须包含在 '...'
.
中
相比之下,$_
中的 $
必须被 _escaped - 作为 `$
- 因为它必须 通过 [=146] =]到远程机器。
就是说,因为您想确定远程计算机上的实际计算机名称,您甚至不需要字符串插值 ;使用 $env:COMPUTERNAME
:
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText @'
Get-Disk |
select @{ l="ComputerName"; e={ $env:COMPUTERNAME } },
Number,
@{ name='Size (GB)'; expr={[int]($_.Size/1GB)} },
PartitionStyle
'@ -VM $vmName -GuestUser $Username -GuestPassword $Password
请注意,在这种情况下 - 因为不需要字符串插值 - 使用了 verbatim(文字)here-string (@'<newline>...<newline>'@
),这也意味着不转义直通 $
字符。是必需的。
当不需要字符串插值时,您可以实际通过脚本块传递脚本文本({ ... }
),这在一定程度上简化了语法(脚本块将其逐字字符串化为 {
和 }
之间的内容),但是由于最终传递了 string,因此它是为了概念清晰,最好先使用一个。
我正在编写一个脚本来审计我们虚拟环境中的磁盘分区类型。我得到了产生以下输出的代码:
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText {Get-Disk | select Number, @{name='Size (GB)';expr={[int]($_.Size/1GB)}}, PartitionStyle} -VM $vmName -GuestUser $Username -GuestPassword $Password
$output.ScriptOutput | FT -AutoSize
输出:
Number Size (GB) PartitionStyle
------- --------- --------------
0 160 MBR
这本身就很好,但是我还想添加 VM 的名称,因为这将循环遍历数千个 VM。我试过了,但它为 ComputerName:
产生了空白输出$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText {Get-Disk | select @{l="ComputerName";e={$vmName}}, Number, @{name='Size (GB)';expr={[int]($_.Size/1GB)}}, PartitionStyle} -VM $vmName -GuestUser $Username -GuestPassword $Password
$output.ScriptOutput | FT -AutoSize
输出:
ComputerName Number Size (GB) PartitionStyle
------------ ------ --------- --------------
0 160 MBR
关于如何使这项工作有任何想法吗?
作为奖励,关于如何在其中添加 VM 的实际名称的任何想法,因为 vSphere 名称可能不是机器的实际名称?
tl;dr
Invoke-VMScript -ScriptText
accepts only a string containing PowerShell commands, not a script block ({...}
).由于没有单独的参数用于将 arguments 传递给
-ScriptText
代码,唯一的方法是包含 - 总是stringified - 来自 caller's 范围的值是使用 string 插值 ,如图所示在下一节中。- 值得注意的是,通常的基于脚本块的机制使用
$using:
范围来嵌入来自调用者的值不工作。
- 值得注意的是,通常的基于脚本块的机制使用
将脚本块文字
{ ... }
传递给-ScriptText
技术上 有效,因为在转换为字符串时 verbatim 使用了{
和}
之间的内容,但是 最好避免,以避免概念混淆.
注:
下面是对您的问题的解释以及对您原来的方法.
的修复您可以绕过您的问题如果您添加计算列 通过
select
(Select-Object
) on the caller's side (as hinted at by iRon), using theVM
property of the object output byInvoke-VMScript
, which contains the remote computer name (which Lee_Dailey 帮助发现):$vmName = "VM NAME" # Only run `Get-Disk` remotely, and run the `select` (`Select-Object`) # command *locally*: # Note the need to extract the actual script output via the .ScriptOutput # property and the use of the .VM property to get the computer name. $output = Invoke-VMScript -ScriptText { Get-Disk } -VM $vmName -GuestUser $Username -GuestPassword $Password | select -ExpandProperty ScriptOutput -Property VM | select @{l="ComputerName";e='VM'}, Number, @{name='Size (GB)';expr={[int]($_.Size/1GB)}}, PartitionStyle
您通过 -ScriptText
传递给 Invoke-VMScript
的命令是在 另一台机器 上执行的,它对您的命令一无所知本地 $vmName
变量。
在 PowerShell remoting commands such as Invoke-Command
中,$using:
范围将是解决方案:... | select @{l="ComputerName";e={$using:vmName}}, ...
但是,$using:
只能用于脚本块 ({ ... }
)。
当您 尝试 将脚本块传递给 Invoke-VMScript -ScriptText
时,它实际上在提交给 VM 之前转换为 字符串 , 因为 Invoke-VMScript
的 -ScriptText
参数是 [string]
类型的 .
由于 Invoke-VMScript
没有用于从调用者范围传递参数的单独参数,从调用者范围包含值的唯一方法是使用 字符串插值:
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText @"
Get-Disk |
select @{ l="ComputerName"; e={ '$vmName' } },
Number,
@{ name='Size (GB)'; expr={[int](`$_.Size/1GB)} },
PartitionStyle
"@ -VM $vmName -GuestUser $Username -GuestPassword $Password
注意这里使用了可扩展字符串 (
@"<newline>...<newline>"@
); 重要:结束分隔符"@
必须 在行的最开始 (甚至不允许在它之前有空格) ;有关 PowerShell 中字符串文字的更多信息,请参阅 this answer。
中$vmName
现在 在调用者的作用域中预先扩展 ;要使生成的e={ ... }
脚本块在语法上有效,扩展的$vmName
值必须包含在'...'
.相比之下,
$_
中的$
必须被 _escaped - 作为`$
- 因为它必须 通过 [=146] =]到远程机器。
就是说,因为您想确定远程计算机上的实际计算机名称,您甚至不需要字符串插值 ;使用 $env:COMPUTERNAME
:
$vmName = "VM NAME"
$output = Invoke-VMScript -ScriptText @'
Get-Disk |
select @{ l="ComputerName"; e={ $env:COMPUTERNAME } },
Number,
@{ name='Size (GB)'; expr={[int]($_.Size/1GB)} },
PartitionStyle
'@ -VM $vmName -GuestUser $Username -GuestPassword $Password
请注意,在这种情况下 - 因为不需要字符串插值 - 使用了 verbatim(文字)here-string (@'<newline>...<newline>'@
),这也意味着不转义直通 $
字符。是必需的。
当不需要字符串插值时,您可以实际通过脚本块传递脚本文本({ ... }
),这在一定程度上简化了语法(脚本块将其逐字字符串化为 {
和 }
之间的内容),但是由于最终传递了 string,因此它是为了概念清晰,最好先使用一个。