powershell在scriptblocks上循环

时间:2015-02-05 19:25:31

标签: powershell csv pipeline scriptblock

我试图将一组对象中的多个信息导出为CSV文件。

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

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

我不希望复制/粘贴这些行,而是希望有一个散列表,其中包含CSV文件名作为键,而作为值的值则是&lt; ...&gt;

所以我这样做了:

$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

2 个答案:

答案 0 :(得分:1)

好的,所以Switch是一个循环,它根据一组过滤器测试一个数组的每个记录。如果记录通过过滤器,它将针对以下脚本块运行。过滤器可以是文字匹配,RegEx匹配或类似于Where语句的脚本块。根据您的需要,我们将使用最后一个。看看这个例子,看看它是否能实现你的目标:

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}
}

这将使每个用户通过交换机,如果它匹配任何条件,它将附加到关联的CSV文件。

编辑:好的,你不喜欢Switch。如果您真的希望能够在ForEach-Object循环中执行脚本块,那么您可以向脚本块添加参数以允许管道数据,但这并不能完全解决您的问题。我马上就会谈到这一点。首先,让我们使用您的Group-Object mail选项并将其设置为接受输入:

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

成为

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

我在脚本块的开头添加了Param([Parameter(ValueFromPipeline=$True)][Object[]]$Users);$Users|来执行此操作。您可以将其添加到每个scriptblock的开头,它们都应该以相似的方式运行。

然后我们必须强制将$users作为数组传递给它,方法是将其包裹起来:(,$users)
这样就可以了:

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

它提供了您期望的输出。剩下的就是将它放在ForEach for $ScriptBlocks中,同时跟踪当前的scriptblock:

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

输出所有脚本块中的所有内容。您现在唯一的问题是您无法指定要输出的CSV。但这至少回答了你原来的问题。

答案 1 :(得分: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}
}

因此,用户将逐个匹配您的条件,并且当匹配时,将调用将该用户的数据附加到该类型匹配的文件的函数。

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