首页 > 解决方案 > 使用多个线程运行 powershell 脚本

问题描述

我正在尝试从另一个 powershell 脚本中执行一个 powershell 脚本。我当前的脚本运行良好,但如果可能的话,我想尝试加快它的速度。

我的脚本所做的是通过 EWS 将联系人列表导入每个用户的联系人文件夹。

在我的 powershell 脚本中,处理导入的脚本我这样称呼它(ImportContacts 是一个没有任何参数的函数):

. $rootPath\ImportContacts\ImportContacts.ps1
ImportContacts

当我正常运行它时,正如我上面提到的,一切正常,我只是想加快它的速度。我尝试按照一些在 Powershell 中实现 runspacepool 的示例来利用多个线程,但它似乎对我来说不能正常工作。我确定这是一个愚蠢的语法错误,但我目前有这个:

Measure-Command{
$MaxThreads = 5
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads)
$RunspacePool.Open()
$Jobs = @()

ImportContacts | Foreach-Object {
    $PowerShell = [powershell]::Create()
    $PowerShell.RunspacePool = $RunspacePool
    $PowerShell.AddScript({ImportContacts})
    $Jobs += $PowerShell.BeginInvoke()
}

while ($Jobs.IsCompleted -contains $false) 
{
    Start-Sleep 1
}}

这似乎可以完成这项工作,但我无法区分速度。

编辑 5-15-21 为了更好地帮助解决这个问题,这是我检索用户数据的方式。我有一个名为“ExportedContacts.ps1”的文件,它的名称如下:

$Users = & $rootPath\ExportContacts\ExportContacts.ps1

文件内容是这样的

$Users = Get-ADUser -Filter * -Properties extensionAttribute2, middlename, mobile, OfficePhone, GivenName, Surname, DisplayName, EmailAddress, Title, Company, Department, thumbnailPhoto | Where-Object {($_.extensionAttribute2 -like "DynamicDistro") -AND (($_.Mobile -ne $NULL) -OR ($_.OfficePhone -ne $NULL))} | Select-Object @{Name="First Name";Expression={$_.GivenName}},@{Name="Last Name";Expression={$_.Surname}},@{Name="Display Name";Expression={$_.DisplayName}},@{Name="Job Title";Expression={$_.Title}},@{Name="Company";Expression={$_.Company}},@{Name="Department";Expression={$_.Department}},@{Name="Mobile Phone";Expression={$_.Mobile}},@{Name="Home Phone";Expression={$_.OfficePhone}}, @{Name="Middle Name";Expression={$_.MiddleName}}, @{Name="E-mail Address";Expression={$_.EmailAddress}}, thumbnailPhoto | Sort-Object "Last Name"

return $Users

然后我导入这些联系人,类似于我上面提到的方式。导入内容如下:

Function ImportContacts
{
    Write-Host "Importing Contacts. This can take several minutes."

#******************************************************************

    foreach ($ContactItem in $Users)
    {       
        $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
        $ExchangeContact = New-Object Microsoft.Exchange.WebServices.Data.Contact($service);
            
        $ExchangeContact.NickName = ('{0} {1}' -f $ContactItem."First Name", $ContactItem."Last Name"). Trim()
        $ExchangeContact.DisplayName = $ExchangeContact.NickName;
        $ExchangeContact.FileAs = $ExchangeContact.NickName;
        $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $ContactItem."E-mail Address";
        $ExchangeContact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::HomePhone] = $ContactItem."Home Phone";
        $ExchangeContact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::MobilePhone] = $ContactItem."Mobile Phone";
        $ExchangeContact.Department = $ContactItem."Department";
        $ExchangeContact.CompanyName = $ContactItem."Company";
        $ExchangeContact.JobTitle = $ContactItem."Job Title";
        $ExchangeContact.MiddleName = $ContactItem."Middle Name";

        # Save the contact    
        $ExchangeContact.Save($ContactsFolder.Id);  
    }
}

我还包括创建我指定的联系人文件夹并删除现有联系人(如果该文件夹已存在)的文件,以便每次导入都是干净且更新的导入。我很好奇是否有更快的方法来清洁现有物品?

Function CreateContactsFolder
{
    Write-Host "Creating Contacts Folder and Cleaning up stale items. This can take a couple minutes."
    
    Try
    {    
        $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
        $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
        $RootFolder.Load()
            
        #Check to see if they have a contacts folder that we want
        $FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
        $ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where-Object {$_.DisplayName -eq $FolderName}

        if($ContactsFolderSearch)
        {
            $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);

            #If folder exists, connect to it. Clear existing Contacts, and reupload new (UPDATED) Contact Info
            Write-Host "Folder alreads exists. We will remove all contacts under this folder."
            
            # Attempt to empty the target folder up to 10 times.
            $tries = 0
            $max_tries = 0
            while ($tries -lt 2) 
            {
                try 
                {
                    $tries++
                    $ErrorActionPreference='Stop'
                    $ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
                    $tries++
                } 
                catch 
                {
                    $ErrorActionPreference='SilentlyContinue'
                    $rnd = Get-Random -Minimum 1 -Maximum 10
                    Start-Sleep -Seconds $rnd
                    $tries = $tries - 1
                    $max_tries++

                    if ($max_tries -gt 100) 
                    {
                        Write-Host "Error; Cannot empty the target folder; `t$EmailAddress"
                    }
                }
            }       
        }
        else 
        {
            #Contact Folder doesn't exist. Let's create it
            try 
            {
                Write-Host "Creating new Contacts Folder called $FolderName"
                    
                $ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service);
                $ContactsFolder.DisplayName = $FolderName
                $ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
            } 
            catch 
            {
                Write-Host "Error; Cannot create the target folder; `t$EmailAddress"
            }
        }
        
            return $ContactsFolder
    }
    Catch
    {
        Write-Host "Couldn't connect to the user's mailbox. Make sure the admin account you're using to connect to has App Impersonization permissions"
        Write-Host "Check this link for more info: https://help.bittitan.com/hc/en-us/articles/115008098447-The-account-does-not-have-permission-to-impersonate-the-requested-user"
    }
}

标签: multithreadingpowershellimportexchangewebservicesrunspace

解决方案


推荐阅读