SharePoint 2010 Deployment (Teil 5) – Deployment von SQL Server Reporting Services Reports

16. Mai 2012

Bei SharePoint 2010 Deployment handelt es sich um eine Serie von Blogbeiträgen, die die verschiedenen Schritte für das Deployment von SiteCollections erläutert und ausführt. Dabei wird der Fokus auf das Wiederherstellen einer Backup-Datei aus einer SharePoint-Umgebung in eine andere (z.B. von einer Entwicklungsumgebung auf eine Test- oder Produktivumgebung) gelegt.

 

Die Serie “SharePoint 2010” besteht aus den folgenden Beiträgen:

  1. Erstellen einer SiteCollection
  2. Wiederherstellen einer Backup-Datei
  3. Erstellen von Secure Store Applikationen
  4. Importieren von Business Data Connectivity Models (BDCM)
  5. Deployment von SQL Server Reporting Services (SSRS) Reports

Im letzten Teil dieser Blogserie behandeln wir das Deployment von SSRS Reports in eine SharePoint-Bibliothek mit Hilfe von Powershell. Dafür erweitern wir die, im ersten Teil der Blogserie, erstellte Konfigurationsdatei sowie das Powerhell-Skript, um die Aktionen für das Deployment von Report-Dateien (*.rdl) und der Datenquelldateien (*.rds). Dieses Powershell-Skript kann entsprechend der Anforderungen individuell angepasst werden.

Für die Erweiterung, der im ersten Teil der Blogserie erstellten Powershell- und Konfigurationsdatei, sowie das nachträgliche Ausführen sind die folgenden Schritte auszuführen:

  1. Erweitern der Konfigurationsdatei
  2. Erweitern der Powershell-Datei
  3. Ausführen

In diesem Beispiel deployen wir einen SSRS Report, der eine Shared DataSource verwendet.

Voraussetzungen

Voraussetzung, für ein erfolgreiches Deployment von SSRS Reports, ist das Bestehen einer Reportbibliothek, sowie einer Datenverbindungsbibliothek auf ihrer SiteCollection.

Des Weiteren muss SSRS im “SharePoint Integrated Mode” konfiguriert werden. Hier finden Sie eine Anleitung dazu.

Erweitern der Konfigurationsdatei

Um ein unabhängiges Deployment zu verwenden, haben wir im ersten Teil dieser Blogserie Erstellen einer SiteCollection eine Konfigurationsdatei (Konfiguration.xml) erstellt. Diese müssen wir um die zu konfigurierenden Elemente für das Deployment von Reports erweitern.

<ReportSourcePath>Pfad zu den Report-Dateien (*.rdl, *.rds, *.rsd)</ReportSourcePath>
<TargetReportLibrary>Name der Reportbibliothek</TargetReportLibrary>
<TargetReportFolder>Name des Ordners in dem die Reports liegen</TargetReportFolder>
<TargetDataConnectionLibrary>Name der Datenverbindungsbibliothek</TargetDataConnectionLibrary>
<TargetDataConnectionFolder>Name des Ordners in dem die DataSources liegen</TargetDataConnectionFolder>
<TargetDataSetLibrary>Name der DataSets-Bibliothek</TargetDataSetLibrary>
<TargetDataSetFolder>Name des Ordners in dem die DataSets liegen</TargetDataSetFolder>
<SSRSWebservice>/ReportServer/ReportService2010.asmx?wsdl</SSRSWebservice>

Erweitern der Powershell-Datei

Im folgenden Schritt erweitern das im ersten Teil der Blogserie erstellte Powershell-Skript (Deployment.ps1) um die in der Konfigurationsdatei neu erstellten Elemente.

#Reporting Variables
$ReportSourcePath = $configurationElement.Config_Content.ReportSourcePath
$TargRepLibrary = $configurationElement.Config_Content.TargetReportLibrary
$TargetReportFolder = $configurationElement.Config_Content.TargetReportFolder
$TargDataConnLibrary = $configurationElement.Config_Content.TargetDataConnectionLibrary
$TargDataConnFolder = $configurationElement.Config_Content.TargetDataConnectionFolder
$TargDataSetLibrary = $configurationElement.Config_Content.TargetDataSetLibrary
$TargDataSetFolder = $configurationElement.Config_Content.TargetDataSetFolder

$SSRSWebservice = $configurationElement.Config_Content.SSRSWebservice
$WebserviceUrl = $Webapplication + $SSRSWebservice

#Create Proxy
$ssrsProxy = New-WebServiceProxy -Uri $WebserviceUrl -UseDefaultCredential

$force = $true;
$ErrorActionPreference="Stop"
$proxyNamespace = $ssrsProxy.GetType().Namespace

Als nächstes erstellen wir drei Funktionen:

  1. Install-DataSource
  2. Install-DataSets
  3. Install-Reports

Install-DataSources

function Install-DataSource([string] $dsFile)
{
$dataSourcePath = $newCollectionSite + "/" + $TargDataConnLibrary
$dataSourceFolder = $dataSourcePath + "/" + $TargDataConnFolder

if($force)
{
#Check if folder is existing, create if not found
try
{
$ssrsProxy.CreateFolder($TargDataConnFolder, $dataSourcePath, $null)
Write-Host "Created new folder: $TargDataConnFolder"
}
catch [System.Web.Services.Protocols.SoapException]
  {
if ($_.Exception.Detail.InnerText -match "[^rsItemAlreadyExists400]")
{
Write-Host "Folder: $TargDataConnFolder already exists."
}
else
{
$msg = "Error creating folder: $TargDataConnFolder. Msg: '{0}'" -f $_.Exception.Detail.InnerText
Write-Error $msg
}
}
}



try
{
#Load the data source Xml
$DSXml = Get-Content ($dsFile);
#Initialize a DataSourceDefinition object
$dsDefinition = New-Object ("$proxyNamespace.DataSourceDefinition");
#Initialize a DataSource object
$dSource = New-Object ("$proxyNamespace.DataSource")
$dSource.Item = $dsDefinition
#Read the settings from XML and populate related props
$dsDefinition.Extension = $DSXml.RptDataSource.ConnectionProperties.Extension
$dsDefinition.ConnectString = $DSXml.RptDataSource.ConnectionProperties.ConnectString
$dsDefinition.ImpersonateUserSpecified = $false
$dsDefinition.Prompt = $null
$dsDefinition.WindowsCredentials = $false
#$dsDefinition.CredentialRetrieval = [CredentialRetrievalEnum]::Integrated
$dSource.Name = $DSXml.RptDataSource.Name
$dsFileName = [String]::Concat($DSXml.RptDataSource.Name,".rsds")
$rsdsAbsoluteUrl = [string]::Concat($dataSourceFolder,$dsFileName)

#Call Proxy to upload report
$ssrsProxy.CreateDataSource($dsFileName,$dataSourceFolder,$force,$dsDefinition,$null)
if($warnings.Length -eq $null) { Write-Host "Upload Success." }
else { $warnings | % { Write-Warning "Warning: $_" }}
}
catch [System.IO.IOException]
{
$msg = "Error while reading rsds file : '{0}', Message: '{1}'" -f $dsFile, $_.Exception.Message
Write-Error $msg
}
catch [System.Web.Services.Protocols.SoapException]
{
$msg = "Error while uploading rsds file : '{0}', Message: '{1}'" -f $dsFile, $_.Exception.Detail.InnerText
Write-Error $msg
}
}

Install-DataSets

function Install-DataSets([string] $dSetFile)
{
$dataSetPath = $newCollectionSite + "/" + $TargDataSetLibrary
$dataSetFolder = $dataSetPath + "/" + $TargDataSetFolder

if($force)
{
#Check if folder is existing, create if not found
try
{
$ssrsProxy.CreateFolder($TargDataSetFolder, $dataSetPath, $null)
Write-Host "Created new folder: $TargDataSetFolder"
}
catch [System.Web.Services.Protocols.SoapException]
{
if ($_.Exception.Detail.InnerText -match "[^rsItemAlreadyExists400]")
{
Write-Host "Folder: $TargDataSetFolder already exists."
}
else
{
$msg = "Error creating folder: $TargDataSetFolder. Msg: '{0}'" -f $_.Exception.Detail.InnerText
Write-Error $msg
}
}
}



#Load the data source Xml
$DSXml = Get-Content ($dSetFile);
$file = Get-ChildItem($dSetFile);
$site = Get-SPSite $newCollectionSite;
$web = $site.RootWeb;
$rsdFolder = $web.GetFolder("$TargDataSetLibrary/$TargDataSetFolder");

$destUrl = $dataSetFolder+"/"+$file.Name

(Get-Content $dSetFile) | % {$_ -replace "</DataSourceReference>",".rsds</DataSourceReference>"} | Set-Content -path $dSetFile

$rsdFile = $web.GetFile($desturl)
$fileCheckedOut = "N"
if($rsdFile.Exists)
{
$rsdFile.CheckOut();
$fileCheckedOut = "Y"
}
$stream = [IO.File]::OpenRead($dSetFile)
$resultingfile = $rsdFolder.files.Add($desturl,$stream,$true)
$stream.close()

if($fileCheckedOut -eq "Y")
{
$rsdFile.CheckIn("Deployment Script")
}
$rsdFile.Update()

WRITE-HOST "Successfully Deployed Data Set:" $file.Name
}

Install-Reports

function Install-Reports([string]$rdlFile)
{
$reportPath = $newCollectionSite+"/"+$TargRepLibrary

if($force)
{
#Check if folder is existing, create if not found
try
{
$ssrsProxy.CreateFolder($TargetReportFolder, $reportPath, $null)
Write-Host "Created new folder: $TargRepLibrary"
}
catch [System.Web.Services.Protocols.SoapException]
{
if ($_.Exception.Detail.InnerText -match "[^rsItemAlreadyExists400]")
{
Write-Host "Folder: $TargRepLibrary already exists."
}
else
{
$msg = "Error creating folder: $TargRepLibrary. Msg: '{0}'" -f $_.Exception.Detail.InnerText
Write-Error $msg
}
}
}

#Add datasource and dataset extensions
(Get-Content $rdlFile) | % {$_ -replace "</DataSourceReference>",".rsds</DataSourceReference>"} | Set-Content -path $rdlFile
(Get-Content $rdlFile) | % {$_ -replace "</SharedDataSetReference>",".rsd</SharedDataSetReference"} | Set-Content -path $rdlFile

#Get the RDL Item
$rptFileInfo = Get-Item ($rdlFile);
$reportName = $rptFileInfo.Name;

try
{
#Get Report content in bytes
$byteArray = gc $rdlFile -encoding byte

$reportFolder = $newCollectionSite + "/" + $TargRepLibrary + "/" + $TargetReportFolder

#Call Proxy to upload report
$warnings = $null
$ssrsProxy.CreateCatalogItem("Report",$reportName,$reportFolder,$force,$byteArray,$null,[ref]$warnings)
if($warnings.Length -eq $null) { Write-Host "Upload Success." }
}
catch [System.IO.IOException]
{
$msg = "Error while reading rdl file : '{0}', Message: '{1}'" -f $rdlFile, $_.Exception.Message
Write-Error $msg
}
catch [System.Web.Services.Protocols.SoapException]
{
$msg = "Error while uploading rdl file : '{0}', Message: '{1}'" -f $rdlFile, $_.Exception.Detail.InnerText
Write-Error $msg
}

#Fix up the data source
$rptXml = Get-Content ($rdlFile);
#Extract the data source used by report
$localDSName = $rptXml.Report.DataSources.DataSource.Name
$dataSourceFolder = $newCollectionSite + "/" + $TargDataConnLibrary + "/" + $TargDataConnFolder

$rptAbsoluteUrl = [string]::Concat($reportFolder,"/",$reportName)
$rsdsAbsoluteUrl = [string]::Concat($dataSourceFolder,"/",$localDSName,".rsds")

$catalogItemDtSrcs = $ssrsProxy.GetItemDataSources($rptAbsoluteUrl)
$reference = New-Object ("$proxyNamespace.DataSourceReference")
$dsNew = New-Object ("$proxyNamespace.DataSource")
$reference.Reference = $rsdsAbsoluteUrl
$dsNew = $catalogItemDtSrcs[0]
$dsNew.Item = $reference
$ssrsProxy.SetItemDataSources($rptAbsoluteUrl,$catalogItemDtSrcs)
}

Im nächsten Schritt werden die Dateien (*.rdl, *.rsd, *.rds) in die entsprechenden Bibliotheken auf der Zielseite deployed.

$ReportDataSourcePath = $ReportSourcePath + "DataSource"
$ReportDataSetSourcePath = $ReportSourcePath + "DataSet"

#Deploy Data sources 
[Object[]] $dataSourcesToPublish = [System.IO.Directory]::GetFiles($ReportDataSourcePath, "*.rds");
$dataSourcesToPublish | % { Install-DataSource $_ };
  
#Deploy Data Sets 
[Object[]] $dataSetsToPublish = [System.IO.Directory]::GetFiles($ReportDataSetSourcePath, "*.rsd");
$dataSetsToPublish | % { Install-DataSet $_ };
  
#Deploy Reports
[Object[]] $reportsToPublish = [System.IO.Directory]::GetFiles($ReportSourcePath, "*.rdl");
$reportsToPublish | % { Install-Reports $_ };

Abschließend müssen die Dateien, falls noch nicht geschehen, als MajorVersion deployed. Ansonsten können andere Benutzer nicht auf die Reportdateien zugreifen und diese erfolgreich ausführen.

#Publish a Major Version of the files stored in the Report Library
$spAssignment = Start-SPAssignment
$list = (Get-SPWeb -identity $newCollectionSite -AssignmentCollection $spAssignment).Lists["$TargetReportLibrary"]
foreach($item in $list.Items)
{
   $item.File.Publish("Copy of version: $VersionLabel")
   $itemName = $item.Name
   Write-Host "Successfully Published Major Version for file: $itemName"
}

Ausführen

Öffnen Sie nun auf dem Server das Microsoft SharePoint 2010 Management Shell und navigieren zu dem Verzeichnis, in welchem Sie das Powershell-Skript Deployment.ps1 gespeichert haben.

Eine Anleitung, um diese Powershell-Skript auch mit dem vom Windows Server mitgelieferten Powershell-Tool ausführen zu können, finden Sie im zweiten Teil dieser Blogserie.

Den Code, der in den vorherigen Artikeln dieser Blogserie erstellt wurde, können Sie auskommentieren (<# Code #>). So wird nicht alles, sondern nur der Teil für das Deployment der SSRS Reports ausgeführt.

Führen Sie das Skript Deployment.ps1 aus. Anschließend sollte folgendes Fenster erscheinen.

image

Fazit

Zusammenfassend kann man sagen, dass sich mit Hilfe von Powershell in SharePoint 2010 einfach administrative und konfigurierbare Schritte ausführen lassen. Dieses bedeutet, insbesondere für Administratoren und Entwickler, eine erhebliche Zeitersparnis.

Das Deployen von SSRS Reports und deren dazugehörigen Datenquelldateien mit Hilfe von Powershell ist dahingehend sehr hilfreich, da die Pfade der SharePoint-Umgebung angepasst werden. Sollte man die Reports nicht mit diesem Skript deployen, bleiben die Pfade erhalten, die auf der SharePoint-Umgebung vorhanden waren von der die Backup-Datei erstellt wurde.

 

Mit den Dateien Konfiguration.xml und Deployment.ps1, die im Laufe der Blogserie erstellt und erweitert wurden, kann man ohne großen Aufwand seine entwickelte SiteCollection auf eine andere SharePoint-Umgebung übertragen. Man spart sich einen erheblichen Zeitaufwand, da Dateien (z.B. BDCM-Dateien) nicht noch der Umgebung angepasst werden müssen. Des Weiteren erspart man sich die gesamte Erstellung und Einstellung in der Central Administration der jeweiligen SharePoint-Umgebung.

Ich hoffe, dass ich Ihnen mit dieser BlogSerie das Deployment einer SiteCollection von der einen SharePoint-Umgebung zu einer anderen erleichtern konnte und wünsche Ihnen viel Spaß beim Testen des Deployments.

Die Dateien Deployment.ps1 und Konfiguration.xml zu der Blogserie SharePoint 2010 Deployment können Sie sich hier herunterladen.

Hier finden Sie eine Übersicht aller Blogbeiträge zu dieser Blogserie.

Teil 1                    Teil 2                    Teil 3                    Teil 4                    Teil 5