There are several different alternative methods for deploying Reporting Services reports. Whereas you might normally do this manually, or by browsing one report at a time, there are advantages in an automated approach: You might, for example, require that the deployment be scheduled off hours, or you may need to take backups before deployment. If a manual process requires more than a single simple step, than it is hard to guarantee that it will be run consistently if you need to re-run it. The ReportingServices2005 Class provides a useful means of automating a variety of processes within Reporting Services. It can be used in a variety of ways but, in this article, I will be exploring the use of different VB scripts to perform some Reporting Services deployment tasks. These VB script will be executed using the “rs”utility.

rs Utility

The rs utility is a command-line s tool that comes with SQL Server. This utility compiles and runs a Visual Basic .NET script file that can be used for a variety of tasks. We will use it to specify how a report should be deployed to a Reporting Services environment. You can use it to publish reports, manage reporting services folders and report properties, as well as a number of other Reporting Services tasks. By using the rs utility and a Visual Basic .Net script, you can automate most, if not all, of your manual Reporting Services processes.

Here is the syntax for calling this utility:

rs {-?}

[-iinput_file=]

[-sserverURL]

{-uusername}

{-ppassword}

{-ltime_out}

{-bbatchmode}

{-vglobalvars=}

{-eendpoint}

{-ttrace}

The “–i” option is used to identify a Visual Basic .NET script file that describes what Reporting Services operations need to be performed. This script file requires an .rss extension on the Visual Basic .net script file.

The “– s” option is used to identify the Reporting Service URL of the instance of Reporting Services that the script file will run against.

The “–v” option is used to pass variables (parameters) from a command line script file into your .rss Visual Basic .NET script file. You can use this option to create a Visual Basic .NET script that can be more dynamic based on the parameters passed from the rs utility execution call.

I have not discussed all of the options here. I only mentioned the options I will be using in my examples. For a complete explanation of all options, refer to the books online documentation.

In order for you to gain an understand how to use the rs utility, let me go through a couple of simple examples.

Simple code to Deploy a Report Using the rs Utility

For this first example, I will be deploying a single report from a folder on my PC to an existing folder on my Reporting Services instance. The report I will be deploying is named “MyDemoReport”, which exists in the folder “C:\MyReport”. I will be deploying this report to the “Dev” root folder on my Reporting Services instance. The instance name, or serverURL for my Reporting Services instance is http://SSESQL01/ReportServer_SQL2008.

There are two components I will need to code in order to the use the rs utility to deploy the report. The first file that I need to create is a command-line batch script that executes the rs utility. This script will define some parameters and then executes the rs utility. This script also will define some parameters that will be passed to the second component of the rs utility, which is a Visual Basic .Net script file. This script file will contain the code needed to read in my report and then deploy the report to my reporting services instance. This code will be placed in a file with an .rss extension.

Here is the command line script file (Deploy1.cmd):

set TargetFolder=/Dev/MyReports

set TargetURL=http://SSESQL01/ReportServer_SQL2008

set ReportFolder=C:\TEMP\MyReports

set ReportName=DemoReport1

rs -i Deploy_Report.rss -s %TargetURL% -v ReportFolder="%ReportFolder%"

-v TargetFolder="%TargetFolder%" -v ReportName="%ReportName%"

Note: rs line has been split for readability

As you can see, this script executes five different commands. The first four commands merely set the environment variables for the TargetFolderTargetURLReportFolder, and ReportName. The last statement executes the rs utility.

The TargetFolder identifies the directory structure within Reporting Services where my report will be deployed. In this example, that will be “/Dev/MyReports”. My Visual Basic .Net script assumes that this directory already exists prior to running the rs utility. If I wanted, I could have coded my script to automatically create this directory if it didn’t exist.

The TargetURL is used to identify the web address of my Reporting Services instance. In my case, my instance is named “ReportServer_SQL2008” and lives on machine named “SSESQL01”.

The environment variable ReportFolder, identifies the directory name that contains the rdl file that is being deployed. For this example, I’m using “C:\TEMP\MyReports”.

The last environment variable set, ReportName, identifies the report that will be deployed, less the rdl extension. In my example I will be deploying the “DemoReport1.rdl” file that resides in the “C:\Temp\MyReport\” directory.

The last command in the above script is to start the execution of the rs utility. Here you can see I am using three different parameter types “-i”, “-s” and “-v”. The “i” identifies my Visual Basic .NET code that will be used to deploy my DemoReport1 report. That code is in a file named Deploy1.rss and needs to live in the current directory path when I run this script. The “-s” parameter is set to the value of the TargetURL environment variable. There are multiple occurrences of the “-v” parameter. These “-v” parameters are used to declare and set variables that will be available within the Deploy1.rss code.

Note that if I were building a repeatable script I would replace the environment variables in the above script with parameters (%1, %2, %3 and %4). That way you could have a command shell script that could be driven with different parameters to make the process more flexible. Having this flexibility would allow you to call the script with different parameters and then based on the parameters the process would deploy a different report and/or deploy to different Reporting Services machine or directory. Alternatively, if you where familiar with some other scripting tool that could make calls to the Reporting Services2005 Class then you easily create an automated script to deploy reports.

Now that you understand how the command shell script is used to execute the rs utility, lets look at my Visual Basic .NET code that does the actual migration of my rdl file into a Reporting Services folder. Here is a copy of the Deploy1.rss code:

'

' Deploy Report

'

 

Public Sub Main()

 

Try

Dim ReportDefinition As [Byte]() = Nothing

Dim warnings as Warning() = Nothing

Dim description As New [Property]

Dim properties(0) As [Property]

 

' Open rdl file

Dim rdlfile As FileStream = File.OpenRead(ReportFolder + "\" + ReportName + ".rdl")

 

'read report definition

ReportDefinition = New [Byte](rdlfile.Length) {}

rdlfile.Read(ReportDefinition, 0, CInt(rdlfile.Length))

rdlfile.Close()

 

'Set Report Description

description.Name = "Description"

description.Value = "This is my demo report"

properties(0) = description

 

'Create Report on Report Server

warnings = rs.CreateReport(ReportName, TargetFolder, True, ReportDefinition, Properties)

 

'display warnings if there are any

If Not (warnings Is Nothing) Then

Dim warning As Warning

For Each warning In warnings

Console.WriteLine(warning.Message)

Next warning

 

Else

Console.WriteLine("Report: " + ReportName + " published successfully with no warnings")

End If

Catch e As IOException

Console.WriteLine(e.Message)

End Try

End Sub

Let me go through this code and explain how it works. After declaring a couple of items, the script first opens the report rdl file by executing the “File.OpenRead” methodThis code concatenates together the ReportFolder andReportName variables along with “.rdl” to identify the rdl file to open. The parameters used in the OpenRead method call, were passed to the VB .NET code by using the “-v” option on the rs.exe command. You’ll notice that these two parameters are not declared within the code above before the OpenRead invocation. The rs utility allows you to reference the “-v” parameters (variables) within the Visual Basic .NET code without declaring them. After the rdl file is opened, it is then read using the FileStream Read method. The rdl file is read into the ReportDefinition Byte variable. Next, I set the description property for the report. The ReportDefinition object is then used to create the report on the Report Server using the CreateReport method, which is part of the ReportingServices2005 Class. The CreateReport Method requires the following parameters:

  • ReportName - which contains the name of the Reporting Services report less the .rdl extension.
  • TargetFolder – which contains the Reporting Services parent folder where the report will be placed.
  • Overwrite option – which is a Boolean value that indicates whether a report is to be overwritten or not should it already exist on the report server.
  • ReportDefinition – This parameter contains the definition of the report to be created.
  • Properties – The properties option allows you to set the properties for the report.

The code then finishes off by displaying any warning messages that might have been created while deploying the report. Note that you might get the following warning message:

The dataset `MyDataSource' refers to the shared data source `MyDataSource', which is not published on the report server.

This warning message is telling you that the dataset “MyDataSource” defined in my DemoReport1.rdl refers to a shared data source that is not on the report server. If you get this warning you need to create the data source before this report can be run on the Report Server.

Programmatically Changing a Report Definition

You’ll have seen that very little code is needed to be build a scripting process to deploy a single reporting services report. However, there are lots of different methods and properties, within the ReportingService2005 Class, if you need them. You could, for example, use this class to write applications that will interface with the Reporting Services web service to do many different things to your Reporting Services environment.

Most Reporting Services environments will be setup to have separate development, test and production locations on different servers, or in different folders on the same server. Development, test and production environments might also have different data source names. You can avoid these complications by creating a script with theReportingService2005 class, to migrate reports from one server to another, or folder to folder. This will allow you to automatically switch a data source, or other reporting services properties as a report moves through your development life cycle.

You might have noticed that I got an error related to a missing shared data source with my DemoReport1.rdl file when I deployed into my /Dev/MyReports folder. To make sure that my report does not fail when I try to run it, I need to change the data source to a shared data source that lives in the target environment. I can do that by modifying my example slightly in two places. I must modify my shell script so I can pass another parameter to my Visual Basic .Net code that identifies my shared data source. I also need to modify my .Net code to set the data source in my report definition at some point during the deployment.

Below are my modified scripts I created to support this new requirement to set the data source. Review highlighted code to see where I made changes.

rs Utility Script:

set TargetFolder=/Dev/MyReports

set SourceURL=http://SSESQL01/ReportServer_SQL2008

set ReportFolder=C:\TEMP\MyReports\\

set ReportName=DemoReport1

set TargetDataSource=/DataSource/DevServer

rs -i Deploy_Report_N_DS.rss -s %SourceURL% -v ReportFolder="%ReportFolder%"

-v TargetFolder="%TargetFolder%"

-v ReportName="%ReportName%"

-v TargetDataSource="%TargetDataSource%

 

(note: rs line has been split for readability)

 

Visual Basic .NET code:

'

' Deploy Report and Set Data Source

'

Public Sub Main()

 

Try

Dim ReportDefinition As [Byte]() = Nothing

Dim warnings as Warning() = Nothing

 

Dim description As New [Property]

Dim properties(0) As [Property]

 

' Open rdl file

Dim rdlfile As FileStream = File.OpenRead(ReportFolder + "\" +ReportName + ".rdl")

 

'read report definition

ReportDefinition = New [Byte](rdlfile.Length) {}

rdlfile.Read(ReportDefinition, 0, CInt(rdlfile.Length))

rdlfile.Close()

 

'Set Report Description

description.Name = "Description"

description.Value = "This is my demo report"

properties(0) = description

 

'Create Report on Report Server

warnings = rs.CreateReport(ReportName, TargetFolder, True, ReportDefinition, Properties)

 

'display warnings if there are any

If Not (warnings Is Nothing) Then

Dim warning As Warning

For Each warning In warnings

Console.WriteLine(warning.Message)

Next warning

 

Else

Console.WriteLine("Report: " + ReportName + " published successfully with no warnings")

End If

 

'Set data source based on DataSource parameter

Dim Item1 as DataSourceReference = New DataSourceReference

Dim datasources As [DataSource]() = rs.GetItemDataSources(TargetFolder + "/" + ReportName)

Item1.Reference = TargetDataSource

datasources(0).Item = Item1

rs.SetItemDataSources(TargetFolder + "/" + ReportName, datasources)

 

Catch e As IOException

Console.WriteLine(e.Message)

End Try

End Sub

In the highlighted code within my Visual Studio .Net code, I create a new data source and then populated it with the existing data source for my DemoReport1 report. I did this using the GetItemDataSource method. I then set aDataSourceReference (Item1) using the value passed in the “TargetDataSource” parameter. By looking at the rsUtility script above you can see my new data source will be “/DataSource/DevServer”. Lastly, I set the data source on my target report using the “SetItemDataSource” method.

Browsing a Reporting Services Report Folder and Moving all Reports to Another Folder

For my last example let me show how you can use the rs utility to copy all reports from one Reporting Services folder and another folder. Below is the VB Script code for this example. Before you look at this VB Script I probably should mention some of the limitations of this script:

  • Only copies reports, not Data Sources, or linked reports
  • Does not copy any special properties that you might assign to those report, like subscription, special caching options, parameters, etc.
  • Doesn’t support changing embedded data sources, but does change a shared data source reference
  • Requires target folder to already exists prior to running process

VB Script for Copy Reports:

' Copy Entire Folder

'

' Description: This script copies all the reports from a source folder to a target folder

'

' Define global variables used by different Sub's

Dim Reportdefinition As [Byte]() = Nothing

Dim warnings As Warning() = Nothing

Dim ReportName as String

Dim reportItems As CatalogItem()

Dim reportItem As CatalogItem

Dim strDisplay As String

Dim type As String

Dim props(1) As [Property]

Dim DescProp as New [Property]

Dim HiddenProp as New [Property]

Dim properties As [Property]()

 

' Declare source and target

Dim srs As New ReportingService2005()

Dim trs As New ReportingService2005()

Public Sub Main()

 

' Establish Source Credentials

srs.Credentials = System.Net.CredentialCache.DefaultCredentials

srs.url = sourceURL & "/ReportService2005.asmx"

 

' Establish Target Credentials

trs.Credentials = System.Net.CredentialCache.DefaultCredentials

trs.url = targetURL & "/ReportService2005.asmx"

 

' Process through source folder identifying Reports

reportItems = rs.ListChildren(sourceFolder, false)

' Iterate through the results

For Each reportItem In reportItems

' get type of item

type = srs.GetItemType(sourceFolder + "/" + ReportItem.Name)

' Is Item type a Report

If (type = 2)

' read the Source Report

ReadSource()

' Deploy Report Type to Target Type

DeployTarget()

End If

Next

End Sub

 

Public Sub ReadSource()

Try

ReportDefinition = rs.GetReportDefinition(sourceFolder + "/" + ReportItem.Name)

DescProp.Name = "Description"

props(0) = DescProp

HiddenProp.Name = "Hidden"

props(1) = HiddenProp

properties = rs.GetProperties(sourceFolder + "/" + ReportItem.Name, props)

 

Catch e As IOException

Console.WriteLine(e.Message)

End Try

 

strDisplay = "Report: " & reportItem.Name & " Source Read"

Console.Writeline(strDisplay)

End Sub 'ReadSource

 

 

Public Sub DeployTarget()

Try

warnings = rs.CreateReport(reportItem.Name, TargetFolder, True, ReportDefinition, properties)

'Set data source based on DataSource parameter

Dim Item1 as DataSourceReference = New DataSourceReference

Dim datasources As [DataSource]() = rs.GetItemDataSources(targetFolder + "/" + ReportItem.Name)

Item1.Reference = targetDataSource

datasources(0).Item = Item1

rs.SetItemDataSources(targetFolder + "/" + ReportItem.Name, datasources)

 

 

If Not (warnings Is Nothing) Then

Dim warning As Warning

For Each warning In warnings

Console.WriteLine(warning.Message)

Next warning

Else

strDisplay = "Report " & reportItem.Name & " Published"

Console.Writeline(strDisplay)

End If

Catch e As IOException

Console.WriteLine(e.Message)

End Try

End Sub 'DeployTarget

 

I’m not going to go through this code in detail, but below I will explain the process and discuss some of the methods used in this script.

Just like in my prior examples this code is executed by using a command shell script that passes parameters via the –v option of the rs utility. Here is the command shell script used to execute the VB script file above:

set sourceFolder=/Dev

set targetFolder=/Prod

set sourceURL=http://ssesql01/ReportServer_SQL2008

set targetURL=http://ssesql01/ReportServer_SQL2008

set targetDataSource=/DataSource/ProdServer

set copyScript=C:\temp\Demo3\ReadSource_DeployTarget_EntireDirectory.rss

 

rs -s http://ssesql01/ReportServer_SQL2008 -i "%copyscript%"
   -v sourceURL="%SourceURL%" -v targetURL="%targetURL%"

   -v sourceFolder="%sourceFolder%" -v targetFolder="%targetFolder%" 
   -v targetDataSource="%targetDataSource%"

Note: rs line has been split for readability and my VBScript (ReadSource_DeployTarget_EntireDirectory) needs to live in the “C:\temp\Demo3 folder)

If you look at the rs utility call above you can see that my VBScript requires 5 different parameters:

  • sourceURL: identifies source Reporting Services instance from where you want to copy your reports
  • targetURL: identifies target Reporting Services instance to where you want to copy your reports
  • sourceFolder: identifies the complete folder name from where the reports will be copied
  • targetFolder: identifies the complete folder name to where the reports will be copied
  • targetDataSource: identifies the full data source name for the target data source, used to modify the data source of the reports being copied.

The VBScript file can be looked at as having four different sections of code. The first section declares some variables and objects that are used in the other three sections. In that section you should note that there are two different SQLReporting2005 objects being created. One object is named “srs” for the source Reporting Services environment and the second is “trs” for the target reporting services environment. The different reporting services environments can be on the same reporting services instance or on different ones. In my command script above, I referenced these two different Reporting Services environments using the sourceFolder and targetFolder parameters passed from the rs utility.

The next section is the “Main” subroutine. In this section, the source and target reporting services credentials are established. Next, the “ListChildren” method is used to return an array of objects contained in the source folder. The array is then processed in a loop until all objects has been processed. For each iteration through the loop the “GetItemType” method is used to determine if the current object type is a report (type=2). If the object is a report then the source folder is read using the “ReadSource” subroutine followed by creating the report in the target folder using the “DeployReport” subroutine.

The “ReadSource” subroutine is used to get the report definition from the source folder. It does this by first obtaining the report definition using the GetReportDefinition method. Then retrieves that report properties using the GetProperties methods.

To create the reports in the target folder the “DeployReport” subroutine is used. The CreateReport method is then used to create the report. To obtain the original data source configuration information the GetItemDataSources method is used. The targetDataSource parameter is then used in conjunction with the SetItemDataSources method to replace the original data source with a new reference to the appropriate data source for the target environment.

I have only shown you a few things that you can do with the rs utility and some Visual Basic .NET code. Just think what you could do with a full-blown desktop or server-based .NET deployment application.

Building Applications to Exploit the ReportingServices2005 Class

If you are currently using a manually process to migrate your rdl reports between your Reporting Services folders or other environments, then you should consider how to exploit the Reporting Service 2005 class library and web service to perform those migrations. By using the ReportingServices2005 class library, you can create a number of different routines to migrate and backup your reports. Simplify your deployment processes by building an automated deployment process too, using the rs utility.