Powershell 哪个操作符为大型CSV文件提供更快的输出-匹配-包含或对象的位置

Powershell 哪个操作符为大型CSV文件提供更快的输出-匹配-包含或对象的位置,powershell,active-directory,Powershell,Active Directory,我试图建立一个逻辑,我必须查询4个大型CSV文件对1个CSV文件。特别是针对4个域查找AD对象,并将它们存储在变量中以进行属性比较 我尝试导入不同变量中的所有文件,并使用下面3种不同的代码来获得所需的输出。但完成的时间比预期的要长 CSV导入: $AllMainFile = Import-csv c:\AllData.csv #Input file contains below EmployeeNumber,Name,Domain Z001,ABC,Test.com Z002,DEF,Test.

我试图建立一个逻辑,我必须查询4个大型CSV文件对1个CSV文件。特别是针对4个域查找AD对象,并将它们存储在变量中以进行属性比较

我尝试导入不同变量中的所有文件,并使用下面3种不同的代码来获得所需的输出。但完成的时间比预期的要长

CSV导入:

$AllMainFile = Import-csv c:\AllData.csv
#Input file contains below
EmployeeNumber,Name,Domain
Z001,ABC,Test.com
Z002,DEF,Test.com
Z003,GHI,Test1.com
Z001,ABC,Test2.com


$AAA = Import-csv c:\AAA.csv
#Input file contains below
EmployeeNumber,Name,Domain
Z001,ABC,Test.com
Z002,DEF,Test.com
Z003,GHI,Test1.com
Z001,ABC,Test2.com
Z004,JKL,Test.com

$BBB = Import-Csv C:\BBB.csv
$CCC = Import-Csv C:\CCC.csv
$DDD = Import-Csv c:\DDD.csv
示例代码1:

foreach ($x in $AllMainFile) {
    $AAAoutput += $AAA | ? {$_.employeeNumber -eq $x.employeeNumber}
    $BBBoutput += $BBB | ? {$_.employeeNumber -eq $x.employeeNumber}
    $CCCoutput += $CCC | ? {$_.employeeNumber -eq $x.employeeNumber}
    $DDDoutput += $DDD | ? {$_.employeeNumber -eq $x.employeeNumber}

    if ($DDDoutput.Count -le 1 -and $AAAoutput.Count -le 1 -and $BBBoutput.Count -le 1 -and $CCCoutput.Count -le 1) {
        #### My Other script execution code here
    } else {
        #### My Other script execution code here
    }
}
示例代码2仅替换为-match而不是Where对象:

示例代码3刚刚替换为-包含运算符:

foreach ($x in $AllMainFile) {
    foreach ($c in $AAA){ if ($AllMainFile.employeeNumber -contains $c.employeeNumber) {$AAAoutput += $c}}
    foreach ($c in $BBB){ if ($AllMainFile.employeeNumber -contains $c.employeeNumber) {$BBBoutput += $c}}
    foreach ($c in $CCC){ if ($AllMainFile.employeeNumber -contains $c.employeeNumber) {$CCCoutput += $c}}
    foreach ($c in $DDD){ if ($AllMainFile.employeeNumber -contains $c.employeeNumber) {$DDDoutput += $c}}

    if ($DDDoutput.Count -le 1 -and $AAAoutput.Count -le 1 -and $BBBoutput.Count -le 1 -and $CCCoutput.Count -le 1) {
        #### My Other script execution code here
    } else {
        #### My Other script execution code here
    }
}
我希望通过比较和查找所有4个CSV文件和1个输入文件,尽可能快地执行脚本。每个文件包含超过1000k个对象/行,共5列。

Performance 在回答这个问题之前,我想澄清一些关于度量PowerShell cmdlet性能的问题。本机PowerShell在流式处理对象方面非常好,因此,如果流式处理正确,则可以节省大量内存—不要将流分配给变量或使用括号。PowerShell还能够调用几乎所有现有的方法,如Add和其他技术

衡量命令性能的常用方法是:

(Measure-Command {<myCommand>}).TotalMilliseconds
附录

根据注释和列表中的重复项,似乎实际上请求了所有键上的联接,而不仅仅是EmployeeNumber上的联接。为此,您需要将相关的键与数据中未使用的分隔符连接起来,并将其用作哈希表的键。 不在问题中,但从评论来看,似乎也期望完全加入。对于右连接部分,如果在主表$main.ContainsKey$Key中找不到匹配项,则可以通过返回右对象来完成。对于左连接部分,这更复杂,因为您需要跟踪$InnerMain中已匹配的项,并在最后返回剩余项:

$Main = @{}
$Separator = "`t"                       # Chose a separator that isn't used in any value
ForEach ($Item in $All) {
    $Key = $Item.EmployeeNumber, $Item.Name, $Item.Domain -Join $Separator
    $Main[$Key] = @{MainEmployeeNumber = $Item.EmployeeNumber; MainName = $Item.Name; MainDomain = $Item.Domain}    # What output is expected?
}

ForEach ($Name in 'AAA', 'BBB', 'CCC', 'DDD') {
    $InnerMain = @($False) * $Main.Count
    $Index = 0
    Import-Csv "C:\$Name.csv" | ForEach-Object {
        $Key = $_.EmployeeNumber, $_.Name, $_.Domain -Join $Separator
        If ($Main.ContainsKey($Key)) {
            $InnerMain[$Index] = $True
            [PSCustomObject](@{EmployeeNumber = $_.EmployeeNumber; Name = $_.Name; Domain = $_.Domain} + $Main[$Key])
        } Else {
            [PSCustomObject](@{EmployeeNumber = $_.EmployeeNumber; Name = $_.Name; Domain = $_.Domain; MainEmployeeNumber = $Null; MainName = $Null; MainDomain = $Null})
        }
        $Index++
    } | Export-Csv "C:\Output$Name.csv"
    $Index = 0
    ForEach ($Item in $All) {
        If (!$InnerMain[$Index]) {
            $Key = $Item.EmployeeNumber, $Item.Name, $Item.Domain -Join $Separator
            [PSCustomObject](@{EmployeeNumber = $Null; Name = $Null; Domain = $Null} + $Main[$Key])
        }
        $Index++
    } | Export-Csv "C:\Output$Name.csv"
}
联接对象 仅供参考,我对cmdlet的使用和安装做了一些改进,这些改进非常简单,请参见:包括更容易更改多个连接,这对于像这样的请求可能很方便。虽然我仍然不完全理解您到底在寻找什么,并且有一些小问题,比如:如果某个域是某个特定域的摘录,那么域列中的域如何不同?。 我采用一般描述,特别是针对4个域查找AD对象,并将它们存储在变量中,以便进行属性比较。 在这里,我假设$AllMain文件实际上只是一个中间表,存在于所有相关表的串联中,不一定,但只是混淆,因为它可能包含来自同一域的EmployeeNumber和来自其他域的EmployeeNumber的重复类型。如果这是正确的,则可以使用Join Object cmdlet忽略此表:

结果:

EmployeeNumber AAAName AAADomain BBBName BBBDomain CCCName CCCDomain DDDName DDDDomain
-------------- ------- --------- ------- --------- ------- --------- ------- ---------
Z001           ABC     Domain1   ABC     Domain1   ABC     Domain1   ABC     Domain3
Z001           ABC     Domain1   ABC     Domain1   STU     Domain2   ABC     Domain3
Z002           DEF     Domain2   JKL     Domain2
Z003           GHI     Domain3
Z004                             MNO     Domain4
Z005                                               PQR     Domain2   VWX     Domain4
Z006                                                                 XYZ     Domain1

我可以告诉你+=不会给你带来任何性能方面的好处。您应该使用像[collections.arraylist]这样的可更新列表,并使用它的Add。method@AdminOfThings-谢谢。但在这里,我希望使用比较运算符来提高性能。当然,加上。方法将获得一些向变量添加对象的性能。嗯,还不确定,还没有测试过。创建一个以employeenumber为键的哈希表,以及一个值所在域的集合,或者一个自定义对象,每个域都有一个属性,或者类似的东西。这样,您只需在域A-D中循环一次,哈希表在其中查找内容的速度非常快。如果您想自己完成此操作,则可以使用。如果您不想重新发明轮子,可以尝试此cmdlet:$AllMainFile | LeftJoin$AAAA-on employeeNumber | LeftJoin$bbbbb-on employeeNumber | LeftJoin$CCCC-on employeeNumber | LeftJoin$ddd-on employeeNumber可能的重复项,感谢您的详细见解。到目前为止,它在下面。我在csv中获得的输出:MainName EmployeeNumber Name Domain MainDomain ABC Z001 ABC Test.com Test2.com DEF Z002 DEF Test.com Test.com GHI Z003 GHI Test1.com Test1.com ABC Z001 ABC Test2.com Test2.com因此,问题是,>$Main忽略了重复项。在这种情况下,$AllData中的第一个条目。>如果没有匹配,它也会忽略。Z004从AAA美元起。输出文件没有此项。有什么想法吗?我想我已经回答了最初的问题:哪个操作符提供更快的输出-匹配-包含,或者大型CSV文件的对象在哪里请,此外,我想你想自己重新发明一些东西。。。无论如何,我已经在我的回答中添加了一些关于如何解决你评论中的问题的更多信息。对我来说,它变得越来越复杂。对不起,我不是PS专家,可能无法充分解释要求。在这里,我想再试一次。对每个employeeNumber的主文件运行查询,如果找到,则将其存储在包含重复项的变量中。出来
输入预期值:如果EmployeeNumber与AAA.csv中$AAAmatch值中的“AAA”存储匹配。其他输入文件也是如此。前面提到的示例代码1可以完成这项工作,但速度非常慢。谢谢你的支持。是的,答案被接受,测试完新提供的代码后回来。
$Main = @{}
$Separator = "`t"                       # Chose a separator that isn't used in any value
ForEach ($Item in $All) {
    $Key = $Item.EmployeeNumber, $Item.Name, $Item.Domain -Join $Separator
    $Main[$Key] = @{MainEmployeeNumber = $Item.EmployeeNumber; MainName = $Item.Name; MainDomain = $Item.Domain}    # What output is expected?
}

ForEach ($Name in 'AAA', 'BBB', 'CCC', 'DDD') {
    $InnerMain = @($False) * $Main.Count
    $Index = 0
    Import-Csv "C:\$Name.csv" | ForEach-Object {
        $Key = $_.EmployeeNumber, $_.Name, $_.Domain -Join $Separator
        If ($Main.ContainsKey($Key)) {
            $InnerMain[$Index] = $True
            [PSCustomObject](@{EmployeeNumber = $_.EmployeeNumber; Name = $_.Name; Domain = $_.Domain} + $Main[$Key])
        } Else {
            [PSCustomObject](@{EmployeeNumber = $_.EmployeeNumber; Name = $_.Name; Domain = $_.Domain; MainEmployeeNumber = $Null; MainName = $Null; MainDomain = $Null})
        }
        $Index++
    } | Export-Csv "C:\Output$Name.csv"
    $Index = 0
    ForEach ($Item in $All) {
        If (!$InnerMain[$Index]) {
            $Key = $Item.EmployeeNumber, $Item.Name, $Item.Domain -Join $Separator
            [PSCustomObject](@{EmployeeNumber = $Null; Name = $Null; Domain = $Null} + $Main[$Key])
        }
        $Index++
    } | Export-Csv "C:\Output$Name.csv"
}
$AAA = ConvertFrom-Csv @'
EmployeeNumber,Name,Domain
Z001,ABC,Domain1
Z002,DEF,Domain2
Z003,GHI,Domain3
'@

$BBB = ConvertFrom-Csv @'
EmployeeNumber,Name,Domain
Z001,ABC,Domain1
Z002,JKL,Domain2
Z004,MNO,Domain4
'@

$CCC = ConvertFrom-Csv @'
EmployeeNumber,Name,Domain
Z005,PQR,Domain2
Z001,ABC,Domain1
Z001,STU,Domain2
'@

$DDD = ConvertFrom-Csv @'
EmployeeNumber,Name,Domain
Z005,VWX,Domain4
Z006,XYZ,Domain1
Z001,ABC,Domain3
'@

$AAA | FullJoin $BBB -On EmployeeNumber -Discern AAA |
    FullJoin $CCC -On EmployeeNumber -Discern BBB |
    FullJoin $DDD -On EmployeeNumber -Discern CCC,DDD | Format-Table
EmployeeNumber AAAName AAADomain BBBName BBBDomain CCCName CCCDomain DDDName DDDDomain
-------------- ------- --------- ------- --------- ------- --------- ------- ---------
Z001           ABC     Domain1   ABC     Domain1   ABC     Domain1   ABC     Domain3
Z001           ABC     Domain1   ABC     Domain1   STU     Domain2   ABC     Domain3
Z002           DEF     Domain2   JKL     Domain2
Z003           GHI     Domain3
Z004                             MNO     Domain4
Z005                                               PQR     Domain2   VWX     Domain4
Z006                                                                 XYZ     Domain1