我遇到了一个脚本,该脚本可以在PowerShell V5.0中运行,但不能在V2.0中运行。
我需要比较两个CSV文件中的两列,如果两个文件中都存在一个值,则用一个CSV编辑一个值。
这是一个有问题的例子。 $a
在V5.0中被重命名为1X,而在V2.0中仍被重命名为1。我尝试使用Compare
,但这并不能解决我的问题。不幸的是,不能在该特定计算机上升级到V5.0。您能提供的任何建议将不胜感激。
# create examples
$a = @()
$itema = New-Object PSObject
$itema | Add-Member -Type NoteProperty -Name 'ID' -Value '1'
$a += $itema
$b = @()
$itemb = New-Object PSObject
$itemb | Add-Member -Type NoteProperty -Name 'ID' -Value '1'
$b += $itemb
# problem
foreach ($value in $a) {
$ID = $value.ID
if ($b.ID -contains $ID) {$value.ID = $ID + "X"}
}
答案 0 :(得分:1)
PowerShell v2不支持member enumeration,这是您在此处使用的语言:
$b.ID -contains $ID
PowerShell v3中引入了该功能。
在PowerShell v2中,$b.ID
尝试扩展 array ID
的属性$b
,由于数组对象不具有空属性,因此会产生空结果这样的财产。
在PowerShell v3和更高版本中,$b.ID
尝试在数组ID
的 elements 上扩展属性$b
(如果数组对象本身没有扩展)具有该属性)。
要使您的代码与PowerShell v2兼容,请更改以下内容:
if ($b.ID -contains $ID) {$value.ID = $ID + "X"}
对此:
if (@($b | Select-Object -Expand ID) -contains $ID) {$value.ID = $ID + "X"}
附录:
出于性能方面的考虑,将ID列表仅在循环外扩展一次并将其存储在单独的变量中是很有意义的
$id_list = @($b | Select-Object -Expand ID)
,然后在比较中使用该变量:
if ($id_list -contains $ID) {$value.ID = $ID + "X"}
如果真的想让您 提高性能,建议您根据ID创建哈希表
$id_list = @{}
foreach ($e in $b) {
$id_list[$e.ID] = $true
}
并进行如下比较:
if ($id_list.ContainsKey($ID)) {$value.ID = $ID + "X"}
哈希表查找比-contains
操作提供更好的性能,因为前者执行索引查找,而后者对数组进行线性搜索。
答案 1 :(得分:0)
这是因为Powershell 2.0不支持允许您从数组中的对象中选择多个具有相同名称的属性的功能。
在更高的Powershell版本中,$b.ID
将为您提供ID
中对象中所有$b
值的数组。在Powershell 2.0中,不会发生这种情况,$.ID
是$null
,因为数组本身没有ID
属性。
您可以像这样提取数组:
$known_IDs = $b | ForEach-Object { $_.ID }
之后,这将在PowerShell 2.0中起作用:
foreach ($item_a in $a) {
if ($known_IDs -contains $item_a.ID) {
$item_a.ID += "X"
}
}
或者,作为管道:
$a | Where-Object { $known_IDs -contains $_.ID } | ForEach-Object { $_.ID += "X" }