Powershell:将变量从一个CSV比较到另一个CSV,并在此基础上创建新变量

Powershell:将变量从一个CSV比较到另一个CSV,并在此基础上创建新变量,powershell,Powershell,有人要问的问题是编辑试用后的方法您的csv文件格式不正确,因此我无法确定这是否正是您所需要的,但这应该为您指明正确的方向: $File1 = Import-Csv .\file1.csv -Delimiter "`t" $File2 = Import-Csv .\file2.csv -Delimiter "`t" $NewFile1 = $File1 | % { $Obj = [PSCustomObject]$_ $Obj | Add-Member -Mem NotePrope

有人要问的问题是编辑试用后的方法

您的csv文件格式不正确,因此我无法确定这是否正是您所需要的,但这应该为您指明正确的方向:

$File1 = Import-Csv .\file1.csv -Delimiter "`t"
$File2 = Import-Csv .\file2.csv -Delimiter "`t"

$NewFile1 = $File1 | % {
    $Obj = [PSCustomObject]$_
    $Obj | Add-Member -Mem NoteProperty -Name Patched -Value ([bool]($_.CommanName -in $File2.CommanName))
    return $Obj
}

$NewFile1
哪个会输出

Server   HotfixID CommanName      Patched
------   -------- ----------      -------
apdk778  kb3333   apdk778 kb3333     True
apdk778  yn2919   apdk778 yn2919     True
apdk778  lk4898   apdk778 lk4898     True
iijka211 kb3333   iijka211 kb3333   False
iijka211 yn2919   iijka211 yn2919    True
iijka211 lk4898   iijka211 lk4898    True
为了读取csv文件,我用制表符替换了前两组空格。

效果很好,但您可以简化为定义计算属性的单个选择对象调用,该调用的性能也更好:

$file1Objects = Import-Csv .\file1.csv -Delimiter "`t"
$file2Objects = Import-Csv .\file2.csv -Delimiter "`t"

$decoratedFile1Objects = $file1Objects | Select-Object *,
  @{ n='Patched'; e={ ('No', 'Yes')[$file2Objects.CommanName -contains $_.CommanName] } }
简要说明计算属性的工作原理;有关更详细的解释,请参阅我的

请注意,使用惯用法[]根据布尔测试的结果从两个选项中选择一个:

“否”、“是”是一个字符串数组,其元素无索引0,有索引1。 $file2Objects.CommanName-包含$\值。CommanName是一个布尔表达式,在数组索引[…]的上下文中使用时,如果$False,则强制为0,如果$True,则强制为1。 换言之:

如果布尔表达式返回$False,则使用索引0,结果是字符串No。 如果布尔表达式返回$True,则使用索引1,结果为字符串Yes。 请注意,这种方法是PowerShell缺少其他语言(如C)所具有的三元条件以及指定分支的顺序颠倒的一种变通方法:

C伪代码:?是的,不是 PowerShell解决方案:“否”、“是”[] 除了分支/选项的顺序之外,还有另一个重要的区别:如果数组元素是命令/表达式,那么它们都会被计算,而不管选择哪一个,都不会发生短路。 有一个突出的问题。 至于你尝试了什么:

您的嵌套foreach循环方法:

不为未修补的行创建输出对象 并且,对于修补行,创建一个新对象,其唯一属性是新对象。 下面的代码修复了这些问题,再次依赖Select Object添加新属性:

$decoratedFile1Objects = foreach ($f1 in $file1) {
  # Add property and default to 'No'
  $f1Decorated = Select-Object -InputObject $f1 *, @{ n='Patched'; e={ 'No' } } 
  foreach($f2 in $file2) {
    if ($f1.CommanName -eq $f2.CommanName) { 
      # Match found: set property to 'Yes' and exit the inner loop
      $f1Decorated.Patched = 'Yes'
      break
    }
  }
  $f1Decorated  # Output the decorated object.
}

但是,使用PowerShell的-contains和-in-array membership测试运算符不仅更加方便,而且性能也更好。

您的csv文件都无法正常工作,能否请您将它们更新为用逗号或制表符分隔,以便我们能够准确地看到您试图读取的内容?这是否会检查给定的服务器,或者只是CommanName存在于所有服务器上?我认为您必须过滤掉$File2的一个子集,例如$serverDetails=$File2 | Where Object{$\uu.Server-eq$Obj.Server}。感谢你,这在现实中并不清楚question@gms0ulman他已经包括了一个包含服务器名称和更新的专栏,我想-如果我对Csv格式有错误,我可以用两个循环的解决方案更新,但我认为这对他来说没问题。很好的一点,我忽略了逗号是其他两个专栏的组合。做得很好。只是想向初学者展示一个简短但可能更晦涩的变体:$|在$File2.CommanName中添加Member-PassThru-Mem NoteProperty-Name Patched-Value[bool]$|.CommanName-作为%脚本块的主体就足够了。@AtulD:很高兴听到这个。我添加了一个变量赋值,类似于$all=。。。为了清楚起见。