IF 包含多个字符串 do "this" else "this"

IF contains more than one string do "this" else "this"

如果存在具有相同名称的 SCOM 组,则尝试制作请求更多信息(组 ID)的脚本:

function myFunction {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true)]
        [string[]]$ObjectName
    )

    foreach ($o in $ObjectName) {
        $p = Get-SCOMGroup -DisplayName "$o" | select DisplayName
        <#
        if ($p contains more than one string) {
            "Request group Id"
        } else {
            "do this"
        }
        #>            
    }
}

在评论区中需要有关功能的帮助。

将值包装在数组子表达式中 @() 并计算它有多少条目:

if(@($p).Count -gt 1){"Request group Id"}

注意:此答案补充

计算对象的数量return由命令编辑:

  • Mathias 的回答显示了一个 强大的、PowerShell v2 兼容的解决方案 基于 array sub-expression operator@().

      # @() ensures that the output of command ... is treated as an array,
      # even if the command emits only *one* object.
      # You can safely call .Count (or .Length) on the result to get the count.
      @(...).Count 
    
  • PowerShell v3 或更高版本中,您可以像对待集合一样对待标量,因此仅使用 (...).Count 通常就足够了 。 (标量是单个对象,而不是对象集合)。

      # Even if command ... returns only *one* object, it is safe
      # to call .Count on the result in PSv3+
      (...).Count
    

这些方法通常,但并不总是可以互换,如下所述。


  • 选择@(...).Count,如果:

    • 您必须保持 PSv2 兼容
    • 您想要统计 多个 命令的输出(用 ; 或换行符分隔)
    • 对于将整个集合作为单个对象输出的命令(这种情况很少见),您希望将此类集合计数为1对象.[1]
    • 更一般地说,如果您需要确保命令输出 return 作为真正的 数组 编辑,但请注意它总是类型 [object[]];如果您需要 特定元素类型 ,请使用强制转换(例如 [int[]]),但请注意,您并不严格需要 @(...);例如,
      [int[]] (...) 会做 - 除非你想防止枚举集合输出为单个对象。
  • 选择(...).Count,如果:

    • 只有一个命令的输出必须计算
    • 对于将整个集合作为单个对象输出的命令,您想要计算此类集合的单个元素;也就是说,(...) 强制枚举命令输出。[2]
    • 用于计算命令输出的元素已经存储在变量中 - 当然,您随后可以简单地省略 (...) 并使用 $var.Count

警告:由于a longstanding bug(从 PowerShell Core 6.2.0 开始仍然存在),在 标量上访问 .Count Set-StrictMode -Version 2 或更高版本生效时失败 - 在这种情况下使用 @(...),但请注意,您可能必须强制枚举。

为了展示与将集合作为单个对象输出的(罕见)命令的行为差异

PS> @(Write-Output -NoEnumerate (1..10)).Count 
1  # Array-as-single-object was counted as *1* object

PS> (Write-Output -NoEnumerate (1..10)).Count 
10  # Elements were enumerated.

性能考虑:

  • 如果一个命令的输出是直接计数,(...)@(...)执行的差不多:

      $arr = 1..1e6  # Create an array of 1 million integers.
    
      { (Write-Output $arr).Count }, { @(Write-Output $arr).Count } | ForEach-Object {
        [pscustomobject] @{
          Command = "$_".Trim()
          Seconds = '{0:N3}' -f (Measure-Command $_).TotalSeconds
        }
      }
    
    • 示例输出,来自单核 Windows 10 VM(绝对时间并不重要,只是数字几乎相同):

          Command                    Seconds
          -------                    -------
          (Write-Output $arr).Count  0.352
          @(Write-Output $arr).Count 0.365
      
  • 相比之下,对于大型集合 已经存储在变量中 @(...) 引入了大量开销 ,因为集合被重新创建为(新)数组(如前所述,您可以 $arr.Count):

      $arr = 1..1e6  # Create an array of 1 million integers.
    
      { ($arr).Count }, { @($arr).Count } | ForEach-Object {
        [pscustomobject] @{
          Command = "$_".Trim()
          Seconds = '{0:N3}' -f (Measure-Command $_).TotalSeconds
        }
      }
    
    • 示例输出;注意 @(...) 解决方案是如何慢 7 倍的:

          Command       Seconds
          -------       -------
          ($arr).Count  0.009
          @($arr).Count 0.067
      

编码风格注意事项:

以下情况适用于 @(...)(...) 在功能上等效(并且执行相同或性能次要)的情况,即当您 自由选择要使用的结构

Mathias 推荐 @(...).Count,在评论中指出:

There's another reason to explicitly wrap it in this context - conveying intent, i.e., "We don't know if $p is a scalar or not, hence this construct".

我投给 (...).Count:

一旦您了解 PowerShell(v3 或更高版本)将标量视为按需计数为 1 的集合,您就可以自由利用这些知识,而无需在 语法:

  • 编写代码时,这意味着 您不必担心给定的命令 情境 是否可能 return 标量而不是集合(这在 PowerShell 中很常见,其中使用 单个 输出对象捕获命令的输出按原样捕获该对象,而 2 个或更多 个输出对象导致 数组).

  • 作为有益的副作用,代码变得更简洁(有时更快)。

示例:

# Call Get-ChildItem twice, and, via Select-Object, limit the 
# number of output objects to 1 and 2, respectively.
1..2 | ForEach-Object {

  # * In the 1st iteration, $var becomes a *scalar* of type [System.IO.DirectoryInfo]
  # * In the 2nd iteration, $var becomes an *array* with 
  #   2 elements of type [System.IO.DirectoryInfo]
  $var = Get-ChildItem -Directory / | Select-Object -First $_

  # Treat $var as a collection, which in PSv3+ works even
  # if $var is a scalar:
  [pscustomobject] @{
    Count = $var.Count
    FirstElement = $var[0]
    DataType = $var.GetType().Name
  }

}

以上结果:

Count FirstElement  DataType
----- ------------  --------
    1 /Applications DirectoryInfo
    2 /Applications Object[]

也就是说,即使 System.IO.DirectoryInfo 类型的标量对象也明智地将其 .Count 报告为 1 并允许使用 [0] 访问“其第一个元素”。

有关标量和集合的统一处理的更多信息,请参阅


[1] 例如,@(Write-Output -NoEnumerate 1, 2).Count1,因为 Write-Output 命令输出一个 单个 对象 -数组 1, 2 - _作为一个整体。因为只输出一个对象,@(...) 将该对象包装在一个数组中,导致 , (1, 2),即一个单元素数组,其第一个也是唯一一个元素本身就是一个数组。

[2] 例如,(Write-Output -NoEnumerate 1, 2).Count2,因为即使 Write-Output 命令将数组输出为单个对象,该数组也用作-是。也就是说,整个表达式等价于(1, 2).Count。更一般地说,如果 (...) 中的命令仅输出 one 对象,则该对象按原样使用;如果它输出 多个 对象,它们将收集在常规 PowerShell 数组(类型 [object[]])中 - 这与通过 [=121 捕获命令输出时得到的行为相同=]变量赋值 ($captured = ...)。