【问题标题】:How to populate two arrays as result of Compare-Object如何填充两个数组作为比较对象的结果
【发布时间】:2021-12-19 03:17:53
【问题描述】:

我正在尝试在加载 CSV 时进行一些检查,并通知用户发现了哪些额外的标题以及哪些标题仍然缺失。 $headers_required 将被硬编码,$headers_loaded 将由 Import-CSV 填充 目标是用与另一个数组的差异填充这两个数组,例如 Unix 中的 diff。

$headers_required=@( `
'Path', `
'GivenName', `
'Name', `
'EmailAddress', `
'sAMAccountName', `
'psw-temp', `
'Path', `
'ChangePasswordAtLogon' `
)

$headers_loaded=@( `
'Path', `
'GivenName', `
'Name', `
'PhoneNumber', `
'PreferredFilm', `
'sAMAccountName', `
'psw-temp', `
'Path', `
'ChangePasswordAtLogon', `
'BankAccount' `
)

最终我想拥有

$extra_headers_not_nedeed=@('BankAccount', 'PhoneNumber', 'PreferredFilm')
$missing_headers=@('EmailAddress')

我可以用这种方式过滤它们

$extra_headers_not_nedeed=Compare-Object ($headers_required|Sort-Object) ($headers_loaded|Sort-Object) | Where SideIndicator -eq '<='
$missing_headers=Compare-Object ($headers_required|Sort-Object) ($headers_loaded|Sort-Object) | Where SideIndicator -eq '=>'

我会过滤它们

PS C:\> $missing_headers|Write-host
@{InputObject=EmailAddress; SideIndicator=<=}

PS C:\> $extra_headers_not_needed|Write-host
@{InputObject=BankAccount; SideIndicator==>}
@{InputObject=PhoneNumber; SideIndicator==>}
@{InputObject=PreferedFilm; SideIndicator==>}
  1. 我怎样才能得到上面指定的普通数组而不是结构化对象?我试过 $missing_headers['InputObject'] 但它返回整个对象而不是 'EmailAddress'

  2. 是否有更紧凑的方式(除了符号)来获得相同的结果?

TIA

【问题讨论】:

    标签: arrays powershell


    【解决方案1】:

    我会使用function,您可以重复使用它并动态分配新的参考标头以与您的 Csv 进行比较。

    我个人不会使用Compare-Object,我认为这会带走所有乐趣。

    function Test-Csv {
    param(
        [parameter(mandatory)]
        [string[]]$ReferenceHeaders,
        [parameter(mandatory)]
        [object]$InputObject
    )
        
        $csvHeaders = $InputObject[0].PSObject.Properties.Name
        $valid, $missing = $ReferenceHeaders.where({ $_ -in $csvHeaders }, 'Split')
        $invalid = $csvHeaders.where({ $_ -notin $ReferenceHeaders })
        
        $valid.foreach({
            [pscustomobject]@{
                HeaderName = $_
                Status = 'Valid'
            }
        })
        $missing.foreach({
            [pscustomobject]@{
                HeaderName = $_
                Status = 'Missing'
            }
        })
        $invalid.foreach({
            [pscustomobject]@{
                HeaderName = $_
                Status = 'Invalid'
            }
        })
    }
    

    用法

    # Define the Reference Headers
    $requiredHeaders =@( 
        'Path' 
        'GivenName' 
        'Name' 
        'EmailAddress' 
        'sAMAccountName' 
        'psw-temp' 
        'ChangePasswordAtLogon' 
    )
    
    # This example Csv would be the one you import from a file as an example
    $exampleCsv = @'
    GivenName,sAMAccountName,RandomHeader1,Path,RandomHeader2
    z,z,z,z,z
    '@ | ConvertFrom-Csv
    
    PS \> Test-Csv -ReferenceHeaders $requiredHeaders -InputObject $exampleCsv
    
    HeaderName            Status 
    ----------            ------ 
    Path                  Valid  
    GivenName             Valid  
    sAMAccountName        Valid  
    Name                  Missing
    EmailAddress          Missing
    psw-temp              Missing
    ChangePasswordAtLogon Missing
    RandomHeader1         Invalid
    RandomHeader2         Invalid
    

    PS \> $result = Test-Csv -ReferenceHeaders $requiredHeaders -InputObject $exampleCsv
    
    PS \> $result | Where-Object Status -EQ 'Missing'
    
    HeaderName            Status 
    ----------            ------ 
    Name                  Missing
    EmailAddress          Missing
    psw-temp              Missing
    ChangePasswordAtLogon Missing
    
    PS \> $result | Where-Object Status -EQ 'Invalid'
    
    HeaderName    Status 
    ----------    ------ 
    RandomHeader1 Invalid
    RandomHeader2 Invalid
    

    【讨论】:

    • 这很有趣,但是你如何得到'missing'和'extra'这两个数组呢?
    • @Alex 当然,我让函数输出pscustomobject 数组的原因是因为它很容易过滤并从中创建新数组。看我上次的编辑:)(我用Invalid而不是Extra,但如果你愿意,你绝对可以改变它)
    【解决方案2】:

    -PassThru 参数添加到compare-object 命令:

    # ~> $extra_headers_not_nedeed=Compare-Object ($headers_required|Sort-Object) ($headers_loaded|Sort-Object) -passthru| Where SideIndicator -eq '<='
    # ~> $extra_headers_not_nedeed
    EmailAddress
    
    # ~> $missing_headers=Compare-Object ($headers_required|Sort-Object) ($headers_loaded|Sort-Object) -PassThru | Where SideIndicator -eq '=>'
    # ~> $missing_headers
    BankAccount
    PhoneNumber
    PreferredFilm
    

    【讨论】:

    • 谢谢 ZDAN,最终我喜欢我可以通过 $extra_headers_not_nedeed.'InputObject' => EmailAddress 提取数据
    【解决方案3】:

    只是另一种选择:

    Clear-Host
    
    $Extra_Headers_Not_Needed = New-Object -TypeName 'System.Collections.ArrayList'
    $Missing_Headers          = New-Object -TypeName 'System.Collections.ArrayList'
    $x = Compare-Object ($headers_required|Sort-Object) ($headers_loaded|Sort-Object)
    
    ForEach ( $header in $x) {
       Switch  (($Header).SideIndicator) {
       '=>' {$Null = $Extra_Headers_Not_Needed.Add($Header.InputObject)  ; Break}
       '<=' {$Null = $Missing_Headers.Add($Header.InputObject)           ; Break}
       Default {"Error: $($Header.InputObject)" }
       }
    }
    "Not Needed $($Extra_Headers_Not_Needed.Count) :"
    $Extra_Headers_Not_Needed
    "`nMissing Headers $($Missing_Headers.Count) :"
    $Missing_Headers
    

    输出:

    Not Needed 3 :
    BankAccount
    PhoneNumber
    PreferredFilm
    
    Missing Headers 1 :
    EmailAddress
    

    【讨论】:

      【解决方案4】:

      感谢 Zdan 和 Santiago,

      最终我也发现了这种方式(来自 a[key]='value' 概念)

      PS C:\> $missing_headers.'InputObject'
      BankAccount
      PhoneNumber
      PreferredFilm
      
      PS C:\> $extra_headers_not_nedeed.'InputObject'
      EmailAddress
      

      因为

      PS C:> $extra_headers_not_nedeed.psobject.properties
      
      MemberType      : NoteProperty
      IsSettable      : True
      IsGettable      : True
      Value           : EmailAddress
      TypeNameOfValue : System.String
      Name            : InputObject
      IsInstance      : True
      
      MemberType      : NoteProperty
      IsSettable      : True
      IsGettable      : True
      Value           : <=
      TypeNameOfValue : System.String
      Name            : SideIndicator
      IsInstance      : True
      

      【讨论】:

        猜你喜欢
        • 2016-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多