Octopus.Script exported 2021-03-11 by twerthi belongs to ‘SQL Server’ category.
Uploads SSRS reports to an SSRS server from a package.
The following Datasource properties can be overidden: ConnectionString, Username, Password, and CredentialRetrieval (valid values are: Integrated, Prompt, Store, or None). To override the property, create a Variable using the syntax of DatasourceName.PropertyName. For example: MyDatasource.Username
To specify the Username and Password are Windows Credentials, create a variable called DatasourceName.WindowsCredentials and set the value to the string value ‘true’ (minus the quotes).
Parameters
When steps based on the template are included in a project’s deployment process, the parameters below can be set.
Package
SSRSPackage =
Select the package containing the SSRS reports.
Url of SSRS Server service
ReportServiceUrl =
The complete Url to the SSRS server. Example: http://198.239.216.46/ReportServer_LOCALDEV/reportservice2010.asmx?wsdl
Report Execution Url
ReportExecutionUrl =
The complete Url to the Report Execution service. Example: http://198.239.216.46/ReportServer_LOCALDEV/ReportExecution2005.asmx?wsdl
Report folder
ReportFolder =
Relative Url to the folder in which the reports will be deployed.
Report data source folder
ReportDatasourceFolder =
Relative Url where the data sources for the reports are located, starting with ’/‘
Overwrite datasource(s)
OverwriteDataSources = False
Tick if the existing report data source file needs to e replaced.
Backup Location
BackupLocation =
Directory path to take a backup of existing reports (.rdl) and data source (.rds) files.
DataSet folder
ReportDataSetFolder =
Relative Url where Shared Data Sets are stored
Report Parts Folder
ReportPartsFolder =
Relative folder where Report Parts are uploaded to.
Service Domain
ServiceUserDomain =
(Optional - leave blank to use Tentacle identity) Name of the domain for the user account to execute as
Service Username
ServiceUserName =
(Optional - leave blank to use Tentacle identity) Username of the user account to execute as
Service Password
ServicePassword =
(Optional - leave blank to use Tentacle identity) Password of the user account to execute as
Clear the Report Folder
ClearReportFolder = false
Optional - This will delete all items in the Report Folder before adding items.
Use package folder structure
UseArchiveStructure = false
Tick this box to create folders matching the package folder structure and upload items into their respective folders. Ticking this box ignores all other folder specifications except Root folder
Root folder
RootFolder =
Used only when ‘Use package folder structure’ is checked. This specifies the root folder on SSRS to start in. Value is relative so it begins with a /
Script body
Steps based on this template will execute the following PowerShell script.
$DeployedPath = $OctopusParameters["Octopus.Action.Package[SSRSPackage].ExtractedPath"]
$ReleaseNumber = $OctopusParameters["Octopus.Release.Number"]
$UseArchiveStructure = [Convert]::ToBoolean($OctopusParameters["UseArchiveStructure"])
#region Upload-Item
Function Upload-Item
{
# parameters
param ([string] $Item, [string]$ItemType, [string] $ItemFolder)
Write-Host "Loading data from $Item"
$ItemData = [System.IO.File]::ReadAllBytes($Item)
# Create local variables
$Warnings = $null
$ItemName = $Item.SubString($Item.LastIndexOf("\") + 1)
#$ItemName = $ItemName.SubString(0, $ItemName.IndexOf("."))
$ItemName = $ItemName.SubString(0, $ItemName.LastIndexOf("."))
# upload item
if ($IsReportService2005) {
if($ItemType -eq "Report")
{
[void]$ReportServerProxy.CreateReport($ItemName, $ItemFolder, $true, $ItemData, $null)
}
else
{
# error
Write-Error "$ItemType is not supported in ReportService2005"
}
}
elseif ($IsReportService2010) {
[void]$ReportServerProxy.CreateCatalogItem($ItemType, $ItemName, $ItemFolder, $true, $ItemData, $null, [ref] $Warnings);
}
else { Write-Warning 'Report Service Unknown in Upload-Item method. Use ReportService2005 or ReportService2010.' }
}
#endregion
#region Get-ItemDataSourceNames()
Function Get-ItemDataSourceNames
{
# Parameters
Param ($ItemFile, $DataSourceName)
# declare working variables
$DataSourceNames = @()
# load the xml
[xml]$Xml = Get-Content $ItemFile
# retrieve the datasource nodes
$DataSourceReferenceNodes = $Xml.GetElementsByTagName("DataSource")
# loop through returned results
foreach($Node in $DataSourceReferenceNodes)
{
# check to see if we're looking for a specific one
if($DataSourceName -ne $null)
{
# check to see if it's the current node
if($DataSourceName -eq $Node.Name)
{
# add
$DataSourceNames += $Node.DataSourceReference
}
}
else
{
# store the name
$DataSourceNames += $Node.DataSourceReference
}
}
# return the results
return ,$DataSourceNames # Apparently using the , in front of the variable is how you return explicit arrays in PowerShell ... could you be more obsure?
}
#endregion
#region Get-ItemDataSources()
Function Get-ItemDataSources
{
# Parameters
Param ($ItemFile)
# declare working variables
$DataSourceNames = @()
# load the xml
[xml]$Xml = Get-Content $ItemFile
# retrieve the datasource nodes
$DataSourceReferenceNodes = $Xml.GetElementsByTagName("DataSource")
# loop through returned results
foreach($Node in $DataSourceReferenceNodes)
{
# store the name
$DataSourceNames += $Node.Name
}
# return the results
return ,$DataSourceNames # Apparently using the , in front of the variable is how you return explicit arrays in PowerShell ... could you be more obsure?
}
#endregion
#region Get-ItemDataSourceReferenceNames
Function Get-ItemDataSourceReferenceNames
{
# Parameters
Param ($ItemFile)
# declare working variables
$DataSourceNames = @()
# load the xml
[xml]$Xml = Get-Content $ItemFile
# retrieve the datasource nodes
$DataSourceReferenceNodes = $Xml.GetElementsByTagName("DataSourceReference")
# loop through returned results
foreach($Node in $DataSourceReferenceNodes)
{
# get the data
$DataSourceNames += $Node.InnerText
}
# return the results
return ,$DataSourceNames # Apparently using the , in front of the variable is how you return explicit arrays in PowerShell ... could you be more obsure?
}
#endregion
#region Get-DataSetSharedReferenceName
Function Get-DataSetSharedReferenceName
{
# parameters
param($ReportFile, $DataSetName)
# load the xml
[xml]$ReportXml = Get-Content $ReportFile
# Get the DataSet nodes
$DataSetNode = $ReportXml.GetElementsByTagName("DataSet") | Where-Object {$_.Name -eq $DataSetName}
# return the name
$DataSetNode.SharedDataSet.SharedDataSetReference
}
#endregion
#region Item-Exists()
Function Item-Exists($ItemFolderPath, $ItemName)
{
# declare search condition
$SearchCondition = New-Object "$ReportServerProxyNamespace.SearchCondition";
# fill in properties
$SearchCondition.Condition = Get-SpecificEnumValue -EnumNamespace "$ReportServerProxyNamespace.ConditionEnum" -EnumName "Equals"
$SearchCondition.ConditionSpecified = $true
$SearchCondition.Name = "Name"
$SearchPath = $(if ([string]::IsNullOrWhitespace($ItemFolderPath)) { "/"} else { $ItemFolderPath } )
if ($IsReportService2005) {
$SearchCondition.Value = $ItemName
# search
$items = $ReportServerProxy.FindItems($SearchPath, (Get-SpecificEnumValue -EnumNamespace "$ReportServerProxyNamespace.BooleanOperatorEnum" -EnumName "And"), $SearchCondition)
}
elseif ($IsReportService2010) {
$SearchCondition.Values = @($ItemName)
# search
$items = $ReportServerProxy.FindItems($SearchPath, (Get-SpecificEnumValue -EnumNamespace "$ReportServerProxyNamespace.BooleanOperatorEnum" -EnumName "And"), $null, $SearchCondition)
}
else { Write-Warning 'Report Service Unknown in Item-Exists method. Use ReportService2005 or ReportService2010.' }
# check to see if anything was returned
if($items.Length -gt 0)
{
# loop through returned items
foreach($item in $items)
{
# check the path
if($item.Path -eq "$ItemFolderPath/$ItemName")
{
# return true
return $true
}
else
{
# warn
Write-Warning "Unexpected path for $($item.Name); path is $($item.Path) exepected $ItemFolderPath/$ItemName"
}
}
# items were found, but the path doesn't match
return $false
}
else
{
return $false
}
}
#endregion
Function Get-ItemPath
{
# Define parameters
param(
$ItemName,
$StartFolder,
$CompareFolderPath)
# declare search condition
$SearchCondition = New-Object "$ReportServerProxyNamespace.SearchCondition";
# fill in properties
$SearchCondition.Condition = Get-SpecificEnumValue -EnumNamespace "$ReportServerProxyNamespace.ConditionEnum" -EnumName "Equals"
$SearchCondition.ConditionSpecified = $true
$SearchCondition.Name = "Name"
if ($IsReportService2005) {
$SearchCondition.Value = $ItemName
# search
$items = $ReportServerProxy.FindItems($StartFolder, (Get-SpecificEnumValue -EnumNamespace "$ReportServerProxyNamespace.BooleanOperatorEnum" -EnumName "And"), $SearchCondition)
}
elseif ($IsReportService2010) {
$SearchCondition.Values = @($ItemName)
# search
$items = $ReportServerProxy.FindItems($StartFolder, (Get-SpecificEnumValue -EnumNamespace "$ReportServerProxyNamespace.BooleanOperatorEnum" -EnumName "And"), $null, $SearchCondition)
}
else { Write-Warning 'Report Service Unknown in Item-Exists method. Use ReportService2005 or ReportService2010.' }
# Check how many items were returned
if ($items.Length -eq 1)
{
return $items[0].Path
}
else
{
# Loop through returned items
foreach ($item in $items)
{
# compare folders
if ($CompareFolderPath -eq ($item.Path.SubString(0, $item.Path.LastIndexOf("/"))))
{
# Display message we're guessing
Write-Host "Multiple items were found with name $ItemName, assuming location is same folder as reference, $CompareFolderPath."
return $item.Path
}
}
# Display warning
Write-Warning "Multiple items were returned for $ItemName, unable to determine which one to return."
return [string]::Empty
}
}
#region Set-ItemDataSources()
Function Set-ItemDataSources
{
# parameters
Param($ItemFile, $ItemFolder)
# declare local variables
$ItemName = $ItemFile.SubString($ItemFile.LastIndexOf("\") + 1)
$ItemName = $ItemName.SubString(0, $ItemName.LastIndexOf("."))
$AllDataSourcesFound = $true
# get the datasources
$DataSources = $ReportServerProxy.GetItemDataSources([string]::Format("{0}/{1}", $ItemFolder, $ItemName))
#loop through retrieved datasources
foreach($DataSource in $DataSources)
{
# check to see if it's a dataset
if([System.IO.Path]::GetExtension($ItemFile).ToLower() -eq ".rsd")
{
# datasets can have one and only one datasource
# The method GetItemDataSources does not return the name of the datasource for datasets like it does for reports
# instead, it alaways returns DataSetDataSource. This made the call to Get-ItemDataSourceNames necessary,
# otherwise it would not link correctly
$DataSourceName = (Get-ItemDataSourceReferenceNames -ItemFile $ItemFile)[0]
}
else
{
# get the anme from teh source itself
$DataSourceName = (Get-ItemDataSourceNames -ItemFile $ItemFile -DataSourceName $DataSource.Name)[0]
}
if ([string]::IsNullOrWhiteSpace($DataSourceName))
{
Write-Host "Datasource $($DataSource.Name) is not a shared datasource, skipping."
$AllDataSourcesFound = $false
continue
}
# Check to see if datasourcename contains the folder -- this can happen if the report was created by Report Builder
if((![string]::IsNullOrEmpty($ReportDataSource)) -and ($DataSourceName.ToLower().Contains($ReportDatasourceFolder.ToLower())))
{
# Remove teh path from the item name
$DataSourceName = $DataSourceName.ToLower().Replace("$($ReportDatasourceFolder.ToLower())/","")
}
$DatasourcePath = ""
if ($UseArchiveStructure -eq $true)
{
$DatasourcePath = Get-ItemPath -ItemName $DataSourceName -StartFolder $RootFolder -CompareFolderPath $ItemFolder
$DatasourcePath = $DatasourcePath.SubString(0, $DatasourcePath.LastIndexOf("/"))
}
else
{
$DatasourcePath = $ReportDatasourceFolder
}
# check to make sure the datasource exists in the location specified
if((Item-Exists -ItemFolderPath $DatasourcePath -ItemName $DataSourceName) -eq $true)
{
# create datasource reference variable
$DataSourceReference = New-Object "$ReportServerProxyNamespace.DataSourceReference";
# assign
$DataSourceReference.Reference = "$DatasourcePath/" + $DataSourceName
$DataSource.Item = $DataSourceReference
}
else
{
# display warning
Write-Warning "Unable to find datasource $($DataSourceName) in $DatasourcePath"
# update to false
$AllDataSourcesFound = $false
}
}
# check to see if found all datasources
if($AllDataSourcesFound -eq $true)
{
Write-Host "Linking datasources to $ItemFolder/$ItemName"
# save the references
$ReportServerProxy.SetItemDataSources("$ItemFolder/$ItemName", $DataSources)
}
}
#endregion
#region Set-ReportDataSets()
Function Set-ReportDataSets
{
# parameters
param($ReportFile, $ReportFolderPath)
# declare local variables
$ReportName = $ReportFile.SubString($ReportFile.LastIndexOf("\") + 1)
$ReportName = $ReportName.SubString(0, $ReportName.LastIndexOf("."))
$AllDataSetsFound = $true
$DataSetFolder = ""
# get the datasources
$DataSets = $ReportServerProxy.GetItemReferences([string]::Format("{0}/{1}", $ReportFolderPath, $ReportName), "DataSet")
# loop through returned values
foreach($DataSet in $DataSets)
{
# get the name of the shared data set reference
$SharedDataSetReferenceName = Get-DataSetSharedReferenceName -ReportFile $ReportFile -DataSetName $DataSet.Name
# Check to see if the SharedDataSetReferenceName contains the folder path -- this can happen if the report was built using Report Builder
if((![string]::IsNullOrEmpty($ReportDataSetFolder)) -and ($SharedDataSetReferenceName.ToLower().Contains($ReportDataSetFolder.ToLower())))
{
# Remove the folder path from the name, it will cause issues when trying to set
$SharedDataSetReferenceName = $SharedDataSetReferenceName.ToLower().Replace("$($ReportDataSetFolder.ToLower())/", "")
}
# Check to see if we're using the archive folder structure
if ($UseArchiveStructure -eq $true)
{
# Set dataset folder
$DataSetFolder = Get-ItemPath -ItemName $SharedDataSetReferenceName -StartFolder $RootFolder -CompareFolderPath $ReportFolderPath
$DataSetFolder = $DataSetFolder.SubString(0, $DataSetFolder.LastIndexOf("/"))
}
else
{
$DataSetFolder = $ReportDataSetFolder
}
# check to make sure the datasource exists in the location specified
if((Item-Exists -ItemFolderPath $DataSetFolder -ItemName $SharedDataSetReferenceName) -eq $true)
{
# create datasource reference variable
$DataSetReference = New-Object "$ReportServerProxyNamespace.ItemReference";
# assign
$DataSetReference.Reference = "$DataSetFolder/" + $SharedDataSetReferenceName
$DataSetReference.Name = $DataSet.Name
# log
Write-Host "Linking Shared Data Set $($DataSet.Name) to $ReportName"
# update reference
$ReportServerProxy.SetItemReferences("$ReportFolderPath/$ReportName", @($DataSetReference))
}
else
{
# get the datasource name to include in warning message -- I know there must be a way to use the property in a string literal, but I wasn't able to figure it out while trying
# to solve a reported bug so I took the easy way.
$DataSetName = $DataSet.Name
# display warning
Write-Warning "Unable to find dataset $DataSetName in $ReportDataSetFolder"
# update to false
$AllDataSetsFound = $false
}
}
# check to see if all datsets were found
if($AllDataSetsFound -eq $False)
{
Write-Warning "Not all datasets found"
# save the references
$ReportServerProxy.SetItemReferences("$ReportFolder/$ReportName", @($DataSets))
}
}
#endregion
#region Get-ObjectNamespace()
Function Get-ObjectNamespace($Object)
{
# return the value
($Object).GetType().ToString().SubString(0, ($Object).GetType().ToString().LastIndexOf("."))
}
#endregion
#region Get-SpecificEnumValue()
Function Get-SpecificEnumValue($EnumNamespace, $EnumName)
{
# get the enum values
$EnumValues = [Enum]::GetValues($EnumNamespace)
# Loop through to find the specific value
foreach($EnumValue in $EnumValues)
{
# check current
if($EnumValue -eq $EnumName)
{
# return it
return $EnumValue
}
}
# nothing was found
return $null
}
#endregion
#region Update-ReportParamters()
Function Update-ReportParameters($ReportFile, $ReportFolderPath)
{
# declare local variables
$ReportParameters = @();
# necessary so that when attempting to use the report execution service, it doesn't puke on you when it can't find the data source
$ReportData = (Remove-SharedReferences -ReportFile $ReportFile)
# get just the report name
$ReportName = $ReportFile.SubString($ReportFile.LastIndexOf("\") + 1)
$ReportName = $ReportName.SubString(0, $ReportName.LastIndexOf("."))
# create warnings object
$ReportExecutionWarnings = $null
# set the report full path
$ReportPath = "$ReportFolderPath/$ReportName"
# load the report definition
$ExecutionInfo = $ReportExecutionProxy.LoadReportDefinition($ReportData, [ref] $ReportExecutionWarnings);
# loop through the report execution parameters
foreach($Parameter in $ExecutionInfo.Parameters)
{
# create new item parameter object
$ItemParameter = New-Object "$ReportServerProxyNamespace.ItemParameter";
# fill in the properties except valid values, that one needs special processing
Copy-ObjectProperties -SourceObject $Parameter -TargetObject $ItemParameter;
# fill in the valid values
$ItemParameter.ValidValues = Convert-ValidValues -SourceValidValues $Parameter.ValidValues;
# exclude if it's query based
if($Parameter.DefaultValuesQueryBased -ne $true)
{
# add to list
$ReportParameters += $ItemParameter;
}
}
# force the parameters to update
Write-Host "Updating report parameters for $ReportFolderPath/$ReportName"
if ($IsReportService2005) {
$ReportServerProxy.SetReportParameters("$ReportFolderPath/$ReportName", $ReportParameters);
}
elseif ($IsReportService2010) {
$ReportServerProxy.SetItemParameters("$ReportFolderPath/$ReportName", $ReportParameters);
}
else { Write-Warning 'Report Service Unknown in Update-ReportParameters method. Use ReportService2005 or ReportService2010.' }
}
#endregion
#region Remove-ShareReferences()
Function Remove-SharedReferences($ReportFile)
{
######################################################################################################
#You'll notice that I've used the keyword of [void] in front of some of these method calls, this is so
#that the operation isn't captured as output of the function
######################################################################################################
# read xml
[xml]$ReportXml = Get-Content $ReportFile -Encoding UTF8;
# create new memory stream object
$MemoryStream = New-Object System.IO.MemoryStream
try
{
# declare array of nodes to remove
$NodesToRemove = @();
# get datasource names
$DataSourceNames = Get-ItemDataSources -ItemFile $ReportFile
# check to see if report has datasourcenames
if($DataSourceNames.Count -eq 0)
{
# Get reference to reportnode
$ReportNode = $ReportXml.FirstChild.NextSibling # Kind of a funky way of getting it, but the SelectSingleNode("//Report") wasn't working due to Namespaces in the node
# create new DataSources node
$DataSourcesNode = $ReportXml.CreateNode($ReportNode.NodeType, "DataSources", $null)
# create new datasource node
$DataSourceNode = $ReportXml.CreateNode($ReportNode.NodeType, "DataSource", $null)
# create new datasourcereference node
$DataSourceReferenceNode = $ReportXml.CreateNode($ReportNode.NodeType, "DataSourceReference", $null)
# create new attribute
$DataSourceNameAttribute = $ReportXml.CreateAttribute("Name")
$DataSourceNameAttribute.Value = "DataSource1"
$dataSourceReferenceNode.InnerText = "DataSource1"
# add attribute to datasource node
[void]$DataSourceNode.Attributes.Append($DataSourceNameAttribute)
[void]$DataSourceNode.AppendChild($DataSourceReferenceNode)
# add nodes
[void]$ReportNode.AppendChild($DataSourcesNode)
[void]$DataSourcesNode.AppendChild($DataSourceNode)
# add fake datasource name to array
$DataSourceNames += "DataSource1"
}
# get all datasource nodes
$DatasourceNodes = $ReportXml.GetElementsByTagName("DataSourceReference");
# loop through returned nodes
foreach($DataSourceNode in $DatasourceNodes)
{
# create a new connection properties node
$ConnectionProperties = $ReportXml.CreateNode($DataSourceNode.NodeType, "ConnectionProperties", $null);
# create a new dataprovider node
$DataProvider = $ReportXml.CreateNode($DataSourceNode.NodeType, "DataProvider", $null);
$DataProvider.InnerText = "SQL";
# create new connection string node
$ConnectString = $ReportXml.CreateNode($DataSourceNode.NodeType, "ConnectString", $null);
$ConnectString.InnerText = "Data Source=Server Name Here;Initial Catalog=database name here";
# add new node to parent node
[void] $DataSourceNode.ParentNode.AppendChild($ConnectionProperties);
# append childeren
[void] $ConnectionProperties.AppendChild($DataProvider);
[void] $ConnectionProperties.AppendChild($ConnectString);
# Add to remove list
$NodesToRemove += $DataSourceNode;
}
# get all shareddataset nodes
$SharedDataSetNodes = $ReportXml.GetElementsByTagName("SharedDataSet")
#loop through the returned nodes
foreach($SharedDataSetNode in $SharedDataSetNodes)
{
# create holder nodes so it won't error
$QueryNode = $ReportXml.CreateNode($SharedDataSetNode.NodeType, "Query", $null);
$DataSourceNameNode = $ReportXml.CreateNode($QueryNode.NodeType, "DataSourceName", $null);
$CommandTextNode = $ReportXml.CreateNode($QueryNode.NodeType, "CommandText", $null);
# add valid datasource name, just get the first in the list
$DataSourceNameNode.InnerText = $DataSourceNames[0]
# add node to parent
[void] $SharedDataSetNode.ParentNode.Appendchild($QueryNode)
# add datasourcename and commandtext to query node
[void]$QueryNode.AppendChild($DataSourceNameNode)
[void]$QueryNode.AppendChild($CommandTextNode)
# add node to removelist
$NodesToRemove += $SharedDataSetNode
}
# loop through nodes to remove
foreach($Node in $NodesToRemove)
{
# remove from parent
[void] $Node.ParentNode.RemoveChild($Node);
}
$ReportXml.InnerXml = $ReportXml.InnerXml.Replace("xmlns=`"`"", "")
# save altered xml to memory stream
$ReportXml.Save($MemoryStream);
# return the altered xml as byte array
return $MemoryStream.ToArray();
}
finally
{
# close and dispose
$MemoryStream.Close();
$MemoryStream.Dispose();
}
}
#endregion
#region Copy-ObjectProperties()
Function Copy-ObjectProperties($SourceObject, $TargetObject)
{
# Get source object property array
$SourcePropertyCollection = $SourceObject.GetType().GetProperties();
# get the destination
$TargetPropertyCollection = $TargetObject.GetType().GetProperties();
# loop through source property collection
for($i = 0; $i -lt $SourcePropertyCollection.Length; $i++)
{
# get the target property
$TargetProperty = $TargetPropertyCollection | Where {$_.Name -eq $SourcePropertyCollection[$i].Name}
# check to see if it's null
if($TargetProperty -ne $null)
{
# check to see if it's the valid values property
if($TargetProperty.Name -ne "ValidValues")
{
# set the value
$TargetProperty.SetValue($TargetObject, $SourcePropertyCollection[$i].GetValue($SourceObject));
}
}
}
}
#endregion
#region ConvertValidValues()
Function Convert-ValidValues($SourceValidValues)
{
# declare local values
$TargetValidValues = @();
# loop through source values
foreach($SourceValidValue in $SourceValidValues)
{
# create target valid value object
$TargetValidValue = New-Object "$ReportServerProxyNamespace.ValidValue";
# copy properties
Copy-ObjectProperties -SourceObject $SourceValidValue -TargetObject $TargetValidValue
# add to list
$TargetValidValues += $TargetValidValue
}
# return the values
return ,$TargetValidValues
}
#endregion
#region Backup-ExistingItem()
Function Backup-ExistingItem
{
# parameters
Param($ItemFile, $ItemFolder)
# declare local variables
$ItemName = $ItemFile.SubString($ItemFile.LastIndexOf("\") + 1)
$ItemName = $ItemName.SubString(0, $ItemName.LastIndexOf("."))
# check to see if the item exists
if((Item-Exists -ItemFolderPath $ItemFolder -ItemName $ItemName) -eq $true)
{
# get file extension
$FileExtension = [System.IO.Path]::GetExtension($ItemFile)
# check backuplocation
if($BackupLocation.EndsWith("\") -ne $true)
{
# append ending slash
$BackupLocation = $BackupLocation + "\"
}
# add the release number to the backup location
$BackupLocation = $BackupLocation + $ReleaseNumber + "\"
# ensure the backup location actually exists
if((Test-Path $BackupLocation) -ne $true)
{
# create it
New-Item -ItemType Directory -Path $BackupLocation
}
# download the item
$Item = $ReportServerProxy.GetItemDefinition("$ItemFolder/$ItemName")
# form the backup path
$BackupPath = "{0}{1}{2}" -f $BackupLocation, $ItemName, $FileExtension;
# write to disk
[System.IO.File]::WriteAllBytes("$BackupPath", $Item);
# write to screen
Write-Host "Backed up $ItemFolder/$ItemName to $BackupPath";
}
}
#endregion
#region Normalize-SSRSFolder()
function Normalize-SSRSFolder ([string]$Folder) {
if (-not $Folder.StartsWith('/')) {
$Folder = '/' + $Folder
}
return $Folder
}
#endregion
#region New-SSRSFolder()
function New-SSRSFolder ([string] $Name) {
Write-Verbose "New-SSRSFolder -Name $Name"
$Name = Normalize-SSRSFolder -Folder $Name
if ($ReportServerProxy.GetItemType($Name) -ne 'Folder') {
$Parts = $Name -split '/'
$Leaf = $Parts[-1]
$Parent = $Parts[0..($Parts.Length-2)] -join '/'
if ($Parent) {
New-SSRSFolder -Name $Parent
} else {
$Parent = '/'
}
$ReportServerProxy.CreateFolder($Leaf, $Parent, $null)
}
}
#endregion
#region Clear-SSRSFolder()
function Clear-SSRSFolder ([string] $Name) {
Write-Verbose "Clear-SSRSFolder -Name $Name"
$Name = Normalize-SSRSFolder -Folder $Name
if ($ReportServerProxy.GetItemType($Name) -eq 'Folder' -and $ClearReportFolder) {
Write-Host ("Clearing the {0} folder" -f $Name)
$ReportServerProxy.ListChildren($Name, $false) | ForEach-Object {
Write-Verbose "Deleting item: $($_.Path)"
$ReportServerProxy.DeleteItem($_.Path)
}
}
}
#endregion
#region New-SSRSDataSource()
function New-SSRSDataSource ([string]$RdsPath, [string]$Folder, [bool]$OverwriteDataSources) {
Write-Verbose "New-SSRSDataSource -RdsPath $RdsPath -Folder $Folder"
$Folder = Normalize-SSRSFolder -Folder $Folder
[xml]$Rds = Get-Content -Path $RdsPath
$dsName = $Rds.RptDataSource.Name
$ConnProps = $Rds.RptDataSource.ConnectionProperties
$type = $ReportServerProxy.GetType().Namespace #Get proxy type
$DSDdatatype = ($type + '.DataSourceDefinition')
$Definition = new-object ($DSDdatatype)
if($Definition -eq $null){
Write-Error Failed to create data source definition object
}
$dsConnectionString = $($OctopusParameters["$($dsName).ConnectionString"])
$dsUsername = $($OctopusParameters["$($dsName).Username"])
$dsPassword = $($OctopusParameters["$($dsName).Password"])
$dsCredentialRetrieval = $($OctopusParameters["$($dsName).CredentialRetrieval"])
# replace the connection string variable that is configured in the octopus project
if ($dsConnectionString) {
$Definition.ConnectString = $dsConnectionString
} else {
$Definition.ConnectString = $ConnProps.ConnectString
}
$Definition.Extension = $ConnProps.Extension
# Check to see if the credential retrieval is overridden
if ($null -ne $dsCredentialRetrieval)
{
Write-Host "Forcing CredentialRetrieval property to: $dsCredentialRetrieval."
$Definition.CredentialRetrieval = $dsCredentialRetrieval
}
else
{
# Set the Credential Retrieval method
if ([Convert]::ToBoolean($ConnProps.IntegratedSecurity)) {
$Definition.CredentialRetrieval = 'Integrated'
}
elseif (![string]::IsNullOrWhitespace($dsUsername) -and ![string]::IsNullOrWhitespace($dsPassword))
{
$Definition.CredentialRetrieval = 'Store'
}
}
if ($Definition.CredentialRetrieval -eq 'Store')
{
Write-Host "$($dsName).Username = '$dsUsername'"
Write-Host "$($dsName).Password = '$dsPassword'"
$Definition.UserName = $dsUsername;
$Definition.Password = $dsPassword;
}
# Check to see if this is supposed to be an Windows Authentication stored account
if ($OctopusParameters["$($dsName).WindowsCredentials"] -eq "true")
{
# Set the definition to Windows Credentials
$Definition.WindowsCredentials = $true
}
$DataSource = New-Object -TypeName PSObject -Property @{
Name = $Rds.RptDataSource.Name
Path = $Folder + '/' + $Rds.RptDataSource.Name
}
if ($OverwriteDataSources -or $ReportServerProxy.GetItemType($DataSource.Path) -eq 'Unknown') {
Write-Host "Overwriting datasource $($DataSource.Name)"
$ReportServerProxy.CreateDataSource($DataSource.Name, $Folder, $OverwriteDataSources, $Definition, $null)
}
return $DataSource
}
#endregion
#region Main
try
{
# declare array for reports
$ReportFiles = @()
$ReportDataSourceFiles = @()
$ReportDataSetFiles = @()
$ReportPartFiles = @()
$IsReportService2005 = $false
$IsReportService2010 = $false
if ($ReportServiceUrl.ToLower().Contains('reportservice2005.asmx')) {
$IsReportService2005 = $true
Write-Host "2005 Report Service found."
}
elseif ($ReportServiceUrl.ToLower().Contains('reportservice2010.asmx')) {
$IsReportService2010 = $true
Write-Host "2010 Report Service found."
}
Write-Host "Deploy Path: $DeployedPath"
# get all report files for deployment
Write-Host "Getting all .rdl files"
Get-ChildItem $DeployedPath -Recurse -Filter "*.rdl" | ForEach-Object { If(($ReportFiles -contains $_.FullName) -eq $false) {$ReportFiles += $_.FullName}}
Write-Host "# of rdl files found: $($ReportFiles.Count)"
# get all report datasource files for deployment
Write-Host "Getting all .rds files"
Get-ChildItem $DeployedPath -Recurse -Filter "*.rds" | ForEach-Object { If(($ReportDataSourceFiles -contains $_.FullName) -eq $false) {$ReportDataSourceFiles += $_.FullName}}
Write-Host "# of rds files found: $($ReportDataSourceFiles.Count)"
# get all report datset files for deployment
Write-Host "Getting all .rsd files"
Get-ChildItem $DeployedPath -Recurse -Filter "*.rsd" | ForEach-Object { If(($ReportDataSetFiles -contains $_.FullName) -eq $false) {$ReportDataSetFiles += $_.FullName}}
Write-Host "# of rsd files found: $($ReportDataSetFiles.Count)"
# get all report part files for deployment
Write-Host "Getting all .rsc files"
Get-ChildItem $DeployedPath -Recurse -Filter "*.rsc" | ForEach-Object { If(($ReportPartFiles -contains $_.FullName) -eq $false) {$ReportPartFiles += $_.FullName}}
Write-Host "# of rsc files found: $($ReportPartFiles.Count)"
# set the report proxies
Write-Host "Creating SSRS Web Service proxies"
# check to see if credentials were supplied for the services
if(([string]::IsNullOrEmpty($ServiceUserDomain) -ne $true) -and ([string]::IsNullOrEmpty($ServiceUserName) -ne $true) -and ([string]::IsNullOrEmpty($ServicePassword) -ne $true))
{
# secure the password
$secpasswd = ConvertTo-SecureString "$ServicePassword" -AsPlainText -Force
# create credential object
$ServiceCredential = New-Object System.Management.Automation.PSCredential ("$ServiceUserDomain\$ServiceUserName", $secpasswd)
# create proxies
$ReportServerProxy = New-WebServiceProxy -Uri $ReportServiceUrl -Credential $ServiceCredential
$ReportExecutionProxy = New-WebServiceProxy -Uri $ReportExecutionUrl -Credential $ServiceCredential
}
else
{
# create proxies using current identity
$ReportServerProxy = New-WebServiceProxy -Uri $ReportServiceUrl -UseDefaultCredential
$ReportExecutionProxy = New-WebServiceProxy -Uri $ReportExecutionUrl -UseDefaultCredential
}
#Create folder information for DataSource and Report
if ($UseArchiveStructure -eq $false)
{
New-SSRSFolder -Name $ReportFolder
New-SSRSFolder -Name $ReportDatasourceFolder
New-SSRSFolder -Name $ReportDataSetFolder
New-SSRSFolder -Name $ReportPartsFolder
}
else
{
New-SSRSFolder -Name $RootFolder
}
#Clear destination folder if specified
if([System.Convert]::ToBoolean("$ClearReportFolder")) {
Clear-SSRSFolder -Name $ReportFolder
}
#Create DataSource
foreach($RDSFile in $ReportDataSourceFiles) {
Write-Host "New-SSRSDataSource $RdsFile"
$DatasourceFolder = ""
if ($UseArchiveStructure -eq $true)
{
# Adjust report folder to archive path
$DatasourceFolder = $(if ($RootFolder -eq "/") { [string]::Empty} else { $RootFolder } ) + $RDSFile.Replace($DeployedPath, '').Replace('\', '/').Replace((Split-Path $RDSFile -Leaf), '')
# Remove final slash
$DatasourceFolder = $DatasourceFolder.Substring(0, $DatasourceFolder.LastIndexOf('/'))
# Check if folder exists
New-SSRSFolder -Name $DatasourceFolder
}
else
{
$DatasourceFolder = $ReportDatasourceFolder
}
$DataSource = New-SSRSDataSource -RdsPath $RdsFile -Folder $DatasourceFolder -Overwrite ([System.Convert]::ToBoolean("$OverwriteDataSources"))
}
# get the service proxy namespaces - this is necessary because of a bug documented here http://stackoverflow.com/questions/7921040/error-calling-reportingservice2005-finditems-specifically-concerning-the-bool and http://www.vistax64.com/powershell/273120-bug-when-using-namespace-parameter-new-webserviceproxy.html
$ReportServerProxyNamespace = Get-ObjectNamespace -Object $ReportServerProxy
$ReportExecutionProxyNamespace = Get-ObjectNamespace -Object $ReportExecutionProxy
# Create dat sets
foreach($DataSet in $ReportDataSetFiles)
{
$DataSetPath = ""
# Check to see if it's set to follow archive structure
if ($UseArchiveStructure -eq $true)
{
# Adjust report folder to archive path
$DataSetPath = $(if ($RootFolder -eq "/") { [string]::Empty} else { $RootFolder } ) + $DataSet.Replace($DeployedPath, '').Replace('\', '/').Replace((Split-Path $DataSet -Leaf), '')
# Remove final slash
$DataSetPath = $DataSetPath.Substring(0, $DataSetPath.LastIndexOf('/'))
# Check if folder exists
New-SSRSFolder -Name $DataSetPath
}
else
{
$DataSetPath = $ReportDataSetFolder
}
# check to see if we need to back up
if($BackupLocation -ne $null -and $BackupLocation -ne "")
{
# backup the item
Backup-ExistingItem -ItemFile $DataSet -ItemFolder $DataSetPath
}
# upload the dataset
Upload-Item -Item $DataSet -ItemType "DataSet" -ItemFolder $DataSetPath
# update the dataset datasource
Set-ItemDataSources -ItemFile $DataSet -ItemFolder $DataSetPath
}
# get the proxy auto generated name spaces
# loop through array
foreach($ReportFile in $ReportFiles)
{
$ReportPath = ""
# Check to see if it's set to follow archive structure
if ($UseArchiveStructure -eq $true)
{
# Adjust report folder to archive path
$ReportPath = $(if ($RootFolder -eq "/") { [string]::Empty} else { $RootFolder } ) + $ReportFile.Replace($DeployedPath, '').Replace('\', '/').Replace((Split-Path $ReportFile -Leaf), '')
# Remove final slash
$ReportPath = $ReportPath.Substring(0, $ReportPath.LastIndexOf('/'))
# Check if folder exists
New-SSRSFolder -Name $ReportPath
}
else
{
$ReportPath = $ReportFolder
}
# check to see if we need to back up
if($BackupLocation -ne $null -and $BackupLocation -ne "")
{
# backup the item
Backup-ExistingItem -ItemFile $ReportFile -ItemFolder $ReportPath
}
# upload report
Upload-Item -Item $ReportFile -ItemType "Report" -ItemFolder $ReportPath
# extract datasources
#Write-Host "Extracting datasource names for $ReportFile"
#$ReportDataSourceNames = Get-ReportDataSourceNames $ReportFile
# set the datasources
Set-ItemDataSources -ItemFile $ReportFile -ItemFolder $ReportPath
# set the datasets
Set-ReportDataSets -ReportFile $ReportFile -ReportFolderPath $ReportPath
# update the report parameters
Update-ReportParameters -ReportFile $ReportFile -ReportFolderPath $ReportPath
}
# loop through rsc files
foreach($ReportPartFile in $ReportPartFiles)
{
# check to see if we need to back up
if($BackupLocation -ne $null -and $BackupLocation -ne "")
{
# backup the item
Backup-ExistingItem -ItemFile $ReportPartFile -ItemFolder $ReportPartsFolder
}
# upload item
Upload-Item -Item $ReportPartFile -ItemType "Component" -ItemFolder $ReportPartsFolder
}
}
finally
{
# check to see if the proxies are null
if($ReportServerProxy -ne $null)
{
# dispose
$ReportServerProxy.Dispose();
}
if($ReportExecutionProxy -ne $null)
{
# dispose
$ReportExecutionProxy.Dispose();
}
}
#endregion
Provided under the Apache License version 2.0.
To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.
{
"Id": "2c118ec9-4c3e-45a4-85b7-9f3c8ae99ca9",
"Name": "Deploy SSRS Reports from a package parameter",
"Description": "Uploads SSRS reports to an SSRS server from a package.\n\nThe following Datasource properties can be overidden: ConnectionString, Username, Password, and CredentialRetrieval (valid values are: Integrated, Prompt, Store, or None). To override the property, create a Variable using the syntax of DatasourceName.PropertyName. For example: MyDatasource.Username \n\nTo specify the Username and Password are Windows Credentials, create a variable called DatasourceName.WindowsCredentials and set the value to the string value 'true' (minus the quotes).",
"Version": 5,
"ExportedAt": "2021-03-11T19:29:06.452Z",
"ActionType": "Octopus.Script",
"Author": "twerthi",
"Packages": [
{
"Name": "SSRSPackage",
"Id": "5f4c7059-081e-44d7-bfea-6b9a90c4e77c",
"PackageId": null,
"FeedId": null,
"AcquisitionLocation": "Server",
"Properties": {
"Extract": "True",
"SelectionMode": "deferred",
"PackageParameterName": "SSRSPackage"
}
}
],
"Parameters": [
{
"Id": "e339fdfe-376f-4d6b-9226-9d5fc07c0a62",
"Name": "SSRSPackage",
"Label": "Package",
"HelpText": "Select the package containing the SSRS reports.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Package"
}
},
{
"Id": "",
"Name": "ReportServiceUrl",
"Label": "Url of SSRS Server service",
"HelpText": "The complete Url to the SSRS server.\nExample: http://198.239.216.46/ReportServer_LOCALDEV/reportservice2010.asmx?wsdl",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ReportExecutionUrl",
"Label": "Report Execution Url",
"HelpText": "The complete Url to the Report Execution service.\nExample: http://198.239.216.46/ReportServer_LOCALDEV/ReportExecution2005.asmx?wsdl",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ReportFolder",
"Label": "Report folder",
"HelpText": "Relative Url to the folder in which the reports will be deployed.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ReportDatasourceFolder",
"Label": "Report data source folder",
"HelpText": "Relative Url where the data sources for the reports are located, starting with '/'",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "OverwriteDataSources",
"Label": "Overwrite datasource(s)",
"HelpText": "Tick if the existing report data source file needs to e replaced.",
"DefaultValue": "False",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "",
"Name": "BackupLocation",
"Label": "Backup Location",
"HelpText": "Directory path to take a backup of existing reports (.rdl) and data source (.rds) files.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ReportDataSetFolder",
"Label": "DataSet folder",
"HelpText": "Relative Url where Shared Data Sets are stored",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ReportPartsFolder",
"Label": "Report Parts Folder",
"HelpText": "Relative folder where Report Parts are uploaded to.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ServiceUserDomain",
"Label": "Service Domain",
"HelpText": "(Optional - leave blank to use Tentacle identity) Name of the domain for the user account to execute as",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ServiceUserName",
"Label": "Service Username",
"HelpText": "(Optional - leave blank to use Tentacle identity) Username of the user account to execute as",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "",
"Name": "ServicePassword",
"Label": "Service Password",
"HelpText": "(Optional - leave blank to use Tentacle identity) Password of the user account to execute as",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "",
"Name": "ClearReportFolder",
"Label": "Clear the Report Folder",
"HelpText": "Optional - This will delete all items in the Report Folder before adding items.",
"DefaultValue": "false",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "",
"Name": "UseArchiveStructure",
"Label": "Use package folder structure",
"HelpText": "Tick this box to create folders matching the package folder structure and upload items into their respective folders. Ticking this box ignores all other folder specifications except Root folder",
"DefaultValue": "false",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "",
"Name": "RootFolder",
"Label": "Root folder",
"HelpText": "Used only when 'Use package folder structure' is checked. This specifies the root folder on SSRS to start in. Value is relative so it begins with a /",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
}
],
"Properties": {
"Octopus.Action.Script.ScriptBody": "$DeployedPath = $OctopusParameters[\"Octopus.Action.Package[SSRSPackage].ExtractedPath\"]\n$ReleaseNumber = $OctopusParameters[\"Octopus.Release.Number\"]\n$UseArchiveStructure = [Convert]::ToBoolean($OctopusParameters[\"UseArchiveStructure\"])\n\n#region Upload-Item\nFunction Upload-Item\n{\n # parameters\n param ([string] $Item, [string]$ItemType, [string] $ItemFolder)\n\n Write-Host \"Loading data from $Item\"\n $ItemData = [System.IO.File]::ReadAllBytes($Item)\n\n # Create local variables\n $Warnings = $null\n $ItemName = $Item.SubString($Item.LastIndexOf(\"\\\") + 1)\n #$ItemName = $ItemName.SubString(0, $ItemName.IndexOf(\".\"))\n $ItemName = $ItemName.SubString(0, $ItemName.LastIndexOf(\".\"))\n \n\t# upload item\n if ($IsReportService2005) {\n if($ItemType -eq \"Report\")\n {\n\t [void]$ReportServerProxy.CreateReport($ItemName, $ItemFolder, $true, $ItemData, $null)\n }\n else\n {\n # error\n Write-Error \"$ItemType is not supported in ReportService2005\"\n }\n\t}\n\telseif ($IsReportService2010) {\n\t\t[void]$ReportServerProxy.CreateCatalogItem($ItemType, $ItemName, $ItemFolder, $true, $ItemData, $null, [ref] $Warnings);\n\t}\n\telse { Write-Warning 'Report Service Unknown in Upload-Item method. Use ReportService2005 or ReportService2010.' }\n}\n#endregion\n\n#region Get-ItemDataSourceNames()\nFunction Get-ItemDataSourceNames\n{\n # Parameters\n Param ($ItemFile, $DataSourceName)\n\n # declare working variables\n $DataSourceNames = @()\n \n # load the xml\n [xml]$Xml = Get-Content $ItemFile\n\n # retrieve the datasource nodes\n $DataSourceReferenceNodes = $Xml.GetElementsByTagName(\"DataSource\")\n\n # loop through returned results\n foreach($Node in $DataSourceReferenceNodes)\n {\n # check to see if we're looking for a specific one\n if($DataSourceName -ne $null)\n {\n # check to see if it's the current node\n if($DataSourceName -eq $Node.Name)\n {\n # add\n $DataSourceNames += $Node.DataSourceReference\n }\n }\n else\n {\n # store the name\n $DataSourceNames += $Node.DataSourceReference\n }\n }\n\n # return the results\n return ,$DataSourceNames # Apparently using the , in front of the variable is how you return explicit arrays in PowerShell ... could you be more obsure?\n}\n#endregion\n\n#region Get-ItemDataSources()\nFunction Get-ItemDataSources\n{\n # Parameters\n Param ($ItemFile)\n\n # declare working variables\n $DataSourceNames = @()\n \n # load the xml\n [xml]$Xml = Get-Content $ItemFile\n\n # retrieve the datasource nodes\n $DataSourceReferenceNodes = $Xml.GetElementsByTagName(\"DataSource\")\n\n # loop through returned results\n foreach($Node in $DataSourceReferenceNodes)\n {\n # store the name\n $DataSourceNames += $Node.Name\n }\n\n # return the results\n return ,$DataSourceNames # Apparently using the , in front of the variable is how you return explicit arrays in PowerShell ... could you be more obsure?\n}\n#endregion\n\n#region Get-ItemDataSourceReferenceNames\nFunction Get-ItemDataSourceReferenceNames\n{\n # Parameters\n Param ($ItemFile)\n\n # declare working variables\n $DataSourceNames = @()\n \n # load the xml\n [xml]$Xml = Get-Content $ItemFile\n\n # retrieve the datasource nodes\n $DataSourceReferenceNodes = $Xml.GetElementsByTagName(\"DataSourceReference\")\n\n # loop through returned results\n foreach($Node in $DataSourceReferenceNodes)\n {\n # get the data\n $DataSourceNames += $Node.InnerText\n }\n\n # return the results\n return ,$DataSourceNames # Apparently using the , in front of the variable is how you return explicit arrays in PowerShell ... could you be more obsure?\n}\n#endregion\n\n#region Get-DataSetSharedReferenceName\nFunction Get-DataSetSharedReferenceName\n{\n # parameters\n param($ReportFile, $DataSetName)\n\n # load the xml\n [xml]$ReportXml = Get-Content $ReportFile\n\n # Get the DataSet nodes\n $DataSetNode = $ReportXml.GetElementsByTagName(\"DataSet\") | Where-Object {$_.Name -eq $DataSetName}\n\n # return the name\n $DataSetNode.SharedDataSet.SharedDataSetReference\n}\n#endregion\n\n#region Item-Exists()\nFunction Item-Exists($ItemFolderPath, $ItemName)\n{\n # declare search condition\n $SearchCondition = New-Object \"$ReportServerProxyNamespace.SearchCondition\";\n\n # fill in properties\n $SearchCondition.Condition = Get-SpecificEnumValue -EnumNamespace \"$ReportServerProxyNamespace.ConditionEnum\" -EnumName \"Equals\"\n $SearchCondition.ConditionSpecified = $true\n $SearchCondition.Name = \"Name\"\n $SearchPath = $(if ([string]::IsNullOrWhitespace($ItemFolderPath)) { \"/\"} else { $ItemFolderPath } )\n\n\tif ($IsReportService2005) {\n\t\t$SearchCondition.Value = $ItemName\n\t\t# search\n\t $items = $ReportServerProxy.FindItems($SearchPath, (Get-SpecificEnumValue -EnumNamespace \"$ReportServerProxyNamespace.BooleanOperatorEnum\" -EnumName \"And\"), $SearchCondition)\n\t}\n\telseif ($IsReportService2010) {\n\t\t$SearchCondition.Values = @($ItemName)\n\t\t# search\n\t $items = $ReportServerProxy.FindItems($SearchPath, (Get-SpecificEnumValue -EnumNamespace \"$ReportServerProxyNamespace.BooleanOperatorEnum\" -EnumName \"And\"), $null, $SearchCondition)\n\t}\n\telse { Write-Warning 'Report Service Unknown in Item-Exists method. Use ReportService2005 or ReportService2010.' } \n\n\n # check to see if anything was returned\n if($items.Length -gt 0)\n {\n # loop through returned items\n foreach($item in $items)\n {\n # check the path\n if($item.Path -eq \"$ItemFolderPath/$ItemName\")\n {\n # return true\n return $true\n }\n else\n {\n # warn\n Write-Warning \"Unexpected path for $($item.Name); path is $($item.Path) exepected $ItemFolderPath/$ItemName\"\n }\n }\n\n # items were found, but the path doesn't match\n \n return $false\n }\n else\n {\n return $false\n }\n}\n#endregion\n\nFunction Get-ItemPath\n{\n # Define parameters\n param(\n $ItemName,\n $StartFolder,\n $CompareFolderPath)\n\n # declare search condition\n $SearchCondition = New-Object \"$ReportServerProxyNamespace.SearchCondition\";\n\n # fill in properties\n $SearchCondition.Condition = Get-SpecificEnumValue -EnumNamespace \"$ReportServerProxyNamespace.ConditionEnum\" -EnumName \"Equals\"\n $SearchCondition.ConditionSpecified = $true\n $SearchCondition.Name = \"Name\"\n\n\tif ($IsReportService2005) {\n\t\t$SearchCondition.Value = $ItemName\n\t\t# search\n\t $items = $ReportServerProxy.FindItems($StartFolder, (Get-SpecificEnumValue -EnumNamespace \"$ReportServerProxyNamespace.BooleanOperatorEnum\" -EnumName \"And\"), $SearchCondition)\n\t}\n\telseif ($IsReportService2010) {\n\t\t$SearchCondition.Values = @($ItemName)\n\t\t# search\n\t $items = $ReportServerProxy.FindItems($StartFolder, (Get-SpecificEnumValue -EnumNamespace \"$ReportServerProxyNamespace.BooleanOperatorEnum\" -EnumName \"And\"), $null, $SearchCondition)\n\t}\n\telse { Write-Warning 'Report Service Unknown in Item-Exists method. Use ReportService2005 or ReportService2010.' } \n\n # Check how many items were returned\n if ($items.Length -eq 1)\n {\n return $items[0].Path\n }\n else\n {\n # Loop through returned items\n foreach ($item in $items)\n {\n # compare folders\n if ($CompareFolderPath -eq ($item.Path.SubString(0, $item.Path.LastIndexOf(\"/\"))))\n {\n # Display message we're guessing\n Write-Host \"Multiple items were found with name $ItemName, assuming location is same folder as reference, $CompareFolderPath.\"\n return $item.Path\n }\n }\n\n # Display warning\n Write-Warning \"Multiple items were returned for $ItemName, unable to determine which one to return.\"\n return [string]::Empty\n } \n}\n\n#region Set-ItemDataSources()\nFunction Set-ItemDataSources\n{\n # parameters\n Param($ItemFile, $ItemFolder)\n\n # declare local variables\n $ItemName = $ItemFile.SubString($ItemFile.LastIndexOf(\"\\\") + 1)\n $ItemName = $ItemName.SubString(0, $ItemName.LastIndexOf(\".\"))\n $AllDataSourcesFound = $true\n \n # get the datasources\n $DataSources = $ReportServerProxy.GetItemDataSources([string]::Format(\"{0}/{1}\", $ItemFolder, $ItemName))\n\n #loop through retrieved datasources\n foreach($DataSource in $DataSources)\n {\n # check to see if it's a dataset\n if([System.IO.Path]::GetExtension($ItemFile).ToLower() -eq \".rsd\")\n {\n # datasets can have one and only one datasource\n # The method GetItemDataSources does not return the name of the datasource for datasets like it does for reports\n # instead, it alaways returns DataSetDataSource. This made the call to Get-ItemDataSourceNames necessary,\n # otherwise it would not link correctly\n $DataSourceName = (Get-ItemDataSourceReferenceNames -ItemFile $ItemFile)[0]\n }\n else\n {\n # get the anme from teh source itself\n $DataSourceName = (Get-ItemDataSourceNames -ItemFile $ItemFile -DataSourceName $DataSource.Name)[0]\n } \n \n if ([string]::IsNullOrWhiteSpace($DataSourceName))\n {\n Write-Host \"Datasource $($DataSource.Name) is not a shared datasource, skipping.\"\n $AllDataSourcesFound = $false\n continue\n }\n \n # Check to see if datasourcename contains the folder -- this can happen if the report was created by Report Builder\n if((![string]::IsNullOrEmpty($ReportDataSource)) -and ($DataSourceName.ToLower().Contains($ReportDatasourceFolder.ToLower())))\n {\n # Remove teh path from the item name\n $DataSourceName = $DataSourceName.ToLower().Replace(\"$($ReportDatasourceFolder.ToLower())/\",\"\")\n }\n\n $DatasourcePath = \"\"\n\n if ($UseArchiveStructure -eq $true)\n {\n $DatasourcePath = Get-ItemPath -ItemName $DataSourceName -StartFolder $RootFolder -CompareFolderPath $ItemFolder\n $DatasourcePath = $DatasourcePath.SubString(0, $DatasourcePath.LastIndexOf(\"/\"))\n }\n else\n {\n $DatasourcePath = $ReportDatasourceFolder\n }\n\n # check to make sure the datasource exists in the location specified\n if((Item-Exists -ItemFolderPath $DatasourcePath -ItemName $DataSourceName) -eq $true)\n {\n # create datasource reference variable\n $DataSourceReference = New-Object \"$ReportServerProxyNamespace.DataSourceReference\";\n\n # assign\n $DataSourceReference.Reference = \"$DatasourcePath/\" + $DataSourceName\n $DataSource.Item = $DataSourceReference \n }\n else\n {\n # display warning\n Write-Warning \"Unable to find datasource $($DataSourceName) in $DatasourcePath\"\n\n # update to false\n $AllDataSourcesFound = $false\n } \n }\n\n # check to see if found all datasources\n if($AllDataSourcesFound -eq $true)\n {\n Write-Host \"Linking datasources to $ItemFolder/$ItemName\"\n \n # save the references\n $ReportServerProxy.SetItemDataSources(\"$ItemFolder/$ItemName\", $DataSources)\n }\n}\n#endregion\n\n#region Set-ReportDataSets()\nFunction Set-ReportDataSets\n{\n # parameters\n param($ReportFile, $ReportFolderPath)\n\n # declare local variables\n $ReportName = $ReportFile.SubString($ReportFile.LastIndexOf(\"\\\") + 1)\n $ReportName = $ReportName.SubString(0, $ReportName.LastIndexOf(\".\"))\n $AllDataSetsFound = $true\n $DataSetFolder = \"\"\n\n # get the datasources\n $DataSets = $ReportServerProxy.GetItemReferences([string]::Format(\"{0}/{1}\", $ReportFolderPath, $ReportName), \"DataSet\")\n\n # loop through returned values\n foreach($DataSet in $DataSets)\n {\n # get the name of the shared data set reference\n $SharedDataSetReferenceName = Get-DataSetSharedReferenceName -ReportFile $ReportFile -DataSetName $DataSet.Name\n\n # Check to see if the SharedDataSetReferenceName contains the folder path -- this can happen if the report was built using Report Builder\n if((![string]::IsNullOrEmpty($ReportDataSetFolder)) -and ($SharedDataSetReferenceName.ToLower().Contains($ReportDataSetFolder.ToLower())))\n {\n # Remove the folder path from the name, it will cause issues when trying to set\n $SharedDataSetReferenceName = $SharedDataSetReferenceName.ToLower().Replace(\"$($ReportDataSetFolder.ToLower())/\", \"\")\n }\n \n # Check to see if we're using the archive folder structure\n if ($UseArchiveStructure -eq $true)\n {\n # Set dataset folder\n $DataSetFolder = Get-ItemPath -ItemName $SharedDataSetReferenceName -StartFolder $RootFolder -CompareFolderPath $ReportFolderPath\n $DataSetFolder = $DataSetFolder.SubString(0, $DataSetFolder.LastIndexOf(\"/\"))\n }\n else\n {\n $DataSetFolder = $ReportDataSetFolder\n }\n\n # check to make sure the datasource exists in the location specified\n if((Item-Exists -ItemFolderPath $DataSetFolder -ItemName $SharedDataSetReferenceName) -eq $true)\n {\n # create datasource reference variable\n $DataSetReference = New-Object \"$ReportServerProxyNamespace.ItemReference\";\n\n # assign\n $DataSetReference.Reference = \"$DataSetFolder/\" + $SharedDataSetReferenceName\n $DataSetReference.Name = $DataSet.Name\n\n # log\n Write-Host \"Linking Shared Data Set $($DataSet.Name) to $ReportName\"\n \n # update reference\n $ReportServerProxy.SetItemReferences(\"$ReportFolderPath/$ReportName\", @($DataSetReference))\n }\n else\n {\n # get the datasource name to include in warning message -- I know there must be a way to use the property in a string literal, but I wasn't able to figure it out while trying\n # to solve a reported bug so I took the easy way.\n $DataSetName = $DataSet.Name\n \n # display warning\n Write-Warning \"Unable to find dataset $DataSetName in $ReportDataSetFolder\"\n\n # update to false\n $AllDataSetsFound = $false\n } \n }\n\n # check to see if all datsets were found\n if($AllDataSetsFound -eq $False)\n {\n Write-Warning \"Not all datasets found\"\n\n # save the references\n $ReportServerProxy.SetItemReferences(\"$ReportFolder/$ReportName\", @($DataSets))\n }\n}\n\n#endregion\n\n#region Get-ObjectNamespace()\nFunction Get-ObjectNamespace($Object)\n{\n # return the value\n ($Object).GetType().ToString().SubString(0, ($Object).GetType().ToString().LastIndexOf(\".\"))\n}\n#endregion\n\n#region Get-SpecificEnumValue()\nFunction Get-SpecificEnumValue($EnumNamespace, $EnumName)\n{\n # get the enum values\n $EnumValues = [Enum]::GetValues($EnumNamespace)\n\n # Loop through to find the specific value\n foreach($EnumValue in $EnumValues)\n {\n # check current\n if($EnumValue -eq $EnumName)\n {\n # return it\n return $EnumValue\n }\n }\n\n # nothing was found\n return $null\n}\n#endregion\n\n#region Update-ReportParamters()\nFunction Update-ReportParameters($ReportFile, $ReportFolderPath)\n{\n # declare local variables\n $ReportParameters = @();\n \n # necessary so that when attempting to use the report execution service, it doesn't puke on you when it can't find the data source\n $ReportData = (Remove-SharedReferences -ReportFile $ReportFile)\n\n # get just the report name\n $ReportName = $ReportFile.SubString($ReportFile.LastIndexOf(\"\\\") + 1)\n $ReportName = $ReportName.SubString(0, $ReportName.LastIndexOf(\".\"))\n \n # create warnings object\n $ReportExecutionWarnings = $null\n\n # set the report full path\n $ReportPath = \"$ReportFolderPath/$ReportName\" \n\n # load the report definition\n $ExecutionInfo = $ReportExecutionProxy.LoadReportDefinition($ReportData, [ref] $ReportExecutionWarnings);\n\n # loop through the report execution parameters\n foreach($Parameter in $ExecutionInfo.Parameters)\n {\n # create new item parameter object\n $ItemParameter = New-Object \"$ReportServerProxyNamespace.ItemParameter\";\n\n # fill in the properties except valid values, that one needs special processing\n Copy-ObjectProperties -SourceObject $Parameter -TargetObject $ItemParameter;\n\n # fill in the valid values\n $ItemParameter.ValidValues = Convert-ValidValues -SourceValidValues $Parameter.ValidValues;\n\n # exclude if it's query based\n if($Parameter.DefaultValuesQueryBased -ne $true)\n {\n # add to list\n $ReportParameters += $ItemParameter;\n }\n }\n\n # force the parameters to update\n Write-Host \"Updating report parameters for $ReportFolderPath/$ReportName\"\n\tif ($IsReportService2005) {\n\t\t$ReportServerProxy.SetReportParameters(\"$ReportFolderPath/$ReportName\", $ReportParameters);\n\t}\n\telseif ($IsReportService2010) {\n\t\t$ReportServerProxy.SetItemParameters(\"$ReportFolderPath/$ReportName\", $ReportParameters);\n\t}\n\telse { Write-Warning 'Report Service Unknown in Update-ReportParameters method. Use ReportService2005 or ReportService2010.' }\n}\n#endregion\n\n#region Remove-ShareReferences()\nFunction Remove-SharedReferences($ReportFile)\n{\n ######################################################################################################\n #You'll notice that I've used the keyword of [void] in front of some of these method calls, this is so\n #that the operation isn't captured as output of the function\n ######################################################################################################\n\n # read xml\n [xml]$ReportXml = Get-Content $ReportFile -Encoding UTF8;\n \n # create new memory stream object\n $MemoryStream = New-Object System.IO.MemoryStream\n\n try\n {\n\n # declare array of nodes to remove\n $NodesToRemove = @();\n\n # get datasource names\n $DataSourceNames = Get-ItemDataSources -ItemFile $ReportFile\n\n # check to see if report has datasourcenames\n if($DataSourceNames.Count -eq 0)\n {\n # Get reference to reportnode\n $ReportNode = $ReportXml.FirstChild.NextSibling # Kind of a funky way of getting it, but the SelectSingleNode(\"//Report\") wasn't working due to Namespaces in the node\n\n # create new DataSources node\n $DataSourcesNode = $ReportXml.CreateNode($ReportNode.NodeType, \"DataSources\", $null)\n\n # create new datasource node\n $DataSourceNode = $ReportXml.CreateNode($ReportNode.NodeType, \"DataSource\", $null)\n\n # create new datasourcereference node\n $DataSourceReferenceNode = $ReportXml.CreateNode($ReportNode.NodeType, \"DataSourceReference\", $null)\n\n # create new attribute\n $DataSourceNameAttribute = $ReportXml.CreateAttribute(\"Name\")\n $DataSourceNameAttribute.Value = \"DataSource1\"\n $dataSourceReferenceNode.InnerText = \"DataSource1\"\n\n # add attribute to datasource node\n [void]$DataSourceNode.Attributes.Append($DataSourceNameAttribute)\n [void]$DataSourceNode.AppendChild($DataSourceReferenceNode)\n\n # add nodes\n [void]$ReportNode.AppendChild($DataSourcesNode)\n [void]$DataSourcesNode.AppendChild($DataSourceNode)\n\n # add fake datasource name to array\n $DataSourceNames += \"DataSource1\"\n }\n\n # get all datasource nodes\n $DatasourceNodes = $ReportXml.GetElementsByTagName(\"DataSourceReference\");\n\n # loop through returned nodes\n foreach($DataSourceNode in $DatasourceNodes)\n {\n # create a new connection properties node\n $ConnectionProperties = $ReportXml.CreateNode($DataSourceNode.NodeType, \"ConnectionProperties\", $null);\n\n # create a new dataprovider node\n $DataProvider = $ReportXml.CreateNode($DataSourceNode.NodeType, \"DataProvider\", $null);\n $DataProvider.InnerText = \"SQL\";\n\n # create new connection string node\n $ConnectString = $ReportXml.CreateNode($DataSourceNode.NodeType, \"ConnectString\", $null);\n $ConnectString.InnerText = \"Data Source=Server Name Here;Initial Catalog=database name here\";\n\n # add new node to parent node\n [void] $DataSourceNode.ParentNode.AppendChild($ConnectionProperties);\n\n # append childeren\n [void] $ConnectionProperties.AppendChild($DataProvider);\n [void] $ConnectionProperties.AppendChild($ConnectString);\n\n # Add to remove list \n $NodesToRemove += $DataSourceNode;\n }\n\n # get all shareddataset nodes\n $SharedDataSetNodes = $ReportXml.GetElementsByTagName(\"SharedDataSet\")\n\n #loop through the returned nodes\n foreach($SharedDataSetNode in $SharedDataSetNodes)\n {\n # create holder nodes so it won't error\n $QueryNode = $ReportXml.CreateNode($SharedDataSetNode.NodeType, \"Query\", $null);\n $DataSourceNameNode = $ReportXml.CreateNode($QueryNode.NodeType, \"DataSourceName\", $null);\n $CommandTextNode = $ReportXml.CreateNode($QueryNode.NodeType, \"CommandText\", $null);\n\n # add valid datasource name, just get the first in the list\n $DataSourceNameNode.InnerText = $DataSourceNames[0]\n \n # add node to parent\n [void] $SharedDataSetNode.ParentNode.Appendchild($QueryNode)\n \n # add datasourcename and commandtext to query node\n [void]$QueryNode.AppendChild($DataSourceNameNode)\n [void]$QueryNode.AppendChild($CommandTextNode)\n\n # add node to removelist\n $NodesToRemove += $SharedDataSetNode\n }\n\n\n # loop through nodes to remove\n foreach($Node in $NodesToRemove)\n {\n # remove from parent\n [void] $Node.ParentNode.RemoveChild($Node);\n }\n \n $ReportXml.InnerXml = $ReportXml.InnerXml.Replace(\"xmlns=`\"`\"\", \"\")\n\n # save altered xml to memory stream\n $ReportXml.Save($MemoryStream);\n\n # return the altered xml as byte array\n return $MemoryStream.ToArray();\n }\n finally\n {\n # close and dispose\n $MemoryStream.Close();\n $MemoryStream.Dispose();\n }\n}\n#endregion\n\n\n#region Copy-ObjectProperties()\nFunction Copy-ObjectProperties($SourceObject, $TargetObject)\n{\n # Get source object property array\n $SourcePropertyCollection = $SourceObject.GetType().GetProperties();\n\n # get the destination\n $TargetPropertyCollection = $TargetObject.GetType().GetProperties();\n\n # loop through source property collection\n for($i = 0; $i -lt $SourcePropertyCollection.Length; $i++)\n {\n # get the target property\n $TargetProperty = $TargetPropertyCollection | Where {$_.Name -eq $SourcePropertyCollection[$i].Name}\n \n # check to see if it's null\n if($TargetProperty -ne $null)\n {\n # check to see if it's the valid values property\n if($TargetProperty.Name -ne \"ValidValues\")\n {\n # set the value\n $TargetProperty.SetValue($TargetObject, $SourcePropertyCollection[$i].GetValue($SourceObject));\n }\n }\n }\n}\n#endregion\n\n#region ConvertValidValues()\nFunction Convert-ValidValues($SourceValidValues)\n{\n # declare local values\n $TargetValidValues = @();\n \n # loop through source values\n foreach($SourceValidValue in $SourceValidValues)\n {\n # create target valid value object\n $TargetValidValue = New-Object \"$ReportServerProxyNamespace.ValidValue\";\n\n # copy properties\n Copy-ObjectProperties -SourceObject $SourceValidValue -TargetObject $TargetValidValue\n\n # add to list\n $TargetValidValues += $TargetValidValue\n }\n\n # return the values\n return ,$TargetValidValues\n}\n#endregion\n\n#region Backup-ExistingItem()\nFunction Backup-ExistingItem\n{\n # parameters\n Param($ItemFile, $ItemFolder)\n\n # declare local variables\n $ItemName = $ItemFile.SubString($ItemFile.LastIndexOf(\"\\\") + 1)\n $ItemName = $ItemName.SubString(0, $ItemName.LastIndexOf(\".\"))\n\n # check to see if the item exists\n if((Item-Exists -ItemFolderPath $ItemFolder -ItemName $ItemName) -eq $true)\n {\n # get file extension\n $FileExtension = [System.IO.Path]::GetExtension($ItemFile)\n \n # check backuplocation\n if($BackupLocation.EndsWith(\"\\\") -ne $true)\n {\n # append ending slash\n $BackupLocation = $BackupLocation + \"\\\"\n }\n\t\t\n\t\t# add the release number to the backup location\n\t\t$BackupLocation = $BackupLocation + $ReleaseNumber + \"\\\"\n\n # ensure the backup location actually exists\n if((Test-Path $BackupLocation) -ne $true)\n {\n # create it\n New-Item -ItemType Directory -Path $BackupLocation\n }\n\n # download the item\n $Item = $ReportServerProxy.GetItemDefinition(\"$ItemFolder/$ItemName\")\n\n # form the backup path\n $BackupPath = \"{0}{1}{2}\" -f $BackupLocation, $ItemName, $FileExtension;\n\n # write to disk\n [System.IO.File]::WriteAllBytes(\"$BackupPath\", $Item);\n\n # write to screen\n Write-Host \"Backed up $ItemFolder/$ItemName to $BackupPath\";\n }\n}\n#endregion\n\n#region Normalize-SSRSFolder()\nfunction Normalize-SSRSFolder ([string]$Folder) {\n if (-not $Folder.StartsWith('/')) {\n $Folder = '/' + $Folder\n }\n \n return $Folder\n}\n#endregion\n\n#region New-SSRSFolder()\nfunction New-SSRSFolder ([string] $Name) {\n Write-Verbose \"New-SSRSFolder -Name $Name\"\n \n $Name = Normalize-SSRSFolder -Folder $Name\n \n if ($ReportServerProxy.GetItemType($Name) -ne 'Folder') {\n $Parts = $Name -split '/'\n $Leaf = $Parts[-1]\n $Parent = $Parts[0..($Parts.Length-2)] -join '/'\n \n if ($Parent) {\n New-SSRSFolder -Name $Parent\n } else {\n $Parent = '/'\n }\n \n $ReportServerProxy.CreateFolder($Leaf, $Parent, $null)\n }\n}\n#endregion\n\n#region Clear-SSRSFolder()\nfunction Clear-SSRSFolder ([string] $Name) {\n Write-Verbose \"Clear-SSRSFolder -Name $Name\"\n \n $Name = Normalize-SSRSFolder -Folder $Name\n \n if ($ReportServerProxy.GetItemType($Name) -eq 'Folder' -and $ClearReportFolder) {\n Write-Host (\"Clearing the {0} folder\" -f $Name)\n $ReportServerProxy.ListChildren($Name, $false) | ForEach-Object {\n Write-Verbose \"Deleting item: $($_.Path)\"\n $ReportServerProxy.DeleteItem($_.Path)\n }\n }\n}\n#endregion\n\n#region New-SSRSDataSource()\nfunction New-SSRSDataSource ([string]$RdsPath, [string]$Folder, [bool]$OverwriteDataSources) {\n Write-Verbose \"New-SSRSDataSource -RdsPath $RdsPath -Folder $Folder\"\n\n $Folder = Normalize-SSRSFolder -Folder $Folder\n \n [xml]$Rds = Get-Content -Path $RdsPath\n $dsName = $Rds.RptDataSource.Name\n $ConnProps = $Rds.RptDataSource.ConnectionProperties\n \n\t$type = $ReportServerProxy.GetType().Namespace #Get proxy type\n\t$DSDdatatype = ($type + '.DataSourceDefinition')\n\t \n\t$Definition = new-object ($DSDdatatype)\n\tif($Definition -eq $null){\n\t Write-Error Failed to create data source definition object\n\t}\n\t\n\t$dsConnectionString = $($OctopusParameters[\"$($dsName).ConnectionString\"])\n $dsUsername = $($OctopusParameters[\"$($dsName).Username\"])\n $dsPassword = $($OctopusParameters[\"$($dsName).Password\"])\n $dsCredentialRetrieval = $($OctopusParameters[\"$($dsName).CredentialRetrieval\"])\n \n\t# replace the connection string variable that is configured in the octopus project\n\tif ($dsConnectionString) {\n\t $Definition.ConnectString = $dsConnectionString\n\t} else {\n\t $Definition.ConnectString = $ConnProps.ConnectString\n\t}\n\t\n $Definition.Extension = $ConnProps.Extension \n\n\t# Check to see if the credential retrieval is overridden\n if ($null -ne $dsCredentialRetrieval)\n {\n \tWrite-Host \"Forcing CredentialRetrieval property to: $dsCredentialRetrieval.\"\n $Definition.CredentialRetrieval = $dsCredentialRetrieval\n }\n else\n {\n \t# Set the Credential Retrieval method\n \tif ([Convert]::ToBoolean($ConnProps.IntegratedSecurity)) {\n\t\t\t$Definition.CredentialRetrieval = 'Integrated'\n\t\t}\n elseif (![string]::IsNullOrWhitespace($dsUsername) -and ![string]::IsNullOrWhitespace($dsPassword))\n {\n \t$Definition.CredentialRetrieval = 'Store'\n }\n }\n \n\tif ($Definition.CredentialRetrieval -eq 'Store')\n {\t\t\n\t\tWrite-Host \"$($dsName).Username = '$dsUsername'\"\n\t\tWrite-Host \"$($dsName).Password = '$dsPassword'\"\n\t\t\n\t\t$Definition.UserName = $dsUsername;\n $Definition.Password = $dsPassword;\n\t}\n \n # Check to see if this is supposed to be an Windows Authentication stored account\n if ($OctopusParameters[\"$($dsName).WindowsCredentials\"] -eq \"true\")\n {\n\t # Set the definition to Windows Credentials\n \t$Definition.WindowsCredentials = $true\n }\n \n\n $DataSource = New-Object -TypeName PSObject -Property @{\n Name = $Rds.RptDataSource.Name\n Path = $Folder + '/' + $Rds.RptDataSource.Name\n }\n \n if ($OverwriteDataSources -or $ReportServerProxy.GetItemType($DataSource.Path) -eq 'Unknown') {\n Write-Host \"Overwriting datasource $($DataSource.Name)\"\n $ReportServerProxy.CreateDataSource($DataSource.Name, $Folder, $OverwriteDataSources, $Definition, $null)\n }\n \n return $DataSource \n}\n#endregion\n\n#region Main\n\ntry\n{\n # declare array for reports\n $ReportFiles = @()\n\t$ReportDataSourceFiles = @()\n $ReportDataSetFiles = @()\n $ReportPartFiles = @()\n\t\n\t$IsReportService2005 = $false\n\t$IsReportService2010 = $false\n\t\n\tif ($ReportServiceUrl.ToLower().Contains('reportservice2005.asmx')) {\n\t\t$IsReportService2005 = $true\n\t\tWrite-Host \"2005 Report Service found.\"\n\t}\n\telseif ($ReportServiceUrl.ToLower().Contains('reportservice2010.asmx')) {\n\t\t$IsReportService2010 = $true\n\t\tWrite-Host \"2010 Report Service found.\"\n\t}\n\t\n\tWrite-Host \"Deploy Path: $DeployedPath\"\n\t\n # get all report files for deployment\n Write-Host \"Getting all .rdl files\"\n Get-ChildItem $DeployedPath -Recurse -Filter \"*.rdl\" | ForEach-Object { If(($ReportFiles -contains $_.FullName) -eq $false) {$ReportFiles += $_.FullName}}\n Write-Host \"# of rdl files found: $($ReportFiles.Count)\"\n\n # get all report datasource files for deployment\n Write-Host \"Getting all .rds files\"\n Get-ChildItem $DeployedPath -Recurse -Filter \"*.rds\" | ForEach-Object { If(($ReportDataSourceFiles -contains $_.FullName) -eq $false) {$ReportDataSourceFiles += $_.FullName}}\n Write-Host \"# of rds files found: $($ReportDataSourceFiles.Count)\"\n\n # get all report datset files for deployment\n Write-Host \"Getting all .rsd files\"\n Get-ChildItem $DeployedPath -Recurse -Filter \"*.rsd\" | ForEach-Object { If(($ReportDataSetFiles -contains $_.FullName) -eq $false) {$ReportDataSetFiles += $_.FullName}}\n Write-Host \"# of rsd files found: $($ReportDataSetFiles.Count)\"\n\n # get all report part files for deployment\n Write-Host \"Getting all .rsc files\"\n Get-ChildItem $DeployedPath -Recurse -Filter \"*.rsc\" | ForEach-Object { If(($ReportPartFiles -contains $_.FullName) -eq $false) {$ReportPartFiles += $_.FullName}}\n Write-Host \"# of rsc files found: $($ReportPartFiles.Count)\"\n\n # set the report proxies\n Write-Host \"Creating SSRS Web Service proxies\"\n\n # check to see if credentials were supplied for the services\n if(([string]::IsNullOrEmpty($ServiceUserDomain) -ne $true) -and ([string]::IsNullOrEmpty($ServiceUserName) -ne $true) -and ([string]::IsNullOrEmpty($ServicePassword) -ne $true))\n {\n # secure the password\n $secpasswd = ConvertTo-SecureString \"$ServicePassword\" -AsPlainText -Force\n\n # create credential object\n $ServiceCredential = New-Object System.Management.Automation.PSCredential (\"$ServiceUserDomain\\$ServiceUserName\", $secpasswd)\n\n # create proxies\n $ReportServerProxy = New-WebServiceProxy -Uri $ReportServiceUrl -Credential $ServiceCredential\n $ReportExecutionProxy = New-WebServiceProxy -Uri $ReportExecutionUrl -Credential $ServiceCredential\n }\n else\n {\n # create proxies using current identity\n $ReportServerProxy = New-WebServiceProxy -Uri $ReportServiceUrl -UseDefaultCredential \n $ReportExecutionProxy = New-WebServiceProxy -Uri $ReportExecutionUrl -UseDefaultCredential \n }\n\n\n\n\t#Create folder information for DataSource and Report\n if ($UseArchiveStructure -eq $false)\n {\n\t New-SSRSFolder -Name $ReportFolder\n\t New-SSRSFolder -Name $ReportDatasourceFolder\n New-SSRSFolder -Name $ReportDataSetFolder\n New-SSRSFolder -Name $ReportPartsFolder\n }\n else\n {\n New-SSRSFolder -Name $RootFolder\n }\n \n #Clear destination folder if specified\n if([System.Convert]::ToBoolean(\"$ClearReportFolder\")) {\n Clear-SSRSFolder -Name $ReportFolder\n }\n\t \n\t#Create DataSource\n foreach($RDSFile in $ReportDataSourceFiles) {\n Write-Host \"New-SSRSDataSource $RdsFile\"\n\n $DatasourceFolder = \"\"\n\n if ($UseArchiveStructure -eq $true)\n {\n # Adjust report folder to archive path\n $DatasourceFolder = $(if ($RootFolder -eq \"/\") { [string]::Empty} else { $RootFolder } ) + $RDSFile.Replace($DeployedPath, '').Replace('\\', '/').Replace((Split-Path $RDSFile -Leaf), '')\n\n # Remove final slash\n $DatasourceFolder = $DatasourceFolder.Substring(0, $DatasourceFolder.LastIndexOf('/')) \n \n # Check if folder exists\n New-SSRSFolder -Name $DatasourceFolder \n }\n else\n {\n $DatasourceFolder = $ReportDatasourceFolder\n }\n \n\t\t$DataSource = New-SSRSDataSource -RdsPath $RdsFile -Folder $DatasourceFolder -Overwrite ([System.Convert]::ToBoolean(\"$OverwriteDataSources\"))\n\t}\n\n # get the service proxy namespaces - this is necessary because of a bug documented here http://stackoverflow.com/questions/7921040/error-calling-reportingservice2005-finditems-specifically-concerning-the-bool and http://www.vistax64.com/powershell/273120-bug-when-using-namespace-parameter-new-webserviceproxy.html\n $ReportServerProxyNamespace = Get-ObjectNamespace -Object $ReportServerProxy\n $ReportExecutionProxyNamespace = Get-ObjectNamespace -Object $ReportExecutionProxy\n\n # Create dat sets\n foreach($DataSet in $ReportDataSetFiles)\n {\n $DataSetPath = \"\"\n\n # Check to see if it's set to follow archive structure\n if ($UseArchiveStructure -eq $true)\n {\n # Adjust report folder to archive path\n $DataSetPath = $(if ($RootFolder -eq \"/\") { [string]::Empty} else { $RootFolder } ) + $DataSet.Replace($DeployedPath, '').Replace('\\', '/').Replace((Split-Path $DataSet -Leaf), '')\n\n # Remove final slash\n $DataSetPath = $DataSetPath.Substring(0, $DataSetPath.LastIndexOf('/'))\n\n # Check if folder exists\n New-SSRSFolder -Name $DataSetPath\n }\n else\n {\n $DataSetPath = $ReportDataSetFolder\n }\n\n # check to see if we need to back up\n if($BackupLocation -ne $null -and $BackupLocation -ne \"\")\n {\n # backup the item\n Backup-ExistingItem -ItemFile $DataSet -ItemFolder $DataSetPath\n }\n\n # upload the dataset\n Upload-Item -Item $DataSet -ItemType \"DataSet\" -ItemFolder $DataSetPath\n\n # update the dataset datasource\n Set-ItemDataSources -ItemFile $DataSet -ItemFolder $DataSetPath\n }\n\n # get the proxy auto generated name spaces\n\n # loop through array\n foreach($ReportFile in $ReportFiles)\n {\n $ReportPath = \"\"\n\n # Check to see if it's set to follow archive structure\n if ($UseArchiveStructure -eq $true)\n {\n # Adjust report folder to archive path\n $ReportPath = $(if ($RootFolder -eq \"/\") { [string]::Empty} else { $RootFolder } ) + $ReportFile.Replace($DeployedPath, '').Replace('\\', '/').Replace((Split-Path $ReportFile -Leaf), '')\n\n # Remove final slash\n $ReportPath = $ReportPath.Substring(0, $ReportPath.LastIndexOf('/'))\n\n # Check if folder exists\n New-SSRSFolder -Name $ReportPath\n }\n else\n {\n $ReportPath = $ReportFolder\n }\n\n # check to see if we need to back up\n if($BackupLocation -ne $null -and $BackupLocation -ne \"\")\n {\n # backup the item\n Backup-ExistingItem -ItemFile $ReportFile -ItemFolder $ReportPath\n }\n \n \n # upload report\n Upload-Item -Item $ReportFile -ItemType \"Report\" -ItemFolder $ReportPath\n\n # extract datasources\n #Write-Host \"Extracting datasource names for $ReportFile\"\n #$ReportDataSourceNames = Get-ReportDataSourceNames $ReportFile\n\n # set the datasources\n Set-ItemDataSources -ItemFile $ReportFile -ItemFolder $ReportPath\n\n # set the datasets\n Set-ReportDataSets -ReportFile $ReportFile -ReportFolderPath $ReportPath\n\n # update the report parameters\n Update-ReportParameters -ReportFile $ReportFile -ReportFolderPath $ReportPath\n }\n \n # loop through rsc files\n foreach($ReportPartFile in $ReportPartFiles)\n {\n # check to see if we need to back up\n if($BackupLocation -ne $null -and $BackupLocation -ne \"\")\n {\n # backup the item\n Backup-ExistingItem -ItemFile $ReportPartFile -ItemFolder $ReportPartsFolder\n }\n\n\t\t# upload item\n Upload-Item -Item $ReportPartFile -ItemType \"Component\" -ItemFolder $ReportPartsFolder\n }\n \n}\nfinally\n{\n # check to see if the proxies are null\n if($ReportServerProxy -ne $null)\n {\n # dispose\n $ReportServerProxy.Dispose();\n }\n\n if($ReportExecutionProxy -ne $null)\n {\n # dispose\n $ReportExecutionProxy.Dispose();\n }\n}\n\n#endregion\n",
"Octopus.Action.Script.Syntax": "PowerShell",
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.RunOnServer": "false"
},
"Category": "SQL Server",
"HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/ssrs-deploy-from-package-parameter.json",
"Website": "/step-templates/2c118ec9-4c3e-45a4-85b7-9f3c8ae99ca9",
"Logo": "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",
"$Meta": {
"Type": "ActionTemplate"
}
}
Page updated on Thursday, March 11, 2021