Deploying SSRS Reports from Powershell
My current client has a BI group that writes SSRS reports. In the "legacy" ALM tool they built, they used VSS, nAnt,Cruise Control and a product called "Visual Intercept" to "build" (actually just extract RDL files) and a nAnt script with a custom task to Deploy the SSRS report (RDL File) to Reporting Services.
We migrated to TFS and use a lot of Powrshell for the deploy scripts. I searched for some solutions from Powershell to deploy RDL's that I felt was a good fit. This solution: http://blogs.devhorizon.com/reza/?p=751 is for a Sharepoint Reporting Service Integration. These are stand-alone SSRS reports - so I'm not even sure if I have the .DLL it relies on "ReportService2006.dl" so it was no go.
The other solution that looks quite promising, from Paul Stovell at Readify http://www.paulstovell.com/blog/reporting-services-automation is an excellent approach, but relies on a utility "rs.exe". But that wasn't installed on the server they run the deploys from (actually the TFS Build server for the time being) and I didn't want any dependencies I didn't have complete control over.
Being a C# guy - I figured the easiest thing was just to write copy the code from the original nAnt custom Task that called the SSRS Web Service to Deploy the report. I wrote a very simple Wrapper to the webservice as a Static Method to a Static Class. I then just copy the generated DLL's to the Build/Deploy server - and call that wrapper from the Deploy script. Simple enough.
I cleaned the original code a bit - adding an integer return that shows 0 for success, 4 for warnings and either 12 or 16 for a fatal error. The C# Code is here. I just added a .NET 2.0 style WebService Reference (as Derick Whitaker explains here: http://devlicio.us/blogs/derik_whittaker/archive/2008/07/21/referencing-2-0-web-services-asmx-in-visual-studio-2008.aspx in case you don't know how) to http://localhost/reportserver/reportservice.asmx?wsdl (don't use ReportService2005.asmx - that's a different web service!)
C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Linq;
using System.Text;
using SSRSDeployer.ReportServer;
using System.Web.Services.Protocols;
namespace SSRSDeployer
{
public static class SSRSDeployer
{
public static int Deploy(string webServiceURL, string rdlPath, string parentFolder, string reportName, out string warnings)
{
//create an instance of the WebService Proxy and set URL and credentials
ReportingService rs = new ReportingService();
rs.Url = webServiceURL;
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
Byte[] definition = null;
Warning[] warns = null;
StringBuilder sb = new StringBuilder();
int ret = 0;
try
{
//read the file as a filestream into a byte array
FileStream stream = File.OpenRead(rdlPath);
definition = new Byte[stream.Length];
stream.Read(definition, 0, (int)stream.Length);
// Call the web service to create the report
rs.Timeout = 1000000;
warns = rs.CreateReport(reportName, parentFolder, true, definition, null);
if (warns != null)
{
foreach (Warning warning in warns)
{
//ignore the warning about shared data source
if (!(warning.Message.StartsWith("The data set ‘") && warning.Message.Contains("’ refers to the shared data source ‘") && warning.Message.EndsWith("which is not published on the report server.")))
{
// otherwise return it to output
sb.Append(string.Format("Warning returned from WebService: {0}", warning.Message));
ret = 4;
}
}
}
}
catch (IOException)
{
//report any IO error reading the RDL file
sb.Append(string.Format("Error: IOExcption reading file: {0}", rdlPath));
ret = 12;
}
catch (SoapException e)
{
//report any Errors from the WebService call
sb.Append(e.Message);
ret = 16;
}
warnings = sb.ToString();
return ret;
}
}
}
To Call it from Powershell, simply load the assembly and call the Method: This Powershell script will deploy all RDL's found in the specified folder with a report name matching the file name. Make sure you put all the generated DLL's from the compile to the folder referenced by the $lib= statement
[string] $webServiceURL = "http://SSRSServer/ReportServer/ReportService.asmx"
[string] $rdlPath = "C:\File13"
[string] $parentFolder = "/SSRS.Folder";
$file = Get-Item $rdlPath
$lib="C:\File13\SSRSDeployer\SSRSDeployer.dll"
$x=[Reflection.Assembly]::LoadFrom($lib)
$files = Get-ChildItem $rdlPath *.rdl
ForEach ($file in $files) {
[string] $reportName = ([string] $file.Name.ToUpper()).Replace(".RDL","")
[string] $warnings = ""
"Deploying Report: $reportName"
[Int32] $result = [SSRSDeployer.SSRSDeployer]::Deploy($webServiceURL, $file.FullName, $parentFolder, $reportName, [ref] $warnings)
if ($result -eq 0) {"Deployed without Errors"}
elseif ($result -eq 4) {"Warnings from Deploy: $warnings"}
elseif ($result -eq 12) {"IO Error reading RDL File"}
elseif ($result -eq 16) {"Error Deploying Report: $warnings"}
}