Here's some information on the solution that I ended up using, in case anyone else needs to do the same. It works really well.
The first approach that worked was building a DLL to use by the Powershell script. This worked fine, but it causes two problems. First, your script had to tote around a DLL. Second, this DLL was tied to a specific SSRS server. In order to access another server, you had to use multiple DLLs.
Eventually, I moved back to using a web proxy. The key here is to use namespaces so that you can instantiate a ParameterValue object. Here's the code:
# Create a proxy to the SSRS server and give it the namespace of 'RS' to use for
# instantiating objects later. This class will also be used to create a report
# object.
$reportServerURI = "http://<SERVER>/ReportServer/ReportExecution2005.asmx?WSDL"
$RS = New-WebServiceProxy -Class 'RS' -NameSpace 'RS' -Uri $reportServerURI -UseDefaultCredential
$RS.Url = $reportServerURI
# Set up some variables to hold referenced results from Render
$deviceInfo = "<DeviceInfo><NoHeader>True</NoHeader></DeviceInfo>"
$extension = ""
$mimeType = ""
$encoding = ""
$warnings = $null
$streamIDs = $null
# Next we need to load the report. Since Powershell cannot pass a null string
# (it instead just passses ""), we have to use GetMethod / Invoke to call the
# function that returns the report object. This will load the report in the
# report server object, as well as create a report object that can be used to
# discover information about the report. It's not used in this code, but it can
# be used to discover information about what parameters are needed to execute
# the report.
$reportPath = "/PathTo/Report"
$Report = $RS.GetType().GetMethod("LoadReport").Invoke($RS, @($reportPath, $null))
# Report parameters are handled by creating an array of ParameterValue objects.
$parameters = @()
$parameters += New-Object RS.ParameterValue
$parameters[0].Name = "Parameter 1"
$parameters[0].Value = "Value"
$parameters += New-Object RS.ParameterValue
$parameters[1].Name = "Parameter 2"
$parameters[1].Value = "Value"
# 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.
# The formats I've tested are: PDF, XML, CSV, WORD (.doc), EXCEL (.xls),
# IMAGE (.tif), MHTML (.mhtml).
$RenderOutput = $RS.Render('PDF',
$deviceInfo,
[ref] $extension,
[ref] $mimeType,
[ref] $encoding,
[ref] $warnings,
[ref] $streamIDs
)
# Convert array bytes to file and write
$Stream = New-Object System.IO.FileStream("output.pdf"), Create, Write
$Stream.Write($RenderOutput, 0, $RenderOutput.Length)
$Stream.Close()
It seems rather easy, and it is. This method works exceptionally well and is the method I'm using now to render and email scheduled reports, as it provides much more flexibility than the built in SSRS scheduling. In addition, it's relatively fast. One of the scripts I'm using to mail out reports can render and send out about 20-30 reports a minute.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…