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.