Currently I am trying to get an output of all disabled users and their message counts in exchange. This is easy enough through a foreach loop:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://aserversomewhere.local/PowerShell/ -Authentication Kerberos -Credential $UserCredential
Import-PSSession $Session -AllowClobber
Import-Module ActiveDirectory
$Users = Get-ADUser -filter * -Properties * -SearchBase "OU=Disabled User Accounts,DC=Private,DC=Private"
$Today = (Get-Date).ToShortDateString()
$OneMonthAgo = (Get-Date).AddMonths(-1).ToShortDateString()
$results = @()
$OnPrem = $Users | Where-Object {$_.mDBUseDefaults -eq "True"}
$365 = $Users | Where-Object{$_.mDBUseDefaults -ne "True"}
Write-Host "Start Date: " $OneMonthAgo -ForegroundColor Green
Write-Host "Total Users OnPrem: " ($OnPrem.mail).Count -ForegroundColor Green
foreach($User in $OnPrem)
{
Write-Host "Checking User: "$User.DisplayName -ForegroundColor Yellow
$MessageCount = Get-MessageTrackingLog -recipients $User.Mail -Start $OneMonthAgo.ToString() | Where-Object {$_.EventID -eq "RECEIVE"} | Measure-Object
Write-Host $User.Name": MessageCount: "$MessageCount.Count -ForegroundColor Cyan
$Object = New-Object PSObject -Property @{
User = $User.Name
Email = $User.Mail
Type = "OnPrem"
DisabledDate = $User.Modified
Location = $User.Office
MessagesReceived = $MessageCount.Count
}
$script:results += $Object
}
The issue is this takes several hours to complete because it is being ran one user at a time. My Goal is to run multiple inquiries at a time either through jobs or in parallel. This needs to be ran in blocks of 10 due to the policy restrictions on the exchange server.
Edit (more information on why):
The reason to find the message counts of the users is, they are disabled and sitting an a disabled OU. The reason for this is their mail is fw to another recipient. Or, their mailbox has been delegated. This is intended for house keeping. The results of this search will be filtered by MessageCount = 0. Then it will either be reported/saved as csv/users removed.
Disclosure: I am very ignorant on running jobs or running in parallel within powershell. And, my google-foo seems to be broken. Any guidance or help with this would be very appreciated.
Version info:
Name : Windows PowerShell ISE Host
Version : 5.1.15063.966
UPDATE:
After Following Shawn's guidance, I was able to successfully speed up these requests quite significantly.
Updated code:
$RunSpaceCollection = @()
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10)
$RunspacePool.ApartmentState = "MTA"
$RunspacePool.Open()
$UserCredential = Get-Credential
Import-Module ActiveDirectory
$Users = Get-ADUser -filter * -Properties * -SearchBase "OU=Disabled User Accounts,DC=private,DC=private"
$Today = (Get-Date).ToShortDateString()
$OneMonthAgo = (Get-Date).AddMonths(-1).ToShortDateString()
[Collections.ArrayList]$results = @()
$OnPrem = $Users | Where-Object {$_.mDBUseDefaults -eq "True"}
$365 = $Users | Where-Object{$_.mDBUseDefaults -ne "True"}
Write-Host "Start Date: " $OneMonthAgo -ForegroundColor Green
Write-Host "Total Users OnPrem: " ($OnPrem.mail).Count -ForegroundColor Green
$scriptblock = {
Param (
[System.Management.Automation.PSCredential]$Credential,
[string]$emailAddress,
[string]$startTime,
[string]$userName,
[string]$loginName,
[string]$DisabledDate,
[string]$OfficeLocation
)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://someserver.local/PowerShell/ -Authentication Kerberos -Credential $Credential
Import-PSSession $Session -AllowClobber -DisableNameChecking -Verbose:$false | Out-Null
$MessageCount = Get-MessageTrackingLog -recipients $emailAddress -Start $startTime.ToString() -ResultSize unlimited
$Object = New-Object PSObject -Property @{
User = $userName
Login = $loginName
Email = $emailaddress
Type = "OnPrem"
DisabledDate = $DisabledDate
Location = $OfficeLocation
MessagesReceived = $MessageCount.Count.ToString()
}
$Object
}
foreach($User in $OnPrem)
{
$Powershell = [PowerShell]::Create()
$null = $Powershell.AddScript($scriptblock)
$null = $Powershell.AddArgument($UserCredential)
$null = $Powershell.AddArgument($user.mail)
$null = $Powershell.AddArgument($OneMonthAgo)
$null = $Powershell.AddArgument($user.Name)
$null = $Powershell.AddArgument($user.samaccountname)
$null = $Powershell.AddArgument($user.Modified)
$null = $Powershell.AddArgument($user.Office)
$Powershell.RunspacePool = $RunspacePool
[Collections.ArrayList]$RunSpaceCollection += New-Object -TypeName PSObject -Property @{
RunSpace = $Powershell.BeginInvoke()
PowerShell = $Powershell
}
}
While($RunspaceCollection) {
Foreach($Runspace in $RunSpaceCollection.ToArray())
{
If ($Runspace.Runspace.IsCompleted) {
[void]$results.Add($Runspace.PowerShell.EndInvoke($Runspace.Runspace))
$Runspace.PowerShell.Dispose()
$RunspaceCollection.Remove($Runspace)
}
}
}
$RunspacePool.Close()
$RunspacePool.Dispose()
$results
The issue I am having is every user (except the last 3 users) are showing 0 as the message count. I know this wrong. Could this somehow not be waiting for the query of Get-MessageTrackingLog -sender to finish?
Example (77 Users total):
All but the last three show:
Email : a.b@something.com
DisabledDate : 02/08/2018
Login : a.b
Type : OnPrem
User : a, b
Location : Clearfield, IA
MessagesReceived : 0
In order to speedup Get-MessageTrackingLog, you have to use pools.
Original:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://aserversomewhere.local/PowerShell/ -Authentication Kerberos -Credential $UserCredential
Import-PSSession $Session -AllowClobber
Import-Module ActiveDirectory
$Users = Get-ADUser -filter * -Properties * -SearchBase "OU=Disabled User Accounts,DC=Private,DC=Private"
$Today = (Get-Date).ToShortDateString()
$OneMonthAgo = (Get-Date).AddMonths(-1).ToShortDateString()
$results = @()
$OnPrem = $Users | Where-Object {$_.mDBUseDefaults -eq "True"}
$365 = $Users | Where-Object{$_.mDBUseDefaults -ne "True"}
Write-Host "Start Date: " $OneMonthAgo -ForegroundColor Green
Write-Host "Total Users OnPrem: " ($OnPrem.mail).Count -ForegroundColor Green
foreach($User in $OnPrem)
{
Write-Host "Checking User: "$User.DisplayName -ForegroundColor Yellow
$MessageCount = Get-MessageTrackingLog -recipients $User.Mail -Start $OneMonthAgo.ToString() | Where-Object {$_.EventID -eq "RECEIVE"} | Measure-Object
Write-Host $User.Name": MessageCount: "$MessageCount.Count -ForegroundColor Cyan
$Object = New-Object PSObject -Property @{
User = $User.Name
Email = $User.Mail
Type = "OnPrem"
DisabledDate = $User.Modified
Location = $User.Office
MessagesReceived = $MessageCount.Count
}
$script:results += $Object
}
With Jobs:
$MaxThread = 10
$RunspacePool = [runspacefactory]::CreateRunspacePool(
[System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
)
[void]$RunspacePool.SetMaxRunspaces($MaxThread)
$RunspacePool.Open()
$UserCredential = Get-Credential
Import-Module ActiveDirectory
$Users = Get-ADUser -filter * -Properties * -SearchBase "OU=Disabled User Accounts,DC=private,DC=private"
$Today = (Get-Date).ToShortDateString()
$OneMonthAgo = (Get-Date).AddMonths(-1).ToShortDateString()
[Collections.ArrayList]$results = @()
$OnPrem = $Users | Where-Object {$_.mDBUseDefaults -eq "True"}
$365 = $Users | Where-Object{$_.mDBUseDefaults -ne "True"}
Write-Host "Start Date: " $OneMonthAgo -ForegroundColor Green
Write-Host "Total Users OnPrem: " ($OnPrem.mail).Count -ForegroundColor Green
$OnPremScriptblock = {
Param (
[System.Management.Automation.PSCredential]$Credential,
[string]$emailAddress,
[string]$startTime,
[string]$userName,
[string]$loginName,
[string]$DisabledDate,
[string]$OfficeLocation
)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://aserversomewhere.local/PowerShell/ -Authentication Kerberos -Credential $Credential
Import-PSSession $Session -AllowClobber -DisableNameChecking -Verbose:$false | Out-Null
$MessageCount = Get-MessageTrackingLog -recipients $emailAddress -Start $startTime.ToString() -ResultSize unlimited
$Object = New-Object PSObject -Property @{
User = $userName
Login = $loginName
Email = $emailaddress
Type = "OnPrem"
DisabledDate = $DisabledDate
Location = $OfficeLocation
MessagesReceived = $MessageCount.Count.ToString()
}
$Object
}
$jobs = New-Object System.Collections.ArrayList
foreach ($user in $OnPrem){
$PowerShell = [PowerShell]::Create()
$null = $PowerShell.AddScript($OnPremScriptblock)
$null = $PowerShell.AddArgument($UserCredential)
$null = $PowerShell.AddArgument($user.mail)
$null = $PowerShell.AddArgument($OneMonthAgo)
$null = $PowerShell.AddArgument($user.name)
$null = $PowerShell.AddArgument($user.samaccountname)
$null = $PowerShell.AddArgument($user.modified)
$null = $PowerShell.AddArgument($user.Office)
$PowerShell.RunspacePool = $RunspacePool
[void]$jobs.Add((
[pscustomobject]@{
PowerShell = $PowerShell
Handle = $PowerShell.BeginInvoke()
}
))
}
While($jobs.handle.IsCompleted -eq $false){
Write-Host "." -NoNewline
Start-Sleep -Milliseconds 100
}
$return = $jobs | foreach{
$_.PowerShell.EndInvoke($_.Handle)
$_.PowerShell.Dispose()
}
$jobs.Clear()
$return
The results are stored in $return