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 你的任何数据到不同的类型。那么如果你引用$data
的Value
属性,这个条件成立:
$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()
调用再次将其删除。
我有一个 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 你的任何数据到不同的类型。那么如果你引用$data
的Value
属性,这个条件成立:
$data.value | Get-member -type Property
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Length Property int Length {get;}
您可以参考
最可能的解释是:
- 来自您的 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()
调用再次将其删除。