根据列值将CSV行转换为列

时间:2018-05-13 08:56:56

标签: powershell

我正在尝试将包含30列的80K行数据csv转换为基于来自orignal CSV的特定列数据的已排序和过滤的CSV。

例如我的数据格式如下:

PatchName   MachineName IPAddress       DefaultIPGateway    Domain Name USERID          UNKNOWN NOTAPPLICABLE   INSTALLED   APPLICABLE  REBOOTREQUIRED  FAILED
KB456982    XXX1002     xx.yy.65.148    xx.yy.64.1          XYZ.NET     XYZ\ayzuser     YES     
KB589631    XXX1003     xx.yy.65.176    xx.yy.64.1          XYZ.NET     XYZ\cdfuser             YES
KB456982    ABC1004     xx.zz.83.56     xx.zz.83.1          XYZ.NET     XYZ\mnguser     YES
KB456982    8797XCV     xx.yy.143.187   xx.yy.143.184       XYZ.NET     WPX\abcuser                                                                     YES

此处MachineName将被过滤为Uniq,而PatchName将转换为Last Columns标题,其中包含" UNKNOWN,NOAPPLICABLE,INSTALLED,FAILED,REBOOTREQUIRED列如果出现YES则为值 -

预期结果:

MachineName IPAddress       DefaultIPGateway    Domain Name USERID          KB456982 KB589631 
XXX1002     xx.yy.65.148    xx.yy.64.1          XYZ.NET     XYZ\ayzuser     UNKNOWN  
XXX1003     xx.yy.65.176    xx.yy.64.1          XYZ.NET     XYZ\cdfuser              NOTAPPLICATBLE
ABC1004     xx.zz.83.56     xx.zz.83.1          XYZ.NET     XYZ\mnguser     UNKNOWN
8797XCV     xx.yy.143.187   xx.yy.143.184       XYZ.NET     WPX\abcuser     FAILED      

寻求帮助来实现这一目标,到目前为止,我能够将PathcName行转置为列,但不能包含所有列并应用条件。 [这需要40分钟来处理]

$b = @()
    foreach ($Property in $a.MachineName | Select -Unique) {
        $Props = [ordered]@{ MachineName = $Property }
        foreach ($Server in $a.PatchName | Select -Unique){ 
            $Value = ($a.where({ $_.PatchName -eq $Server -and $_.MachineName -eq $Property })).NOTAPPLICABALE
            $Props += @{ $Server = $Value }
        }
        $b += New-Object -TypeName PSObject -Property $Props
    }

1 个答案:

答案 0 :(得分:1)

这就是我提出的:

$data = Import-Csv -LiteralPath 'C:\path\to\data.csv'

$lookup = @{}
$allPatches = $data.PatchName | Select-Object -Unique

# Make 1 lookup entry for each computer, to keep the username and IP and so on.
# Add the patch details from the current row (might add more than one patch per computer)
foreach ($row in $data)
{
    if (-not $lookup.ContainsKey($row.MachineName))
    {     
        $lookup[$row.MachineName] = ($row | Select-Object -Property MachineName, IPAddress, DefaultIPGateway, DomainName, UserID)
    }

    $patchStatus = $row.psobject.properties | 
            Where-Object {
                $_.name -in @('applicable', 'notapplicable', 'installed', 'rebootrequired', 'failed', 'unknown') -and 
                -not [string]::IsNullOrWhiteSpace($_.value)
            } | 
            Select-Object -ExpandProperty Name

    $lookup[$row.MachineName] | Add-Member -NotePropertyName $row.PatchName -NotePropertyValue $patchStatus

}

# Pull the computer details out of the lookup, and add all the remaining patches
# so they will convert to CSV properly, then export to CSV
$lookup.Values | ForEach-Object {
    $computer = $_
    foreach ($patch in $allPatches | where-object {$_ -notin $computer.psobject.properties.name})
    {
        $computer | Add-Member -NotePropertyName $patch -NotePropertyValue ''
    }
    $computer
} | Export-Csv -LiteralPath 'c:\path\to\output.csv' -NoTypeInformation