This is the skeleton of a Batch Processing System (Importing from a CSV file, performing consecutive tasks that are dependant on the previous task completing and then outputting the result).
I detailed how it works in Part 1 here and in Part 2 here.
[CmdletBinding()] Param ( [parameter(Mandatory=$True)] [string]$BatchFile ) function New-ReportObject { Param ( [Parameter(ValueFromPipeline=$true)] [PSObject]$TargetObject=$Null ) BEGIN { } PROCESS { $ReportObject=New-Object -typename PSObject $ReportObject | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "" $ReportObject | Add-Member -MemberType NoteProperty -Name "Task1Complete" -Value $False $ReportObject | Add-Member -MemberType NoteProperty -Name "Task2Complete" -Value $False $ReportObject | Add-Member -MemberType NoteProperty -Name "Note" -Value "" if(!($TargetObject -eq $Null)) { $ReportObject.Identifier = $TargetObject.DistinguishedName } Return $ReportObject } END { } } function Set-Task1 { Param ( [Parameter(ValueFromPipeline=$true)] [PSObject]$TargetObject=$Null ) BEGIN { } PROCESS { if($TargetObject -eq $Null) { Return $Null } try { Set-Mailbox -Identity $TargetObject.Identifier -CustomAttribute6 "Value1" -ErrorAction Stop $TargetObject.Task1Complete=$True } catch { if ($Error.Count -gt 0) { $TargetObject.Note=$Error[0] } $Error.Clear() } Return $TargetObject } END { } } function Set-Task2 { Param ( [Parameter(ValueFromPipeline=$true)] [PSObject]$TargetObject=$Null ) BEGIN { } PROCESS { if($TargetObject -eq $Null) { Return $Null } try { Set-Mailbox -Identity $TargetObject.Identifier -CustomAttribute5 "Value2" -ErrorAction Stop $TargetObject.Task2Complete=$True } catch { if ($Error.Count -gt 0) { $TargetObject.Note=$Error[0] } $Error.Clear() } Return $TargetObject } END { } } $ObjectsToProcess=Import-CSV -Path $BatchFile | Select-Object -ExpandProperty EmailAddress | % {Get-Mailbox $_} | New-ReportObject $ObjectsToProcess | Set-Task1 | Where-Object {$_.Task1Complete} | Set-Task2