Powershell ускорить Get-MessageTrackingLog

В настоящее время я пытаюсь получить вывод всех отключенных пользователей и их количество сообщений в обмен. Это достаточно просто с помощью цикла foreach:

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

Проблема в том, что это занимает несколько часов, потому что он запускается по одному пользователю за раз. Моя цель состоит в том, чтобы выполнять несколько запросов одновременно либо через задания, либо параллельно. Это должно быть выполнено в блоках по 10 из-за ограничений политики на сервере обмена.

Изменить (подробнее о том, почему):

Причина для того, чтобы найти количество сообщений пользователей, заключается в том, что они отключены и находятся в отключенном подразделении. Причиной этого является то, что их почта отправлена ​​другому получателю. Или их почтовый ящик был делегирован. Это предназначено для домашнего хозяйства. Результаты этого поиска будут отфильтрованы по MessageCount = 0. Затем он будет либо сообщен / сохранен как удаленный csv/users.

Раскрытие информации: я очень не осведомлен о выполнении заданий или параллельной работе в powershell. И, похоже, мой гугл-фу сломан. Любое руководство или помощь с этим будет очень признателен.

Информация о версии:

Name             : Windows PowerShell ISE Host
Version          : 5.1.15063.966

ОБНОВИТЬ:

Следуя указаниям Шона, я смог значительно ускорить эти запросы.

Обновленный код:

$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

Проблема, с которой я сталкиваюсь, заключается в том, что каждый пользователь (кроме последних 3-х пользователей) показывает 0 в качестве количества сообщений. Я знаю это неправильно. Может ли это как-то не ожидать завершения запроса Get-MessageTrackingLog -sender?

Пример (всего 77 пользователей):

Все, кроме трех последних шоу:

Электронная почта: ab@something.com

DisabledDate: 02/08/2018

Логин: ab

Тип: OnPrem

Пользователь: a, b

Расположение: Клирфилд, IA

Получено сообщений: 0

1 ответ

Решение

Чтобы ускорить Get-MessageTrackingLog, вы должны использовать пулы.

Оригинал:

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

С работой:

$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

Результаты сохраняются в $return