Import-Csv 数据解析为数组

Import-Csv data parse to array

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

这个return对象之间的差异,但是值是一样的。

预期结果应该return没有,因为两个值相同。

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

此 post 不再直接回答 OP 的问题,而是提供对类似情况有帮助的背景信息。这个特殊问题通过在比较数据之前处理 CR 和 LF 字符来解决。有关详细信息,请参阅

由于在这种情况下 $data 是一个名为 value 的 属性 对象,用于保存您的数据,因此您需要比较存储在 value 中的内容 属性 到你的 $regval:

Compare-Object $data.value $regval

$regval 是一个字符串数组 ,然后 将其通过管道传输到 Out-String。在管道之后,它 变成 一个 字符串对象 。在管道传输到 Out-String.

之前,请参阅下面的类型信息
$regval.gettype().fullname
System.String[]

$data是一个对象数组(PSCustomObjects),每个对象都有一个名为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;}

为了使用 Compare-Object 比较两个对象的数据,最好的结果似乎是当对象是同一类型的集合时。在某些情况下,PowerShell 会自动在后台进行转换,例如 Compare-Object "1" 1。也许这与值类型有关,因为我不完全确定。我会比较 before converting 你的任何数据到不同的类型。那么如果你引用$dataValue属性,这个条件成立:

$data.value | Get-member -type Property

   TypeName: System.String

Name   MemberType Definition
----   ---------- ----------
Length Property   int Length {get;}

您可以参考 了解有关 PowerShell 如何处理数组类型的更多信息。

最可能的解释是:

  • 来自您的 CSV 的 多行值(从 单个字段 获得)包含 LF-only ( 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-only 和 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() 调用再次将其删除。