如何在同一份PowerShell脚本中同时运行两个函数?含双数据库查询需求
在PowerShell中异步运行本地数据库查询与Dynamics CRM在线查询的方案
嘿,我完全懂你在PowerShell里搞异步双查询的痛苦——一边是本地数据库,一边是Dynamics CRM在线连接,两种不同的数据源要同时跑,确实容易踩坑。我之前处理过类似场景,给你分享几个实测有效的方案:
方案1:使用Start-Job(兼容PowerShell 5.x和7+)
Start-Job会创建独立的后台作业,适合隔离两个不同的查询任务。需要注意的是,每个作业都是独立进程,所以要在作业内部重新初始化连接(不能直接复用当前会话的CRM或DB连接)。
示例代码:
# 定义本地数据库查询的作业 $localDbJob = Start-Job -ScriptBlock { # 加载SqlClient模块(如果需要) Import-Module SqlServer -ErrorAction SilentlyContinue $connectionString = "Server=.\SQLEXPRESS;Database=LocalDB;Integrated Security=True;" $query = "SELECT TOP 10 * FROM Customers;" $connection = New-Object System.Data.SqlClient.SqlConnection($connectionString) $command = New-Object System.Data.SqlClient.SqlCommand($query, $connection) $connection.Open() $reader = $command.ExecuteReader() $results = @() while ($reader.Read()) { $row = [PSCustomObject]@{ ID = $reader["ID"] Name = $reader["Name"] Email = $reader["Email"] } $results += $row } $connection.Close() return $results } # 定义Dynamics CRM在线查询的作业 $crmJob = Start-Job -ScriptBlock { # 加载Dynamics CRM模块(比如Microsoft.Xrm.Data.PowerShell) Import-Module Microsoft.Xrm.Data.PowerShell -ErrorAction Stop # CRM连接参数 $crmUrl = "https://yourorg.crm.dynamics.com" $credential = Get-Credential -Message "Enter CRM credentials" # 建立CRM连接 $conn = Connect-CrmOnline -Credential $credential -ServerUrl $crmUrl # 执行CRM查询(比如获取账户记录) $query = @" <fetch top='10'> <entity name='account'> <attribute name='accountid' /> <attribute name='name' /> <attribute name='emailaddress1' /> </entity> </fetch> "@ $crmResults = Get-CrmRecordsByFetch -Fetch $query -conn $conn return $crmResults.CrmRecords } # 等待两个作业完成 Wait-Job $localDbJob, $crmJob # 获取作业结果 $localResults = Receive-Job $localDbJob $crmResults = Receive-Job $crmJob # 处理结果 Write-Host "本地数据库查询结果:" $localResults | Format-Table -AutoSize Write-Host "`nDynamics CRM查询结果:" $crmResults | Format-Table -AutoSize # 清理作业 Remove-Job $localDbJob, $crmJob
方案2:使用ForEach-Object -Parallel(PowerShell 7+专属)
如果你用的是PowerShell 7或更高版本,ForEach-Object -Parallel语法更简洁,性能也更好(基于.NET Tasks,比Start-Job轻量)。
示例代码:
# 定义两个任务的配置 $tasks = @( @{ Type = "LocalDB" ConnectionString = "Server=.\SQLEXPRESS;Database=LocalDB;Integrated Security=True;" Query = "SELECT TOP 10 * FROM Customers;" }, @{ Type = "CRM" Url = "https://yourorg.crm.dynamics.com" Credential = Get-Credential -Message "Enter CRM credentials" FetchQuery = @" <fetch top='10'> <entity name='account'> <attribute name='accountid' /> <attribute name='name' /> <attribute name='emailaddress1' /> </entity> </fetch> "@ } ) # 并行执行任务 $results = $tasks | ForEach-Object -Parallel { switch ($_.Type) { "LocalDB" { Import-Module SqlServer -ErrorAction SilentlyContinue $conn = New-Object System.Data.SqlClient.SqlConnection($_.ConnectionString) $cmd = New-Object System.Data.SqlClient.SqlCommand($_.Query, $conn) $conn.Open() $reader = $cmd.ExecuteReader() $output = @() while ($reader.Read()) { $output += [PSCustomObject]@{ Source = "LocalDB" ID = $reader["ID"] Name = $reader["Name"] Email = $reader["Email"] } } $conn.Close() return $output } "CRM" { Import-Module Microsoft.Xrm.Data.PowerShell -ErrorAction Stop $crmConn = Connect-CrmOnline -Credential $_.Credential -ServerUrl $_.Url $crmOutput = Get-CrmRecordsByFetch -Fetch $_.FetchQuery -conn $crmConn return $crmOutput.CrmRecords | ForEach-Object { [PSCustomObject]@{ Source = "CRM" AccountID = $_.accountid AccountName = $_.name Email = $_.emailaddress1 } } } } } -ThrottleLimit 2 # 输出合并后的结果 $results | Format-Table -AutoSize
关键注意事项
- 连接隔离:不管用哪种方法,后台任务/并行进程都无法继承当前会话的数据库或CRM连接,必须在每个任务内部重新初始化连接。
- 模块加载:确保在任务内部加载所需的模块(比如
SqlServer或Microsoft.Xrm.Data.PowerShell),因为后台进程的模块环境是独立的。 - 权限问题:本地数据库查询要确保后台作业的运行账户有访问权限;CRM连接要确认凭据正确,并且网络能访问Dynamics CRM在线端点。
- 调试技巧:如果任务失败,可以用
Receive-Job -Job $job -ErrorVariable err或者在并行块里添加Write-Error来捕获错误信息。
内容的提问来源于stack exchange,提问作者KhaleesiJen
相关产品推荐
相关产品推荐

