在 Powershell 的 Select-Object 中使用变量

Using variable in Select-Object in Powershell

提问人:Greg 提问时间:8/2/2023 最后编辑:mklement0Greg 更新时间:8/2/2023 访问量:103

问:

我有一个表,它是使用时间作为列名创建的。但是,如果第一行在某些 Hours(列) 中没有数据,则该列不会显示表其余部分的列。因此,我正在尝试创建一个动态选择语句,该语句将从午夜开始每小时获取一次,并将这些时间用作搜索变量。我已经完成了创建Select语句,但它没有调用/执行查询。

任何返回数据并构建 HTML 表格的建议将不胜感激。

法典:

$UniversalCurrTime = ((Get-Date).ToUniversalTime()).ToString('h tt')
$UniversalMidnight = ((Get-Date).ToUniversalTime().Date).ToString('h tt')
$hoursBetween = $UniversalMidnight

Write-host 'This is midnight: ' $UniversalMidnight
Write-host 'This is Current time: ' $UniversalTime
$HourSpan = @()
$HourSpan += 'VaultName'
$HourSpan += $UniversalMidnight #($hoursBetween).ToString('h tt')
Do{
    $HourSpan += "'" + ($hoursBetween).ToString('h tt') + "'"
    $hoursBetween = (Get-date $hoursBetween).AddHours(1)
    Write-host 'This is time being added to collection: ' $hoursBetween
}while($hoursBetween -le $UniversalCurrTime)

$HourSpan += 'TotalMessages'

$selectObject = '$reportList |Select-Object ' + (($HourSpan -split '\n') -join ",") + '| ConvertTo-Html -Fragment -ErrorAction SilentlyContinue'
$html = Invoke-Command -ScriptBlock {$selectObject}

在屏幕上输出,但未执行以返回数据。

$reportList |Select VaultName,'12 AM','1 AM','2 AM','3 AM','4 AM','5 AM','6 AM','7 AM','8 AM', '9 AM','10 AM','11 AM','12 PM','1 PM','2 PM','3 PM','4 PM','5 PM','6 PM','7 PM', '8 PM', '9PM', '10 PM', '11 PM', 'TotalMessages' |Where-Object { -Not [String]::IsNullOrWhiteSpace($_) }| ConvertTo-Html -Fragment -ErrorAction SilentlyContinue

应执行此语句。

PowerShell HTML 表 invoke-command 脚本块 select-object

评论

1赞 jdweng 8/2/2023
为什么要使用 To String?您的比较期望这两个日期是 DateTime,但您的代码正在尝试比较两个字符串:$hoursBetween -le $UniversalCurrTime
0赞 Greg 8/2/2023
我将其转换为字符串以获取小时(例如下午 1 点、下午 2 点......)以将其添加到集合中,然后在比较之前将其还原为 DateTime,
0赞 KG-DROID 8/2/2023
$reportList变量中会有什么?
0赞 Greg 8/2/2023
$reportsList包含产品名称 -VaultName- 和每小时添加到数据库表的消息计数以及它们计数 -TotalMessages 的总和。

答:

0赞 mklement0 8/2/2023 #1

$selectObject = '$reportList |Select-Object ' + (($HourSpan -split '\n') -join ",") + '| ConvertTo-Html -Fragment -ErrorAction SilentlyContinue'

上面创建了一个字符串值。

$html = Invoke-Command -ScriptBlock {$selectObject}

上面的内容 - 可以简化为并最终 - 输出存储在 $selectObject 中的字符串,这解释了您所看到的内容。$html = & { $selectObject }$html = $selectObject


撇开存储在 (a) 中是否有效构造,[1] (b) 预期的时间顺序比较是否有效,以及 (c) 假设 和 被删除,您可能正在寻找以下内容:$HourSpan$HourSpan += 'VaultName'$HourSpan += 'TotalMessages'

$html = 
  $reportList |
  Select-Object (@('VaultName') + $HourSpan + 'TotalMessages') |
  ConvertTo-Html -Fragment -ErrorAction SilentlyContinue

也就是说,可以将动态构造的属性名称数组直接传递给 Select-Object 的(位置隐含的)-Property 参数

使用数组作为 LHS - 使用 ,array-subexpression 运算符确保 - 运算符执行(平面)数组连接@(...)+


PowerShell 很少要求将命令动态构造为字符串,并且由于固有的安全风险,通常应避免这样做,但在必要时,您有两种选择:

  • 对于调用方作用域中的一次性调用,请使用 Invoke-Expression;例如:

    $commandString = 'Get-Date'
    Invoke-Expression $commandString
    
  • 对于可重复的调用,请使用 [scriptblock]::Create() 从字符串构造一个脚本块,您可以根据需要重复调用它,通过 调用运算符 - 在子作用域中 - 或通过 ,点源运算符 - 直接在调用方的作用域中:&.

    $commandString = 'Get-Date'
    $scriptBlock = [scriptblock]::Create($commandString)
    # Invoke the script block on demand, in a child scope.
    # To invoke it directly in the caller's scope, use:
    #  . $scriptBlock
    & $scriptBlock
    

[1] 在循环中使用 += 扩展数组是低效的,因为鉴于数组的大小是固定的,因此每次迭代都必须在后台创建一个数组;更有效的方法是使用 do { ... } while (...) 或 foreach 循环等语句作为表达式,并让 PowerShell 本身在数组中收集输出:[array] $outputs = foreach (...) { ... } - 请参阅此答案 如果您需要手动创建数组,例如要创建多个数组,请使用高效可扩展的列表类型 - 请参阅此处

评论

1赞 Greg 8/2/2023
谢谢,谢谢,谢谢!我删除了 $HourSpan += 'VaultName' 和 $HourSpan += 'TotalMessages' 使用您推荐的解决方案修改了我的脚本,并且有效!谢谢。$html = $reportList |选择对象 (@('VaultName') + $HourSpan + 'TotalMessages') |ConvertTo-Html -fragment -ErrorAction SilentlyContinue 您在提交的内容中提供了大量知识,因此我将花时间消化其中包含的语句。
1赞 Greg 8/2/2023
我知道您没有深入研究$HourSpan逻辑,但对于未来的读者,我不得不对 $HourSpan += “'” + ($hoursBetween) 进行一些更改。ToString('h tt') + “'” to $HourSpan += $(DateTime $hoursBetween)。ToString('h tt')。我目前正在阅读您关于如何使 Array 的添加更有效率的另一篇建议文章。