Import-Csv数据解析到数组

时间:2019-03-28 10:18:07

标签: powershell compareobject

我有一个CSV文件,其中某些单元格包含多行。我将使用这些数据来比较从powershell获得的值。

这将返回对象之间的差异,但是值是相同的。

预期结果应不返回任何内容,因为两个值相同。

CSV内容:

Value
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

代码:

PS> $data = Import-Csv .\tr.csv

PS> $data.Value
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

PS> $regval = ((Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg\AllowedExactPaths).machine | Out-String).Trim()

PS> $regval
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

PS> Compare-Object $data.Value $regval
System\CurrentControlSet\Control\ProductOptions...                                                                                                  =>
System\CurrentControlSet\Control\ProductOptions...                                                                                                  <=

PS> $Tostring = ($data.Value | out-string).Trim()

PS> Compare-Object $Tostring $regval

InputObject                                                                                                                                         SideIndicator
-----------                                                                                                                                         -------------
System\CurrentControlSet\Control\ProductOptions...                                                                                                  =>
System\CurrentControlSet\Control\ProductOptions...                                                                                                  <=


PS> $Tostring.Length
145

PS> $regval.Length
147

2 个答案:

答案 0 :(得分:3)

此帖子不再直接回答OP的问题,而是提供有助于类似情况的背景信息。通过在比较数据之前处理CR和LF字符可以解决此特定问题。有关详细信息,请参见Marked Answer

由于在这种情况下$@"(?<![\w.]){Regex.Escape(numberToReplace.ToString())}(?![\w.])"是一个具有名为$data的属性的对象,可以保存您的数据,因此您需要将value属性中存储的内容与{{1} }:

value

$regval是一个字符串数组,之前是将其通过管道传递到Compare-Object $data.value $regval 的地方。在管道之后,它成为一个字符串对象。在传递到$regval之前,请参见下面的类型信息。

Out-String

Out-String是一个对象数组(PSCustomObjects),每个对象都有一个名为$regval.gettype().fullname System.String[] 的属性,如果需要其数据,则需要直接引用该属性:

$data

为了使用Value比较两个对象的数据,当对象是相同类型的集合时,似乎会出现最好的结果。在某些情况下,例如$data.gettype().fullname System.Object[] $data | Get-Member TypeName: System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Value NoteProperty string Value=System\CurrentControlSet\Control\ProductOptions ($regval | Get-member).where({$_.MemberType -eq "Property"}) TypeName: System.String Name MemberType Definition ---- ---------- ---------- Length Property int Length {get;} ,PowerShell会在后台自动进行转换。也许这与值类型有关,因为我不确定。我会在之前 转换为不同类型的数据进行比较。然后,如果您引用Compare-Object的{​​{1}}属性,则该条件变为true:

Compare-Object "1" 1

有关PowerShell如何处理数组类型的更多信息,您可以参考MKlement0's Explanation

答案 1 :(得分:1)

最可能的解释是:

  • CSV中的多行值(从单个字段获取)包含仅LF(Unix风格)换行符
  • 由于从注册表值派生的字符串具有 CRLF(Windows风格)换行符,这是由于将Out-String应用于了数组

最直接的解决方法是删除CR字符。来自$regval(您可以在PowerShell中使用"`r"生成CR字符):

# ...

# Remove all CRs from $regval.
# Note that not providing a replacement string (missing 2nd RHS operand)
# default to the empty string, which effectively *removes* what was matched.
$regval = $regval -replace "`r"

# Should now work as expected.
Compare-Object $data.Value $regval

说:

  • 由于您只比较两个字符串对象,因此可以避免Compare-Object的开销,而只需使用-eq

    $data.Value -eq $regVal
    
  • 或者,您可以将多行值拆分为行数组,然后分别进行比较。请注意,如果您使用正则表达式"`r?`n"或('\r?\n')来匹配换行符以分隔-匹配仅LF和CRLF换行符,则无需删除CR字符。首先,甚至将Out-String应用于Get-ItemProperty HKLM:\...调用的数组输出;但是,使用问题中的变量值,您可以使用:

    # Newline-style-agnostic
    Compare-Object ($data.Value -split "`r?`n") ($regval -split "`r?`n")
    
    # Or, knowing that $data.Value has LF, and $regval CRLF
    Compare-Object ($data.Value -split "`n") ($regval -split "`r`n")
    
    # Or, by using the [string[]] array of registry values directly:
    $regvals = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg\AllowedExactPaths).machine
    Compare-Object ($data.Value -split "`n") $regvals
    

关于您尝试过的事情:

  

$Tostring = ($data.Value | out-string).Trim()

如果$data.Value是一个没有 trailing 换行符的字符串-是否已嵌入 换行符-以上是有效的无操作

  • 已经是字符串的输入对象由Out-String通过原样传递。
  • 尽管Out-String确实附加了CRLF换行符(在Windows上),但随后的.Trim()调用再次将其删除。