如何在单个PowerShell runspace导入Exchange本地与在线模块并复用认证?
实现Exchange本地与Exchange Online模块在单个PowerShell Runspace池中共用且无需重复认证
可以实现将Exchange本地(OnPrem)和Exchange Online的已认证会话导入单个Runspace池,所有子Runspace无需重复认证即可调用两边的命令。以下是针对你现有脚本的修正方案:
原脚本核心问题
- 错误地尝试传递
Import-PSSession生成的临时模块对象到子Runspace,这类模块依赖主Runspace的会话上下文,子Runspace无法直接复用 - 未正确将已认证的PSSession注入到Runspace池的初始会话状态(ISS),导致子Runspace无法获取Exchange Online的认证上下文
修正后的完整脚本
# -------------------------- # 1. 主Runspace中建立并认证Exchange Online会话 # -------------------------- if (-not $exoSession) { $exo_un = Get-Content "xxx" $exo_pw = Get-Content "xxx" | ConvertTo-SecureString $exo_creds = New-Object System.Management.Automation.PSCredential -ArgumentList $exo_un, $exo_pw # 连接Exchange Online并指定命令前缀,避免与本地命令冲突 Connect-ExchangeOnline -Credential $exo_creds -Prefix "Ex" -ShowBanner:$false $exoSession = Get-PSSession | Where-Object { $_.ComputerName -like "outlook.office365*" -and $_.State -eq "Opened" } | Select-Object -First 1 } # -------------------------- # 2. 主Runspace中建立并认证Exchange本地会话 # -------------------------- if (-not $exopSession) { $uri = "http://your-onprem-exchange-server/PowerShell/" # 替换为本地Exchange的PowerShell URI $exopSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Authentication Negotiate # 在主Runspace中先导入本地命令,确保命令可用 Import-PSSession $exopSession -AllowClobber -CommandName Get-Mailbox, Get-Recipient, Set-AdServerSettings | Out-Null Set-AdServerSettings -ViewEntireForest:$true } # -------------------------- # 3. 配置Runspace池的初始会话状态(ISS) # -------------------------- $iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() # 将已认证的Exchange Online会话导入ISS $iss.ImportPSSession($exoSession, @{ AllowClobber = $true CommandName = "Get-ExMailbox", "Get-ExMailboxStatistics", "Get-ExMailboxFolderStatistics" Prefix = "Ex" }) | Out-Null # 将已认证的Exchange本地会话导入ISS $iss.ImportPSSession($exopSession, @{ AllowClobber = $true CommandName = "Get-Mailbox", "Get-Recipient", "Set-AdServerSettings" }) | Out-Null # 添加Set-AdServerSettings到ISS,确保子Runspace能设置森林视图 $iss.Commands.Add(([System.Management.Automation.Runspaces.SessionStateFunctionEntry]::new("Set-AdServerSettings", (Get-Command Set-AdServerSettings).Definition))) # -------------------------- # 4. 创建并启动Runspace池 # -------------------------- $maxThreads = 50 $runspacePool = [runspacefactory]::CreateRunspacePool(1, $maxThreads, $iss, $host) $runspacePool.Open() # -------------------------- # 5. 创建子Runspace任务 # -------------------------- $powershell = [powershell]::Create() $powershell.RunspacePool = $runspacePool $powershell.AddScript({ Param ($smtp) # 确保子Runspace也能查看整个森林 Set-AdServerSettings -ViewEntireForest:$true # 调用两边的命令 $recipientExo = Get-ExMailbox -Identity $smtp -ErrorAction SilentlyContinue $recipientExop = Get-Recipient -Identity $smtp -ErrorAction SilentlyContinue # 返回结果对象 [PSCustomObject]@{ Smtp = $smtp Online = $recipientExo Onprem = $recipientExop } }) # 添加参数 $smtp = "name.name@domain.com" $powershell.AddParameter('smtp', $smtp) | Out-Null # 执行并获取结果 $returnVal = $powershell.BeginInvoke() $result = $powershell.EndInvoke($returnVal) # 输出结果 Write-Host "执行结果:" $result # 清理资源 $powershell.Dispose() $runspacePool.Close() $runspacePool.Dispose() Get-PSSession | Remove-PSSession
关键修改说明
- 复用已认证会话:在主Runspace中完成Exchange Online和本地的认证,将已建立的
PSSession直接导入到Runspace池的ISS中,子Runspace会自动继承会话的认证上下文,无需重复认证 - 避免命令冲突:使用
-Prefix "Ex"给Exchange Online的命令添加前缀,防止与本地Exchange命令重名(比如Get-Mailbox和Get-ExMailbox) - 初始会话状态配置:直接通过
ImportPSSession将已认证会话导入ISS,而非传递临时模块路径,确保子Runspace能正确调用两边的命令 - 资源清理:添加了Runspace池和会话的清理代码,避免残留未关闭的会话
内容的提问来源于stack exchange,提问作者Bbb
相关产品推荐
相关产品推荐

