使用Powershell中的SOAP,使用参数呈现SSRS报告

时间:2010-11-16 16:38:42

标签: powershell reporting-services

我已经玩弄了好几天没有运气。基本上我正在尝试使用Powershell构建一个简单的库来呈现SSRS报告。我正在使用Powershell试图在以后简化开发(而不是为每个项目编写C#应用程序)。大多数情况下,这将用于通过报告安排各种事情。

我的报告呈现主要是在Powershell中工作。我无法弄清楚的一件事是如何在调用render方法之前为报表提供参数。我发现了大量与C#和VB相关的代码(我在其他SSRS项目中使用过),但是我无法将其转换为Powershell。

由于我对Powershell很新,我不熟悉正确的方法。这是我一直在使用的代码:

$ReportExecutionURI = "http://glitas10//ReportServer//ReportExecution2005.asmx?wsdl"
$ReportPath = "/Financial/ExpenseReportStub"
$format = "PDF"

$deviceInfo = "<DeviceInfo><NoHeader>True</NoHeader></DeviceInfo>"
$extension = ""
$mimeType = ""
$encoding = ""
$warnings = $null
$streamIDs = $null

$Reports = New-WebServiceProxy -Uri $ReportExecutionURI -UseDefaultCredential

# Load the report 
$Report = $Reports.GetType().GetMethod("LoadReport").Invoke($Reports, @($ReportPath, $null))

# Render the report
$RenderOutput = $Reports.Render($format, $deviceInfo, [ref] $extension, [ref] $mimeType, [ref] $encoding, [ref] $warnings, [ref] $streamIDs)

显然,对于不需要参数的报表,它可以正常工作。

关于我需要做什么来实例化正确的对象并传递参数的任何想法?

3 个答案:

答案 0 :(得分:9)

以下是我最终使用的解决方案的一些信息,以防其他人需要做同样的事情。它的效果非常好。

第一种方法是构建一个由Powershell脚本使用的DLL。这很好,但它会导致两个问题。首先,您的脚本来围绕DLL。其次,此DLL绑定到特定的SSRS服务器。为了访问另一台服务器,您必须使用多个DLL。

最终,我又回到了使用网络代理。这里的关键是使用名称空间,以便您可以实例化ParameterValue对象。这是代码:

# 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()

看起来相当容易,而且确实如此。这种方法效果非常好,是我现在用来呈现和通过电子邮件发送预定报告的方法,因为它提供了比内置SSRS调度更多的灵活性。另外,它相对较快。我用来邮寄报告的其中一个脚本每分钟可以渲染和发送大约20-30个报告。

答案 1 :(得分:0)

有同样的问题,还希望将生成的MHT文件作为电子邮件正文发送: 发现以下情况有效 旧的CDO.Message是我发现的唯一允许将MHTML文件作为电子邮件正文发送的东西。 下面是VB程序的(工作)翻译 旧但很简单; - )!

################## Send MHTML email ##############################
# use antiquated CDO to send mhtml as email body

$smtpServer = "my-mail-server"
$smtpSubject = "MHT file sent as body of email"
$smtpTo = "you@work.com"
$smtpFrom = "me@home.org"
$MHTMLfile = "my-MHT-File.mht
# e.g. from an SSRS.Render


$AdoDbStream = New-Object -ComObject ADODB.Stream
$AdoDbStream.Charset = "ascii"
$AdoDbStream.Open()
$AdoDbStream.LoadFromFile($MHTMLfile)
$CdoMessage = New-Object -ComObject CDO.Message
$CdoMessage.DataSource.OpenObject($AdoDbStream,"_Stream")

$SendUsingPort = 2
$smtpPort = 25

$cfg = "http://schemas.microsoft.com/cdo/configuration/"
$CdoMessage.Configuration.Fields.Item($cfg + "sendusing") =  $SendUsingPort
$CdoMessage.Configuration.Fields.Item($cfg + "smtpserver") = $SmtpServer
$CdoMessage.Configuration.Fields.Item($cfg + "smtpserverport") = $smtpPort 

$CdoMessage.To      = $smtpTo
$CdoMessage.From    = $smtpFrom
$CdoMessage.Subject = $smtpSubject

$CdoMessage.MimeFormatted = $true
$CdoMessage.Configuration.Fields.Update()

WRITE-HOST "Sending email"
$CdoMessage.Send()

答案 2 :(得分:0)

我有一个类似的问题。 花了一些时间来找出问题所在。 如果需要,您不应“撤消”不带参数的报告 因此,代码应如下所示:

try {
    <# Despose and clear resources if open #>
    if ($RS) { $RS.Dispose() }
    if ($Stream) { $Stream.Close() }

    <# Create Report Service #>
    [string]$reportServerURI = "<SSRS Service URL>"
    $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

    <# Initial Report #>
    $reportPath = "<Full path/URL to rdl file>"
    ## Do not revoke the report ## $Report = $RS.GetType().GetMethod("LoadReport").Invoke($RS, @($reportPath, $null))
    <# Initial Report Parameters Array #> 
    $Parameters = $RS.GetType().GetMethod("LoadReport").Invoke($RS, @($reportPath, $null)).Parameters
    
    <# Populate Report Parameters values #>
    $Params = @()
    Foreach ($Parameter in $Parameters ) {
        $par1 = New-Object RS.ParameterValue;
        $Par1.Name = $Parameter.Name;
        $Par1.Label = $Parameter.Name;
        switch ($Par1.Name) {
                "<1st Param Name>"      { $par1.Value = <1st Param Value>; break }
                "<2nd Param Name>"      { $par1.Value = <2nd Param Value>; break }
                ...
                "<#n Param Name>"      { $par1.Value = <#n Param Value>; break }
            }
        $Params += $Par1;
        }

    <# Execute/invoke the report with the parameters #>
    $RS.SetExecutionParameters($Params, "en-us") > $null
    
    <# Set report render output format#>
    [string]$format = <"PDF","Excel" etc.>

    <# Eecute Report render #>
    try { $RenderOutput = $RS.Render($format,
    $deviceInfo,
    [ref] $extension,
    [ref] $mimeType,
    [ref] $encoding,
    [ref] $warnings,
    [ref] $streamIDs)       
    } catch { Log-Message -message "Unable to render or save the report due to an error." -IsError $true; throw
    }
    
    <# Convert array bytes to file and write #>
    $Stream = New-Object System.IO.FileStream(<Final Report Output File), Create, Write
    $Stream.Write($RenderOutput, 0, $RenderOutput.Length)
    $Stream.Close()
    if ($RS) { $RS.Dispose() }
    }catch{ Log-Message -message "Error in Execute-Report, could not stream or other error." -IsError $true; throw }

问题解决了。