[英]Is it possible to share module between runspaces or assign a module to a runspace pool in Powershell?
我正在編寫一個多線程腳本,該腳本利用運行空間的多線程能力並節省時間,直到我不得不使用 Exchange 模塊。 加載 Exchange 模塊需要很長時間,幾乎與同步處理一樣慢或慢。
下面是我正在使用的代碼,要重現,您需要填充服務器陣列和 Exchange uri。 在底部的引號中,您可以看到我收到的錯誤,表明未加載 Exchange 模塊並且無法訪問 Exchange cmdlet。
有沒有辦法將模塊復制到每個新的運行空間,並且只初始化一次或另一種方式,我可以通過 Exchange Powershell 顯着節省時間並獲得多個運行空間的好處?
Get-Module | Remove-Module;
#Region Initial sessionstate
$servers = @("XXXXX", "XXXXX", "XXXXX");
$uri = 'https://XXXXX/powershell?ExchClientVer=15.1';
$session = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Authentication Negotiate;
$sessionImported = Import-PSSession $session -AllowClobber;
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::Create($sessionImported);
$modules = Get-Module ;
foreach ($module in $modules)
{
if ($module.ExportedCommands.Keys -contains "get-mailbox")
{
$exchangeModule = $module;
}
}
$initialSessionState = [initialsessionstate]::CreateDefault()
$initialSessionState.ImportPSModule($exchangeModule)
#EndRegion Initial sessionstate
$RunspacePool = [runspacefactory]::CreateRunspacePool($initialSessionState);
$RunspacePool.Open();
foreach ($server in $servers)
{
$threads = New-Object System.Collections.ArrayList;
$PowerShell = [powershell]::Create($sessionState);
$PowerShell.RunspacePool = $RunspacePool;
[void]$PowerShell.AddScript({
Param ($server)
[pscustomobject]@{
server = $server
} | Out-Null
Set-ADServerSettings -ViewEntireForest:$true;
$mbs = Get-MailboxDatabase -Server $server -Status;
return $mbs;
}) # end of add script
$PowerShell.AddParameter('server', $server) | Out-Null;
$returnVal = $PowerShell.BeginInvoke();
$temp = "" | Select PowerShell,returnVal;
$temp.PowerShell = $PowerShell;
$temp.returnVal = $returnVal;
$threads.Add($Temp) | Out-Null;
} #foreach server
$completed = $false;
$threadsCompleted = New-Object System.Collections.ArrayList;
while ($completed -eq $false)
{
$completed = $true;
$threadsCompleted.Clear();
foreach ($thread in $threads)
{
$endInvoke = $thread.PowerShell.EndInvoke($thread.returnVal);
#$endInvoke;
$threadHandle = $thread.returnVal.AsyncWaitHandle.Handle;
$threadIsCompleted = $thread.returnVal.IsCompleted;
if ($threadIsCompleted -eq $false)
{
$completed = $false;
}
else
{
$threadsCompleted.Add($threadHandle) | Out-Null;
}
}
Write-Host "Threads completed count: " $threadsCompleted.Count;
foreach ($threadCompleted in $threadsCompleted)
{
Write-Host "Completed thread handle -" $threadCompleted;
}
#Write-Host "";
sleep -Milliseconds 1000;
} # while end
Write-Host "Seconds elapsed:" $stopwatch.Elapsed.TotalSeconds;
Write-Host "";
$temp.PowerShell.Streams.Error;
return;
Set-ADServerSettings:術語“Set-ADServerSettings”不能識別為 cmdlet、function、腳本文件或可運行程序的名稱。 檢查名稱的拼寫,或者如果包含路徑,請驗證路徑是否正確並重試。 在行:9 字符:3
Set-ADServerSettings -ViewEntireForest:$true;
~~~~~~~~~~~~~~~~~~~~
- CategoryInfo: ObjectNotFound: (Set-ADServerSettings:String) [], CommandNotFoundException
- fullyQualifiedErrorId:CommandNotFoundException Get-MailboxDatabase:術語“Get-MailboxDatabase”未被識別為 cmdlet、function、腳本文件或可運行程序的名稱。 檢查名稱的拼寫,或者如果包含路徑,請驗證路徑是否正確並重試。 在行:10 字符:10
$mbs = Get-MailboxDatabase -Server $server -Status;
~~~~~~~~~~~~~~~~~~~
- CategoryInfo: ObjectNotFound: (Get-MailboxDatabase:String) [], CommandNotFoundException
- 完全限定錯誤 ID:CommandNotFoundException
所以答案是肯定的,我發現您可以使用來自 initialsessionstate 的名為 ImportPSModule 的屬性(它可以接受來自 static 模塊的已知模塊名稱或動態或自定義模塊的文件路徑),Exchange 的棘手之處在於該模塊是動態創建的。 但是有希望,如果您按照我在下面的方式捕獲模塊,它有一個名為“Path”的屬性,它為您提供了一個本地文件路徑,該路徑是模塊在第一次創建后臨時存儲在機器上的位置在那個特定的 session 期間。
我還發現您可以指定要導入的命令列表(在下面注釋掉),如果您只需要幾個命令,則可以節省大量導入 Exchange 模塊的時間。 從字面上看,Exchange 命令導入的進度條僅在您僅過濾幾個命令時才會閃爍,如果您要閃爍,您就會錯過它。 如果您使用特定的命令代碼,請確保導入 get-mailbox 命令,因為這就是我過濾哪個模塊用於 Exchange on prem 的方式,並將 uri 配置到您的環境。
單線程版本的基准測試是 106 秒,我見過的運行空間和多線程的代碼進程最快是 9.8 秒,因此處理時間節省的潛力是巨大的。
$WarningPreference = "SilentlyContinue";
Get-Module | Remove-Module;
#Region Initial sessionstate
$uri = 'https://xxxxx/powershell?ExchClientVer=15.1';
$session = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Authentication Negotiate;
Import-PSSession $session -AllowClobber > $null;
#Import-PSSession $session -AllowClobber -CommandName Get-Mailbox, Get-MailboxDatabaseCopyStatus, Get-MailboxDatabase, Get-DatabaseAvailabilityGroup > $null;
$modules = Get-Module;
foreach ($module in $modules)
{
if ($module.ExportedCommands.Keys -contains "get-mailbox")
{
$exchangeModule = $module;
}
}
$maxThreads = 17;
$iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
[void]$iss.ImportPSModule($exchangeModule.Path)
$runspacePool = [runspacefactory]::CreateRunspacePool(1, $maxThreads, $iss, $host)
$runspacePool.Open()
#Region Get dag members
$PowerShell = [powershell]::Create($iss); # may not need a runspace here
$PowerShell.RunspacePool = $RunspacePool;
$PowerShell.AddCommand("get-databaseavailabilitygroup") | Out-Null;
$PowerShell.AddParameter("identity", $DagName) | Out-Null;
$returnVal = $PowerShell.Invoke(); # writes to screen
$servers = New-Object System.Collections.ArrayList;
$serversUnsorted = $returnVal.Servers | sort;
foreach ($server in $serversUnsorted)
{
$servers.Add($server) | Out-Null;
}
#EndRegion Get dag members
#EndRegion Initial sessionstate
foreach ($server in $servers)
{
$PowerShell = [powershell]::Create($iss);
$PowerShell.RunspacePool = $RunspacePool;
[void]$PowerShell.AddScript({
Param ($server)
[pscustomobject]@{
server = $server
} | Out-Null
Set-ADServerSettings -ViewEntireForest:$true;
$copyStatus = Get-MailboxDatabaseCopyStatus -Server $server;
return $copyStatus;
}) # end of add script
$PowerShell.AddParameter('server', $server) | Out-Null;
$returnVal = $PowerShell.BeginInvoke();
$temp = "" | Select PowerShell,returnVal;
$temp.PowerShell = $PowerShell;
$temp.returnVal = $returnVal;
$threads.Add($Temp) | Out-Null;
} #foreach server
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.