Skip to content

Instantly share code, notes, and snippets.

@EitanBlumin
Last active August 28, 2024 05:58
Show Gist options
  • Save EitanBlumin/e3b34d4c2de793054854e0e3d43f4349 to your computer and use it in GitHub Desktop.
Save EitanBlumin/e3b34d4c2de793054854e0e3d43f4349 to your computer and use it in GitHub Desktop.
Powershell script to deploy SSRS reports from a folder (all rds and rdl files)
Param
(
[string] $SourceFolder = "C:\SSRS\My-Reports",
[string] $TargetReportServerUri = "http://localhost:8081/ReportServer",
[PSCredential] $Credential,
[switch] $CustomAuthentication,
[string] $ApiVersion,
[string] $TargetFolder = "/My-Reports/Sample-Reports",
[switch] $Recursive,
[string] $OverrideDataSourcePathForAll, #= "/My-Reports/Data Sources/ProdDS",
[string] $logFileFolderPath = "C:\SSRS_deployment_log",
[string] $logFilePrefix = "ssrs_deploy_",
[string] $logFileDateFormat = "yyyyMMdd_HHmmss",
[int] $logFileRetentionDays = 30
)
Process {
#region initialization
function Get-TimeStamp {
Param(
[switch]$NoWrap,
[switch]$Utc
)
$dt = Get-Date
if ($Utc -eq $true) {
$dt = $dt.ToUniversalTime()
}
$str = "{0:MM/dd/yy} {0:HH:mm:ss}" -f $dt
if ($NoWrap -ne $true) {
$str = "[$str]"
}
return $str
}
if ($logFileFolderPath -ne "")
{
if (!(Test-Path -PathType Container -Path $logFileFolderPath)) {
Write-Output "$(Get-TimeStamp) Creating directory $logFileFolderPath" | Out-Null
New-Item -ItemType Directory -Force -Path $logFileFolderPath | Out-Null
} else {
$DatetoDelete = $(Get-Date).AddDays(-$logFileRetentionDays)
Get-ChildItem $logFileFolderPath | Where-Object { $_.Name -like "*$logFilePrefix*" -and $_.LastWriteTime -lt $DatetoDelete } | Remove-Item | Out-Null
}
$logFilePath = $logFileFolderPath + "\$logFilePrefix" + (Get-Date -Format $logFileDateFormat) + ".LOG"
# attempt to start the transcript log, but don't fail the script if unsuccessful:
try
{
Start-Transcript -Path $logFilePath -Append
}
catch [Exception]
{
Write-Warning "$(Get-TimeStamp) Unable to start Transcript: $($_.Exception.Message)"
$logFileFolderPath = ""
}
}
#endregion initialization
#region install-modules
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
if (Get-PSRepository -Name "PSGallery") {
Write-Verbose "$(Get-TimeStamp) PSGallery already registered"
}
else {
Write-Information "$(Get-TimeStamp) Registering PSGallery"
Register-PSRepository -Default
}
if (Get-Module -ListAvailable -Name PowerShellGet) {
Write-Verbose "$(Get-TimeStamp) PowerShellGet already installed"
}
else {
Write-Information "$(Get-TimeStamp) Installing PowerShellGet"
Install-Module PowerShellGet -RequiredVersion 2.2.4 -Force -SkipPublisherCheck -Scope CurrentUser -ErrorAction Stop -AllowClobber | Out-Null
Import-Module PowerShellGet -Force -Scope Local | Out-Null
}
if ((Get-PSRepository -Name "PSGallery").Trusted) {
Write-Verbose "$(Get-TimeStamp) PSGallery already Trusted"
} else {
Write-Information "$(Get-TimeStamp) Marking PSGallery as Trusted..."
Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
}
# replace the array below with any modules that your script depends on.
# you can remove this region if your script doesn't need importing any modules.
$modules = @("ReportingServicesTools")
foreach ($module in $modules) {
if (Get-Module -ListAvailable -Name $module) {
Write-Verbose "$(Get-TimeStamp) $module already installed"
}
else {
Write-Information "$(Get-TimeStamp) Installing $module"
Install-Module $module -Force -SkipPublisherCheck -Scope CurrentUser -ErrorAction Stop | Out-Null
Import-Module $module -Force -Scope Local | Out-Null
}
}
#Write-Output "Requesting RSTools..."
#Invoke-Expression (Invoke-WebRequest https://aka.ms/rstools)
#endregion install-modules
#region main
$ErrorActionPreference = "Stop"
if ($SourceFolder -eq "" -or $SourceFolder -eq $null) {
$SourceFolder = $(Get-Location).Path + "\"
}
if ($TargetFolder -eq "" -or $TargetFolder -eq $null) {
$TargetFolder = "/"
}
if (!$SourceFolder.EndsWith("\"))
{
$SourceFolder = $SourceFolder + "\"
}
Write-Output "====================================================================================="
Write-Output " Deploying SSRS Reports"
Write-Output "Target Server: $TargetReportServerUri"
$ProxyParams = @{
ReportServerUri = $TargetReportServerUri
CustomAuthentication = $CustomAuthentication
}
if ($Credential -ne $null) {
Write-Output "Username: $($Credential.UserName)"
$ProxyParams.Credential = $Credential
}
if ($ApiVersion -ne $null) {
Write-Output "ApiVersion: $ApiVersion"
$ProxyParams.ApiVersion = $ApiVersion
}
Write-Output "====================================================================================="
$Proxy = New-RsWebServiceProxy @ProxyParams
$SourceFoldersList = @()
$SourceFoldersList += $SourceFolder
if ($Recursive) {
Get-ChildItem -Recurse -Directory -Path $SourceFolder | ForEach-Object {
$SourceFoldersList += $_.FullName
}
}
$SourceFoldersList | ForEach-Object {
$currSourceFolder = $_
if (!$currSourceFolder.EndsWith("\"))
{
$currSourceFolder = $currSourceFolder + "\"
}
if ($currSourceFolder -ne $SourceFolder) {
$currTargetFolder = $TargetFolder + "/" + [Regex]::Replace($currSourceFolder,$SourceFolder.Replace('\','\\'),'').Replace('\','/')
} else {
$currTargetFolder = $TargetFolder
}
Write-Output "====================================================================================="
Write-Output "Source Folder: $currSourceFolder"
Write-Output "Target Folder: $currTargetFolder"
Write-Output "=============="
if ($currTargetFolder -ne "/") {
if ($currTargetFolder.StartsWith("/")) {
$currTargetFolder = $currTargetFolder.Remove(0,1)
}
Write-Output "$(Get-TimeStamp) Creating Folder: $currTargetFolder"
New-RsFolder -Proxy $Proxy -Path / -Name $currTargetFolder -Verbose -ErrorAction SilentlyContinue
}
if (!$currTargetFolder.StartsWith("/")) {
$currTargetFolder = $currTargetFolder.Insert(0, "/")
}
Write-Output "$(Get-TimeStamp) Deploying Data Source files from: $currSourceFolder"
DIR $currSourceFolder -Filter *.rds | % { $_.FullName } | Write-RsCatalogItem -Proxy $Proxy -Destination $currTargetFolder -Verbose -Overwrite
Write-Output "$(Get-TimeStamp) Deploying Data Set files from: $currSourceFolder"
DIR $currSourceFolder -Filter *.rsd | % { $_.FullName } | Write-RsCatalogItem -Proxy $Proxy -Destination $currTargetFolder -Verbose -Overwrite
Write-Output "$(Get-TimeStamp) Deploying Report Definition files from: $currSourceFolder"
DIR $currSourceFolder -Filter *.rdl | % { $_.FullName } | Write-RsCatalogItem -Proxy $Proxy -Destination $currTargetFolder -Verbose -Overwrite
if ($OverrideDataSourcePathForAll -ne $null -and $OverrideDataSourcePathForAll -ne "") {
Write-Output "$(Get-TimeStamp) Fixing Data Source references to: $OverrideDataSourcePathForAll"
Get-RsFolderContent -Proxy $Proxy -RsFolder $currTargetFolder | ForEach {
$CurrReport = $_
Get-RsItemReference -Proxy $Proxy -Path $CurrReport.Path | Where ReferenceType -eq "DataSource" | ForEach {
$CurrReference = $_
if ($CurrReference.Reference -ne $OverrideDataSourcePathForAll) {
Write-Output "$(Get-TimeStamp) UPDATING: Data Source $($CurrReference.Name) in report $($CurrReport.Path)"
Set-RsDataSourceReference -Proxy $Proxy -Path $CurrReport.Path -DataSourceName $CurrReference.Name -DataSourcePath $OverrideDataSourcePathForAll
} else {
Write-Output "$(Get-TimeStamp) Data Source $($CurrReference.Name) in report $($CurrReport.Path) already set correctly."
}
}
}
}
}
#endregion main
#region finalization
if ($logFileFolderPath -ne "") { Stop-Transcript }
#endregion finalization
}
@kadiyala82
Copy link

kadiyala82 commented Aug 6, 2024

Hello Eithan,

looks like your script only used for single folder content to upload SSRS URL. But I am looking for recursive folders and those folder having reports and that needs to create recursive folder hirarchy and upload their hirarchy folder content into the SSRS URL.

I am using below Powershell script but I am getting errors. Can you please correct me or please edit the below script to upload all the recursive hirarchy folder content.

Import-Module ReportingServicesTools
$ReportPath = 'X:\SSRS_Reports_staging'
$Folders = Get-ChildItem $ReportPath -Recurse -Directory
$ReportServerURI = 'http://myreportserver/Reportserver/ReportService2010.asmx?wsdl'
Get-ChildItem $ReportPath -Recurse -Directory -Name | ForEach-Object {
# Split the relative input path into leaf (directory name)
# and parent path, and convert the parent path to the target parent path
# by prepending "/" and converting path-internal "" instances to "/".
$SubFolderParentPath = '/' + ((Split-Path -Parent $) -replace '\', '/')
$SubFolderName = Split-Path -Leaf $

try{
New-RsFolder -ReportServerUri $ReportServerURI -Path $SubFolderParentPath -FolderName $SubFolderName
Write-Host "Created folder ${SubFolderParentPath}/${SubFoldeNamer}"
Write-RsFolderContent -ReportServerUri $ReportServerURI -Path $SubFolderParentPath -RsFolder $SubFolderName -Verbose
}
catch {
# Report the specific error that occurred, accessible via $_
Write-Host "An error occurred for ${SubFolderParentPath}/${SubFolderName}: $_"
}
}

Errors:

VERBOSE: Establishing proxy connection to http://myreportserver/Reportserver/ReportServ
ice2010.asmx...
An error occurred for /DATAMGMT_STAGING/WIZMO: /DATAMGMT_STAGING is not a folder
Created folder /DATAMGMT_STAGING/APC/CORPHOME
VERBOSE: Performing the operation "Upload all contents in folder to CORPHOME" on t
arget "/DATAMGMT_STAGING/APC".
VERBOSE: Establishing proxy connection to http://myreportserver/Reportserver/ReportServ
ice2010.asmx...
An error occurred for /DATAMGMT_STAGING/APC/CORPHOME: /DATAMGMT_STAGING/APC is not
a folder

@EitanBlumin
Copy link
Author

Thank you for the note, @kadiyala82 .
I updated the script to its latest version, and also added the Recursive parameter.

Can you check if it works for you?

@kadiyala82
Copy link

kadiyala82 commented Aug 22, 2024

Hello EItanBlumin

First of all thanks for replying. I just used the updated script, but I got below error.

                         Deploying SSRS Reports

Target Server:
ApiVersion:

PS>TerminatingError(New-RsWebServiceProxy): "Cannot validate argument on parameter 'ApiVersion'. The argument "" does not belong to the set "2005,2006,2010" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again."

TerminatingError(New-RsWebServiceProxy): "Cannot validate argument on parameter 'ApiVersion'. The argument "" does not belong to the set "2005,2006,2010" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again."
New-RsWebServiceProxy : Cannot validate argument on parameter 'ApiVersion'. The argument "" does not belong to
the set "2005,2006,2010" specified by the ValidateSet attribute. Supply an argument that is in the set and
then try the command again.
At X:\Deploy SSRS Reports.ps1:149 char:32

  • $Proxy = New-RsWebServiceProxy @ProxyParams
  •                            ~~~~~~~~~~~~
    
    • CategoryInfo : InvalidData: (:) [New-RsWebServiceProxy], ParentContainsErrorRecordException
    • FullyQualifiedErrorId : ParameterArgumentValidationError,New-RsWebServiceProxy

@EitanBlumin
Copy link
Author

Hi @kadiyala82 .

Based on your error, it looks like you specified an empty string for the ApiVersion parameter.
It should be $null or unspecified instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment