脚本块上的 powershell 循环

powershell Loop on scriptblocks

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

为此,我总是使用以下管道:

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

而不是 copy/paste 这些行,我更希望有一个哈希表,其中 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

好的,所以 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| 来执行此操作。您可以将其添加到每个脚本块的开头,它们都应该 运行 类似。

然后我们必须强制将 $users 作为数组传递给它,方法是这样包装它:(,$users)
这允许:

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

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

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

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

这种方法的问题在于它效率低下:您必须为每个输出文件遍历所有 $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}
}

因此,用户会根据您的条件逐一匹配,并且在进行匹配时,会调用将该用户的数据附加到该类型匹配的文件中的函数。

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