使用 PowerShell Start-Job 的 SSRS 报告
SSRS report using PowerShell Start-Job
我有一个 PowerShell GUI,它使用字符串数组输入从 SSRS 报告中提取一些值。但是,因为这会冻结 GUI,所以我决定使用 Start-Job
来启动一个提取 SSRS 报告的作业,同时 ProgressBar 在 GUI 中保持 运行。
SSRS 报告只有一个输入参数。当我使用 Start-Job
来呈现使用多个值的报告时,无论输入值的数量如何,我都只会得到第一条记录的结果。
在没有Start-Job
返回所有输入值的记录的情况下本机调用时,相同的函数可以顺利运行。
这是代码:
$GetSSRSData = {
param([string[]]$InputArray)
$reportServerURI = "https://<SERVER>/ReportServer/ReportExecution2005.asmx?wsdl"
$RS = New-WebServiceProxy -Class 'RS' -NameSpace 'RS' -Uri $reportServerURI -UseDefaultCredential
$RS.Url = $reportServerURI
$deviceInfo = "<DeviceInfo><NoHeader>True</NoHeader></DeviceInfo>"
$extension = ""
$mimeType = ""
$encoding = ""
$warnings = $null
$streamIDs = $null
$reportPath = "/Folder/Report"
$Report = $RS.GetType().GetMethod("LoadReport").Invoke($RS, @($reportPath, $null))
# Report parameters are handled by creating an array of ParameterValue objects.
$parameters = @()
for($i = 0; $i -lt $InputArray.Count; $i++){
$parameters += New-Object RS.ParameterValue
$parameters[$i].Name = "ParameterName"
$parameters[$i].Value = "$($InputArray[$i])"
}
# Add the parameter array to the service. Note that this returns some
# information about the report that is about to be executed.
$RS.SetExecutionParameters($parameters, "en-us") > $null
# Render the report to a byte array. The first argument is the report format.
$RenderOutput = $RS.Render('CSV',
$deviceInfo,
[ref] $extension,
[ref] $mimeType,
[ref] $encoding,
[ref] $warnings,
[ref] $streamIDs
)
$output = [System.Text.Encoding]::ASCII.GetString($RenderOutput)
return $output
}
$InputArray = @('XXXXXX', 'YYYYYY', 'ZZZZZZ', 'ABCDEF')
<#
# The below code works perfectly
$Data = GetSSRSData -InputArray $InputArray
ConvertFrom-Csv -InputObject $Data
#>
$job = Start-Job -ScriptBlock $GetSSRSData -ArgumentList $InputArray
do { [System.Windows.Forms.Application]::DoEvents() } until ($job.State -ne "Running")
$Data = Receive-Job -Job $job
Write-Host $Data # returns only the first record
当我如下所示更改底部时,我能够验证作业在第一条记录输出后结束。
$RenderOutput = $RS.Render('CSV',
$deviceInfo,
[ref] $extension,
[ref] $mimeType,
[ref] $encoding,
[ref] $warnings,
[ref] $streamIDs
)
Write-Output $RenderOutput
}
$InputArray = @('XXXXXX', 'YYYYYY', 'ZZZZZZ', 'ABCDEF')
$job = Start-Job -ScriptBlock $GetSSRSData -ArgumentList $InputArray
do {[System.Text.Encoding]::ASCII.GetString($job.ChildJobs[0].Output)} until ($job.State -ne "Running")
我也试过在Render功能后加一个5秒的sleep功能,但并没有什么区别
请注意,不能为每个输入重复调用 Start-Job,因为每个函数调用都会花费大量时间,因此需要在一次调用中提取报告。
- 为什么 Render 函数在作为作业启动时表现不同?该函数是否在它也可以呈现其他记录之前过早结束?
- 有没有其他方法可以解决这个问题?
参考:
答案在这里:Invoke-Command 中的 ArgumentList 参数不发送所有数组
这里的答案可能更好:How do I pass an array as a parameter to another script?
将-ArgumentList $InputArray
更改为-ArgumentList (,$InputArray)
$InputArray = @('XXXXXX', 'YYYYYY', 'ZZZZZZ', 'ABCDEF')
$job = Start-Job -ScriptBlock $GetSSRSData -ArgumentList (,$InputArray)
我有一个 PowerShell GUI,它使用字符串数组输入从 SSRS 报告中提取一些值。但是,因为这会冻结 GUI,所以我决定使用 Start-Job
来启动一个提取 SSRS 报告的作业,同时 ProgressBar 在 GUI 中保持 运行。
SSRS 报告只有一个输入参数。当我使用 Start-Job
来呈现使用多个值的报告时,无论输入值的数量如何,我都只会得到第一条记录的结果。
在没有Start-Job
返回所有输入值的记录的情况下本机调用时,相同的函数可以顺利运行。
这是代码:
$GetSSRSData = {
param([string[]]$InputArray)
$reportServerURI = "https://<SERVER>/ReportServer/ReportExecution2005.asmx?wsdl"
$RS = New-WebServiceProxy -Class 'RS' -NameSpace 'RS' -Uri $reportServerURI -UseDefaultCredential
$RS.Url = $reportServerURI
$deviceInfo = "<DeviceInfo><NoHeader>True</NoHeader></DeviceInfo>"
$extension = ""
$mimeType = ""
$encoding = ""
$warnings = $null
$streamIDs = $null
$reportPath = "/Folder/Report"
$Report = $RS.GetType().GetMethod("LoadReport").Invoke($RS, @($reportPath, $null))
# Report parameters are handled by creating an array of ParameterValue objects.
$parameters = @()
for($i = 0; $i -lt $InputArray.Count; $i++){
$parameters += New-Object RS.ParameterValue
$parameters[$i].Name = "ParameterName"
$parameters[$i].Value = "$($InputArray[$i])"
}
# Add the parameter array to the service. Note that this returns some
# information about the report that is about to be executed.
$RS.SetExecutionParameters($parameters, "en-us") > $null
# Render the report to a byte array. The first argument is the report format.
$RenderOutput = $RS.Render('CSV',
$deviceInfo,
[ref] $extension,
[ref] $mimeType,
[ref] $encoding,
[ref] $warnings,
[ref] $streamIDs
)
$output = [System.Text.Encoding]::ASCII.GetString($RenderOutput)
return $output
}
$InputArray = @('XXXXXX', 'YYYYYY', 'ZZZZZZ', 'ABCDEF')
<#
# The below code works perfectly
$Data = GetSSRSData -InputArray $InputArray
ConvertFrom-Csv -InputObject $Data
#>
$job = Start-Job -ScriptBlock $GetSSRSData -ArgumentList $InputArray
do { [System.Windows.Forms.Application]::DoEvents() } until ($job.State -ne "Running")
$Data = Receive-Job -Job $job
Write-Host $Data # returns only the first record
当我如下所示更改底部时,我能够验证作业在第一条记录输出后结束。
$RenderOutput = $RS.Render('CSV',
$deviceInfo,
[ref] $extension,
[ref] $mimeType,
[ref] $encoding,
[ref] $warnings,
[ref] $streamIDs
)
Write-Output $RenderOutput
}
$InputArray = @('XXXXXX', 'YYYYYY', 'ZZZZZZ', 'ABCDEF')
$job = Start-Job -ScriptBlock $GetSSRSData -ArgumentList $InputArray
do {[System.Text.Encoding]::ASCII.GetString($job.ChildJobs[0].Output)} until ($job.State -ne "Running")
我也试过在Render功能后加一个5秒的sleep功能,但并没有什么区别
请注意,不能为每个输入重复调用 Start-Job,因为每个函数调用都会花费大量时间,因此需要在一次调用中提取报告。
- 为什么 Render 函数在作为作业启动时表现不同?该函数是否在它也可以呈现其他记录之前过早结束?
- 有没有其他方法可以解决这个问题?
参考:
答案在这里:Invoke-Command 中的 ArgumentList 参数不发送所有数组
这里的答案可能更好:How do I pass an array as a parameter to another script?
将-ArgumentList $InputArray
更改为-ArgumentList (,$InputArray)
$InputArray = @('XXXXXX', 'YYYYYY', 'ZZZZZZ', 'ABCDEF')
$job = Start-Job -ScriptBlock $GetSSRSData -ArgumentList (,$InputArray)