If you liked the first version of this script ,you'll love the new version.
The first version was written to solve a problem and nothing more, but turned out that it was something the SSRS community was waiting for as it is one of the most read posts on my blog.
The new version has been completely rewritten to make it more robust and in the process i've added a feature or two.
- It now uses the Reporting Service 2010 Web Service
- It's now structurally a better script. Easier to understand and work with.
- Supports Folder structure
- Can easily be modified to upload all kinds of elements like images,pdf+
The script is designed for Configmgr reports ,but the only part that's specific to Configmgr is the part that searches for the data source. To work with other data sources you just need to modify the search criteria or just "hard code" in the name of the shared data source you want to use.
How It works
only required parameter is the URL(-webserviceUrl) to the reporting server.
& '.\Upload Reports v3.ps1' -webServiceUrl http://yourSSRSserver
Default it will look in the script folder for reports ,upload them to a folder called "Larsen Reports" and wont overwrite if report already exist ,but all this can be changed by setting additional parameters.
& '.\Upload Reports v3.ps1' -webServiceUrl http://yourSSRSserver -SourceDirectory d\Reports -ReportFolder Demo -overwrite $true
In this example i just threw a few reports in a folder/sub folder structure. Some reports on the root and some in the sub directories.
I run the script assigning the -reportFolder paramenter to Demo.
As you can see in the screenshot under it first creates the folder structure, then it searches for *.rdl files and upload them to the correct folder/ sub folder and changes the data source.
Everything should be ready to use!
Looking at the Report server, it has created the folders Demo and the 3 sub folders. The reports are uploaded in the right place.
..and the data source has been changed to the correct one.
Download: Upload Reports v3.zip
<# .SYNOPSIS Bulk import SSRS Reports from a folder and update the reports data source. .DESCRIPTION This script takes all the RDL files in a folder and imports them into a SSRS and updates the reports data source to the Configmgr shared data source. .NOTES File Name : Upload Reports.ps1 Version : 3.00 ,13.jun-2016 Author : Thomas Larsen - thomas.larsen@tromsfylke.no Requires : Version 3 .LINK Blog http://larsenconfigmgr.blogspot.com .PARAMETER webServiceUrl Base URL to the report server ,usually the Configmgr Site server .PARAMETER reportFolder Report Server folder where the reports are imported to, the script creates the folder if it's not there. .PARAMETER SourceDirectory The local folder where the .rdl files are located. .PARAMETER Overwrite Set to True if Script should overwrite Reports it they already exist. .Example & '.\Upload Reports.ps1' -webServiceUrl "http://Reportserver.domain.local" Takes the report files from current directory(And Subdirectories) and uploads them the to a folder on SSRS called Larsen Reports(Default) .Example & '.\Upload Reports.ps1' -webServiceUrl "http://Reportserver.domain.local" -reportFolder "Larsen Reports -SourceDirectory "c:\ReportsToUpload" -overwrite $True All Parameters ,select Sourcefolder Destination Folder ,Overwrite if exist #> Param( [string]$webServiceUrl, [string]$reportFolder = "Larsen Reports", [string]$SourceDirectory = $PSScriptRoot, [bool]$overwrite = $false ) Write-Host "Thomas Larsen - December 2015 - http://larsenconfigmgr.blogspot.com" -ForegroundColor Cyan Write-Host "This Script is provided AS-IS, no warrenty is provided" Write-host "" #Connect to SSRS Write-Host "Reportserver: $webServiceUrl" -ForegroundColor DarkMagenta Write-Host "Estabishing Proxy connection, connecting to : $webServiceUrl/ReportServer/ReportService2010.asmx?WSDL" Write-Host "" $ssrsProxy = New-WebServiceProxy -Uri $webServiceUrl'/ReportServer/ReportService2010.asmx?WSDL' -UseDefaultCredential ####### #Get Configmgr shared datasource $Items = $ssrsProxy.listchildren("/", $true) | where {$_.TypeName -eq "Datasource" } foreach ($item in $items) { #Check to see if Datasource name patches Guid Pattern if ($item.name -match '{([a-zA-Z0-9]{8})-([a-zA-Z0-9]{4})-([a-zA-Z0-9]{4})-([a-zA-Z0-9]{4})-([a-zA-Z0-9]{12})}' -and $item.path -like '/ConfigMgr*') { Write-Host "Datasource:" $item.Name -ForegroundColor Magenta Write-host "Type:" $item.TypeName Write-Host "Path:" $item.Path #Save parameters for later use. $DatasourceName = $item.Name $DatasourcePath = $item.Path } } function SSRSFolder ([string]$reportFolder,[string]$reportPath) { ########################################## #Create Folder try { $ssrsProxy.CreateFolder($reportFolder, $reportPath, $null) | out-null if($reportPath -eq '/') { Write-Host "Folder `"$reportpath$reportFolder`" Created" } else { Write-Host "Folder `"$reportpath/$reportFolder`" Created" } } catch [System.Web.Services.Protocols.SoapException] { if ($_.Exception.Detail.InnerText -match "rsItemAlreadyExists400") { Write-Host "Folder: $reportFolder already exists." } else { $msg = "Error creating folder: $reportFolder. Msg: '{0}'" -f $_.Exception.Detail.InnerText Write-Error $msg } } } Function SSRSItem ([string]$ItemType,$item,[string]$folder) { Write-host "" #ReportName if ($ItemType -ne "Resource") { $ItemName = [System.IO.Path]::GetFileNameWithoutExtension($item); } else { $ItemName = $item.Name } write-host $ItemName -ForegroundColor Green #Upload File try { #Get Report content in bytes Write-Host "Getting file content of : $item" $byteArray = Get-Content $item.FullName -encoding byte $msg = "Size: {0} KB" -f "{0:N0}" -f ($byteArray.Length/1KB) Write-Host $msg Write-Host "Uploading to: $folder" #Sets property for images(only png) $type = $ssrsProxy.GetType().Namespace $datatype = ($type + '.Property') $property =New-Object ($datatype); if ($ItemType -eq "Resource" -and $item -like "*.png") { $property.Name = "MimeType" $property.Value = “image/png” } else { $property = $null } #Call Proxy to upload report $warnings =@(); $ssrsProxy.CreateCatalogItem($ItemType,$itemName,$folder,$overwrite,$byteArray,$property,[ref]$warnings) | out-null if($warnings.Length -le 1) { Write-Host "Upload Success." -ForegroundColor Green } else { foreach ($message in $warnings) { if ($message.Code -ne "rsDataSourceReferenceNotPublished") { write-host "$($message.Severity) $($message.Code) $($message.Message)" -ForegroundColor Yellow } } } } 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] { $caught = $false if ($_.Exception.Detail.InnerText -match 'rsItemAlreadyExists400') { $caught = $true Write-Host "Report: $itemName already exists." -ForegroundColor Red } if ($_.Exception.Detail.InnerText -match 'CoretechSSRS') { $caught = $true Write-Host "Cant't find Reporting Extention File." -ForegroundColor Red } elseif ($caught -eq $false) { $msg = "Error uploading report: $reportName. Msg: '{0}'" -f $_.Exception.Detail.InnerText Write-Error $msg } } } Function SSRSDatasource ([string]$ReportPath,$DataSourceName,$DataSourcePath) { $report = $ssrsProxy.GetItemDataSources($ReportPath) ForEach ($Source in $report) { $proxyNamespace = $Source.GetType().Namespace $constDatasource = New-Object ("$proxyNamespace.DataSource") $constDatasource.Name = $DataSourceName $constDatasource.Item = New-Object ("$proxyNamespace.DataSourceReference") $constDatasource.Item.Reference = $DataSourcePath $Source.item = $constDatasource.Item $ssrsProxy.SetItemDataSources($ReportPath, $Source) Write-Host "Changing datasource `"$($Source.Name)`" to $($Source.Item.Reference)" } } ##Create Folder Structure #Create Base Folder Write-Host "Creating Folders Structure:" -ForegroundColor DarkMagenta SSRSFolder $reportFolder "/" ForEach($Folder in Get-ChildItem $SourceDirectory -Directory) { #Add each folder in the sourcefolder to the reporting service SSRSFolder $Folder.Name /$reportFolder } #Upload Reports in root folder ForEach ($rdlfile in Get-ChildItem $SourceDirectory -Filter *.rdl ) { SSRSItem Report $rdlfile /$reportFolder #Change Report Datasource $ReportPath = "/" + $reportFolder + "/" + $rdlfile.BaseName SSRSDatasource $ReportPath $DataSourceName $DataSourcePath } ##For Each folder ForEach($Folder in Get-ChildItem $SourceDirectory -Directory) { #Add each folder in the sourcefolder to the reporting service #SSRSFolder $Folder.Name /$Basefolder #Add reports in the folder ForEach ($rdlfile in Get-ChildItem $Folder -Filter *.rdl ) { SSRSItem Report $rdlfile /$reportFolder/$($folder.Name) #Change Report Datasource $ReportPath = "/" + $reportFolder + "/" + $folder.Name + "/" + $rdlfile.BaseName SSRSDatasource $ReportPath $DataSourceName $DataSourcePath } }
Great Script... Does not appear to grab sub folders as I am getting this error:
ReplyDeleteGet-ChildItem: A parameter cannot be fond that matches parameter name 'Directory'
All Reports in main sourcedirectory are uploading just fine
what version of powershell are you running?
DeleteMy first guess would be that the "Directory" parameter is not available in lower powershell versions.
Yep right on... Was running from Server 2008 R2... I ran from Server 2012 R2 and was good to go... Thanks, Great Script!
DeleteThis comment has been removed by the author.
ReplyDeleteHi, first of all thanks very much for this script, I'm learning a lot from it. I was wondering if you could point me in the direction of how to make the script include subfolders? I've been playing with the -recurse flag but I can only seem to get the subfodler reports, not the full structure.. Thanks
ReplyDeleteThis is a very helpful script, just keep in mind not everyone uses the default namespace, I would recommend adding a parameter for an instance name. Your proxy connector would need to be /ReportServer$/
ReplyDeleteIn case anyone else is coming here, Microsoft has started a github project called ReportingServicesTools that works for SQL Server 2012 and up, PowerShell 3 and up, and Windows 7 and up. You can also get it from the PowershellGallery
ReplyDeleteawesome script, saved me hours of ballache uploading 300 reports 1 by 1!!
ReplyDeleteThings I noted were....if the script is above the folder with the reports in, in my case the script was in C:\Users\LocalAdmin\Documents\Reports and the reports (all in subfolders) was in C:\Users\LocalAdmin\Documents\Reports\UAT it looked in C:\Users\LocalAdmin\Documents\Reports\\ (missing the UAT folder out) for the reports and couldnt find them, once I moved the script into the UAT folder it all worked fine, plus I removed the datasource stuff as I didnt need it.
Thank you again.
Hi there, thanks so much for the script it is great and does everything that I need. Except I really need it not to create a folder called "Demo" first as in your example. I do not wish to enter a initial report folder name to be created, the structure of the folders where the script is located is how they should be and the shouldnt be uploaded into another folder.
ReplyDeleteI have got this to partly work but it is no longer building the folder structure. I have two folders Reports 1 and Reports 1.1 the last should be in Reports 1 but it is at the same level. Please can you assist on how you would modify your script to stop the initial folder creation? I need my current structure to be created in the Home directory.
Thanks,
Glenn
Here's my own take on popular and less popular methods of internet marketing techniques free and paid, and their benefits. I also try to touch base on how to utilize them the best you can, getting the most value out of them. Remember not every method is ideal for every type of site, and a successful advertising campaign will generally contain several methods to varying degrees. ipucum
ReplyDeleteI was running this as per example but got the following error message:
ReplyDeleteNew-WebServiceProxy: the HTML document does not contain Web sevice discovery informatio
.
.
.
You cannot call a method on a null-valued expression
At C:\UploadReportsv3.ps1:135 char:9
Do you know what was wrong here?
I ran into the same issue as RicO'Shea: "You cannot call a method on a null-valued expression." Anyone else run into this?
ReplyDeleteYeah, me too.
DeleteOops, I had the filename wrong, and I had quotes around my server name. Otherwise works great except for a couple of "Exception calling "SetItemDataSources" with "2" argument(s): "The path of the item '' is not valid. The full path must be less than 260 characters long; other restrictions apply." errors. Those might be because of bad datasources.
DeleteIt only seems to go one folder deep. Has anyone found a way to make it recursive?
ReplyDeleteI ran into the same issue as RicO'Shea : You cannot call a method on a null-valued expression
ReplyDeleteAt C:\UploadReportsv3.ps1:135 char:9
Please help us on this issue.