1

我正在尝试将对象集合中的多个信息导出到 CSV 文件中。

为此,我总是有以下管道:

 $users | < my filters/grouping/selects and expands> | Export-CSV ...

而不是复制/粘贴这些行,我希望有一个哈希表,其中 CSV 文件名作为键,< ... > 之间的部分作为值

所以我这样做了:

$scriptblocks = @{"NonCompliantMail"={ ? {-not ([bool]($_.mail -as [Net.Mail.MailAddress])) } };
              "NonCompliantSAM"= { ? { ($_.samaccountname.Trim().Length - $_.samaccountname.Length) -ne 0 }};
              "MissingSN" = { ? {[string]::IsNullOrWhiteSpace($_.sn) } };
              "MissingGivenName" = { ? {[string]::IsNullOrWhiteSpace($_.givenname) } };
              "TrimSN" = { ? { (-not ([string]::IsNullOrWhiteSpace($_.sn))) -and (($_.sn.Trim().Length - $_.sn.Length) -ne 0) } };
              "TrimGivenName" = { ? { (-not ([string]::IsNullOrWhiteSpace($_.givenname))) -and (($_.givenname.Trim().Length - $_.givenname.Length) -ne 0) } }
              "MultipleEmails" = { group-object mail |? { $_.Count -gt 1 } | select -ExpandProperty Group | select mail,samaccountname }
              }

我正在尝试像那样执行它,但它不起作用:

$scriptblocks.getEnumerator() |% { $users | & $_.Value | Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ($_.Key + ".csv")) } 

关于如何做的任何想法?

问候。JB

4

2 回答 2

1

Ok, so a Switch is a loop that tests each record of an array against a set of filters. If the record passes the filter it it run against the following scriptblock. The filters can be a literal match, a RegEx match, or a scriptblock similar to a Where statement. For your needs we'll be using the last of those. Check out this example and see if it accomplishes what you are going for:

Switch($users){
    {-not ([bool]($_.mail -as [Net.Mail.MailAddress])) }{$_|Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ("NonCompliantMail" + ".csv")) -append}
    {($_.samaccountname.Trim().Length - $_.samaccountname.Length) -ne 0 }{$_|Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ("NonCompliantSAM" + ".csv")) -append}
    {[string]::IsNullOrWhiteSpace($_.sn) }{$_|Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ("MissingSN" + ".csv")) -append}
    {[string]::IsNullOrWhiteSpace($_.givenname) }{$_|Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ("MissingGivenName" + ".csv")) -append}
    {(-not ([string]::IsNullOrWhiteSpace($_.sn))) -and (($_.sn.Trim().Length - $_.sn.Length) -ne 0) }{$_|Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ("TrimSN" + ".csv")) -append}
    {(-not ([string]::IsNullOrWhiteSpace($_.givenname))) -and (($_.givenname.Trim().Length - $_.givenname.Length) -ne 0) }{$_|Export-Csv -NoTypeInformation -Force -Encoding $encoding -Delimiter $delimiter -Path (Join-Path $scriptpath ("TrimGivenName" + ".csv")) -append}
}

That will run each user through the switch, and if it matches any of the conditions it will append it to the associated CSV file.

Edit: Ok, you didn't like Switch. If you really want to be able to execute scriptblocks in a ForEach-Object loop like that you can add parameters to your scriptblocks to allow piped data, but this doesn't completely solve your issue. I'll get to that in a moment. First, let's take your Group-Object mail option and set it up to accept input:

"MultipleEmails" = { group-object mail |? { $_.Count -eq 1 } | select -ExpandProperty Group | select mail,samaccountname }

becomes

"MultipleEmails" = {Param([Parameter(ValueFromPipeline=$True)][Object[]]$Users);$Users| group-object mail |? { $_.Count -eq 1 } | select -ExpandProperty Group | select mail,samaccountname }

I added Param([Parameter(ValueFromPipeline=$True)][Object[]]$Users);$Users| to the beginning of the scriptblock to do this. You can add that to the beginning of each scriptblock and they should all run similarly.

Then we have to force $users to be passed to it as an array by wrapping it as such: (,$users)
That allows this:

(,$users)|& $scriptblocks["multipleemails"]

That provides the output that you would expect it to. All that's left is to put that in your ForEach for $ScriptBlocks, along with keeping track of your current scriptblock:

$scriptblocks.keys|%{$sb=$_;(,$users)|& $scriptblocks["$sb"]}

That outputs everything from all of the scriptblocks. The only issue you now have is that you have no way to specify what CSV to output to. But this at least answers your original question.

于 2015-02-05T20:15:41.023 回答
1

这种方法的问题在于它效率低下:您必须为每个输出文件遍历所有 $users 一次。

另一种方法是使用switch语句来解决这个问题(遵循伪代码):

$file1 = "NonCompliantMail.csv"
$file2 = "NonCompliantSAM.csv"
$file3 = "MissingSN.csv"
$file4 = "MissingGivenName.csv"
$file5 = "TrimSN.csv"
$file6 = "TrimGivenName.csv"
$file7 = "UsersWhoDontMatchAnything.csv"

function WriteUserDataToFile
{

    param
    (
        $User,
        $OutFile
    )

    "Process the $User object to append to $OutFile"
}

switch ($users) 
{ 
    ("User matching criteria 1") {WriteUserDataToFile $_ $file1}
    ("User matching criteria 2") {WriteUserDataToFile $_ $file2} 
    ("User matching criteria 3") {WriteUserDataToFile $_ $file3} 
    ("User matching criteria 4") {WriteUserDataToFile $_ $file4} 
    ("User matching criteria 5") {WriteUserDataToFile $_ $file5}
    ("User matching criteria 6") {WriteUserDataToFile $_ $file6}
    default {WriteUserDataToFile $_ $file7}
}

因此,用户将与您的标准一一匹配,并且当进行匹配时,将调用将该用户的数据附加到该匹配类型的文件的函数。

希望这是一个合适的建议。

于 2015-02-05T20:36:02.443 回答