Powershell-基于多字段条件删除CSV中的特定重复项/三重项

Powershell-基于多字段条件删除CSV中的特定重复项/三重项,csv,powershell,duplicates,Csv,Powershell,Duplicates,我有一份从多台服务器收集操作系统信息的工作。生成了多个CSV文件,其中包含Servername、OSCaption、OSversion(本例简化)。如果可以访问服务器,则OSCaption和OSVersion字段将正确填充。否则,输出文件的OSCaption字段中会出现一条错误消息,另一个字段(OSVersion)将保持为空。作业在不同凭据下运行多次,以尽可能多地收集操作系统信息。最后,我结合了CSV,我需要一种方法来删除某种类型的副本/三份副本,等等。。我希望保留一个具有良好OS字段的serv

我有一份从多台服务器收集操作系统信息的工作。生成了多个CSV文件,其中包含Servername、OSCaption、OSversion(本例简化)。如果可以访问服务器,则OSCaption和OSVersion字段将正确填充。否则,输出文件的OSCaption字段中会出现一条错误消息,另一个字段(OSVersion)将保持为空。作业在不同凭据下运行多次,以尽可能多地收集操作系统信息。最后,我结合了CSV,我需要一种方法来删除某种类型的副本/三份副本,等等。。我希望保留一个具有良好OS字段的servername的单个实例,删除具有错误的相同servername的任何记录,但如果服务器根本无法访问,我还希望在OSCaption中保留错误消息的任何单个实例

我有一个未排序的CSV输入文件,如下所示:

Servername,OSCaption,OSVersion
Server1,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server2,Access denied,
Server2,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server3,RDP Error,
Server4,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server2,Access Denied,
Server5 Access Denied,
Servername,OSCaption,OSVersion
Server1,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server2,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server3,RDP Error,
Server4,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server5 Access Denied,
您可以看到Server2在三个证书下运行,第二个证书工作正常。我想抛出Server2的两条错误记录。我需要输出CSV如下所示:

Servername,OSCaption,OSVersion
Server1,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server2,Access denied,
Server2,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server3,RDP Error,
Server4,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server2,Access Denied,
Server5 Access Denied,
Servername,OSCaption,OSVersion
Server1,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server2,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server3,RDP Error,
Server4,Microsoft Windows Server 2008 R2 Enterprise ,6.1.7601
Server5 Access Denied,
但是,我仍然需要Server3和Server5的错误记录,因为没有任何好的可用OSCaption、OSversion条目

下面是我在另一篇文章中使用的一些代码

#http://stackoverflow.com/questions/28170660/delete-duplicate-strings-in-csv-using-powershell


$scrubbed = @()
$data = import-csv C:\posh\duptest.csv #| sort Servername,OSversion 

$data | ForEach-Object{
    If($scrubbed.servername -contains $_.servername){
    # We already have this Num1 check to see if it is null
    If($_.osversion){
        # Num3 is populated so it can be added. 
        $scrubbed += $_
        }
    } Else {
        # This Num1 is unique and should be added. 
        $scrubbed += $_
    }
}

# Output to file
$scrubbed | Export-Csv "C:\posh\scrubbed.csv" -NoTypeInformation

ii "C:\posh\scrubbed.csv"

它似乎无法处理三个相同的服务器名,给我留下了两条server2记录。除了在后续输出文件上重新运行几次之外,还有更优雅的方法吗?get unique似乎不像我想象的那样

假设您有如下CSV文件:

test1.csv:

Computer Name,Msg 1,Msg 2
COMPUTER 1,Windows 8,Another msg
COMPUTER 2,Windows XP,Yet again another msg
COMPUTER 3,Access Denied,
COMPUTER 4,Windows 7,Message
COMPUTER 5,Access Denied,
Computer Name,Msg 1,Msg 2
COMPUTER 1,Access Denied,
COMPUTER 2,Access Denied,
COMPUTER 3,Windows XP,Yet again another msg
COMPUTER 4,Windows 7,Message
COMPUTER 5,Access Denied,
test2.csv:

Computer Name,Msg 1,Msg 2
COMPUTER 1,Windows 8,Another msg
COMPUTER 2,Windows XP,Yet again another msg
COMPUTER 3,Access Denied,
COMPUTER 4,Windows 7,Message
COMPUTER 5,Access Denied,
Computer Name,Msg 1,Msg 2
COMPUTER 1,Access Denied,
COMPUTER 2,Access Denied,
COMPUTER 3,Windows XP,Yet again another msg
COMPUTER 4,Windows 7,Message
COMPUTER 5,Access Denied,
首先,您需要导入所有要处理的文件:

$a = Import-Csv .\test1.csv
$b = Import-Csv .\test2.csv
$c = $a + $b
接下来,我们将所有输入合并到一个大数组中进行处理:

$a = Import-Csv .\test1.csv
$b = Import-Csv .\test2.csv
$c = $a + $b
我们首先需要将“计算机名”列上的行分组。为此,我们使用
Group对象
cmdlet,使用“Computer Name”作为要分组的属性名

这将为我们提供一个具有两个属性的数组。第一个属性是“计算机名”字段。第二个字段是原始数组中具有特定“计算机名”的行的数组

这意味着我们可以从这个“内部数组”中选择最合适的行。最合适的行是具有非空第3列的第一行,或者如果第一行不为空

$d = $c | Group-Object -Property "Computer Name" | % {
    $goodRow = $_.Group | ? { [string]::IsNullOrWhiteSpace($_.'msg 2') -ne $true } | Select -First 1
    if ($goodRow -eq $null) {
        $_.Group | Select -First 1
    } else {
        $goodRow
    }
}
我们现在在变量
$d
中获得了所需的内容,并使用
导出Csv
将其保存到新文件中

$d | Export-Csv .\test3.csv

关于您的特定CSV示例,并假设OSVersion列仅在没有错误时才填充,您可以尝试以下方法:

$Array = @()
$csv = Import-Csv C:\temp.csv
$group = $csv | group servername
foreach ($item in $group)
{
    if ($item.Count -eq 1)
    {
    $Array += $item.Group
    }

        else
        {
        $array += $item.Group | ? {$_.OSVersion}
        }
}
$Array
结果:

Servername OSCaption                                    OSVersion
---------- ---------                                    ---------
Server1    Microsoft Windows Server 2008 R2 Enterprise  6.1.7601 
Server2    Microsoft Windows Server 2008 R2 Enterprise  6.1.7601 
Server3    RDP Error                                             
Server4    Microsoft Windows Server 2008 R2 Enterprise  6.1.7601 
Server5    Access Denied 
但是: 如果您的服务器(例如Server6)仅出现错误,则根本看不到该服务器的结果,要解决此问题,请将
else
部分替换为以下内容:

 else
    {
        if ($item.Group.OSVersion -match '\d')
        {
        $array += $item.Group | ? {$_.OSVersion}
        }
            else
            {
            $Row = "" | Select Servername,OSCaption,OSVersion
            $Row.Servername = $item.Group[0].Servername
            $Row.OSCaption = $item.Group.OSCaption -join ','
            $array += $Row
            }
    }
结果将是:

Servername OSCaption                                    OSVersion
---------- ---------                                    ---------
Server1    Microsoft Windows Server 2008 R2 Enterprise  6.1.7601 
Server2    Microsoft Windows Server 2008 R2 Enterprise  6.1.7601 
Server3    RDP Error                                             
Server4    Microsoft Windows Server 2008 R2 Enterprise  6.1.7601 
Server5    Access Denied                                         
Server6    RDP Error,Access Denied,RDP Error                     

发布的解决方案看起来不错。只是想提供另一种选择:

这是假设对于那些出现错误的服务器,osversion列的值将为空

Import-Csv -Path C:\temp\serverinfo.csv |
  Group-Object Servername | 
    ForEach-Object {if($_.count -gt 1) {$_.group | Where-Object osversion}else{$_.group} }