Uninstall SQL Server Reporting Services 2019

First and foremost, remove and decommission unused / idle services without waiting! They consume resources such as storage, computing power, url reservations et cetera. Nothing is free.

I wouldn’t write a blog post about removing SSRS in normal conditions. However, SQL Server Reporting Services is a separate service now, starting from SQL 2017. That means few things:

  • It is not in SQL Server Installation Media anymore (Like SSMS)
  • It is a separate service now under Services
  • Hence, SSRS is an individual item on “Control Panel – Programs and Feature”

Before SQL 2017, we used to remove components like SSRS, SSIS and SSAS by clicking Microsoft SQL Server 20XX (Version bit) item but now as described above, you need to find and choose “Microsoft SQL Server Reporting Services”, then click “Uninstall/Change”. The rest is Microsoft’s new interface and just one click.

Disable Print and Export Data Buttons for PowerBI Report Server

Here we are again with another Power BI Report Server post. Last time I explained how to disable Download button in this post. This time, we will take a look on how to disable Print button and Export Data options.

Disable Print Button

Just like we did for download button, this is also possible via changing server properties. Before disabling, let me show you “Print Button”

 Steps:

  1. Open SSMS, choose “Reporting Services” for Server Type and connect to Reporting Service as shown in Figure 2. You may also use Web Portal/Service URL to connect to it.
  2. Right-click on Servername in Object Explorer and click Properties.
  3. Click “Advanced” Tab
  4. Under “Other” section, Set “EnableClientPrinting” to False.
It is a dropdown menu, simply click and change from “True” to “False”

PS: You don’t need to restart Power BI Reporting Service or your server. Just refresh the page.

Voilà! Now it is gone.

Disable Export Data Options

This is a bit more complex. There isn’t a simple switch that we can change and hide “Export Drop Down menu”. Again, let me show you this button.

I spend quite some time to find a way to disable this cute floppy disk button but I couldn’t find. Nonetheless, There is another nasty method to hide options via editing Reporting Service config file.

 Steps:

  1. Locate your configuration file “RSReportServer.config”. Normally it would be under your installation path i.e. “C:\Program Files\Microsoft Power BI Report Server\PBIRS\ReportServer”
  2. Open it with any text editor(Wordpad,Notepad et cetera) and search for “<Render” [Look at the screenshot#1 below]. This is the code section that we are interested. You will see various <Extension> objects under <Render> parent tag.
  3. Add ‘ Visible=”false” ‘ at the end of each <Extension> object [Look at the screenshot#2 below]
  4. Save the changes and close configuration file
  5. Restart Power BI Reporting Services from Services vmi
Find Render section
Change Visible attribute to hide export data options

You can also copy below code if you are too lazy.

    <Render>
      <Extension Name="WORDOPENXML" Type="Microsoft.ReportingServices.Rendering.WordRenderer.WordOpenXmlRenderer.WordOpenXmlDocumentRenderer,Microsoft.ReportingServices.WordRendering" Visible="false" />
      <Extension Name="WORD" Type="Microsoft.ReportingServices.Rendering.WordRenderer.WordDocumentRenderer,Microsoft.ReportingServices.WordRendering" Visible="false" />
      <Extension Name="EXCELOPENXML" Type="Microsoft.ReportingServices.Rendering.ExcelOpenXmlRenderer.ExcelOpenXmlRenderer,Microsoft.ReportingServices.ExcelRendering" Visible="false" />
      <Extension Name="EXCEL" Type="Microsoft.ReportingServices.Rendering.ExcelRenderer.ExcelRenderer,Microsoft.ReportingServices.ExcelRendering" Visible="false" />
      <Extension Name="PPTX" Type="Microsoft.ReportingServices.Rendering.PowerPointRendering.PptxRenderingExtension,Microsoft.ReportingServices.PowerPointRendering" Visible="false" />
      <Extension Name="PDF" Type="Microsoft.ReportingServices.Rendering.ImageRenderer.PDFRenderer,Microsoft.ReportingServices.ImageRendering" Visible="false" />
      <Extension Name="IMAGE" Type="Microsoft.ReportingServices.Rendering.ImageRenderer.ImageRenderer,Microsoft.ReportingServices.ImageRendering" Visible="false" />
      <Extension Name="MHTML" Type="Microsoft.ReportingServices.Rendering.HtmlRenderer.MHtmlRenderingExtension,Microsoft.ReportingServices.HtmlRendering" Visible="false">
        <Configuration>
          <DeviceInfo>
            <DataVisualizationFitSizing>Approximate</DataVisualizationFitSizing>
          </DeviceInfo>
        </Configuration>
      </Extension>
      <Extension Name="CSV" Type="Microsoft.ReportingServices.Rendering.DataRenderer.CsvReport,Microsoft.ReportingServices.DataRendering" Visible="false" />
      <Extension Name="XML" Type="Microsoft.ReportingServices.Rendering.DataRenderer.XmlDataReport,Microsoft.ReportingServices.DataRendering" Visible="false" />
      <Extension Name="ATOM" Type="Microsoft.ReportingServices.Rendering.DataRenderer.AtomDataReport,Microsoft.ReportingServices.DataRendering" Visible="false" />
      <Extension Name="NULL" Type="Microsoft.ReportingServices.Rendering.NullRenderer.NullReport,Microsoft.ReportingServices.NullRendering" Visible="false" />
      <Extension Name="RGDI" Type="Microsoft.ReportingServices.Rendering.ImageRenderer.RGDIRenderer,Microsoft.ReportingServices.ImageRendering" Visible="false" />
      <Extension Name="HTML4.0" Type="Microsoft.ReportingServices.Rendering.HtmlRenderer.Html40RenderingExtension,Microsoft.ReportingServices.HtmlRendering" Visible="false">
        <Configuration>
          <DeviceInfo>
            <DataVisualizationFitSizing>Approximate</DataVisualizationFitSizing>
          </DeviceInfo>
        </Configuration>
      </Extension>
      <Extension Name="HTML5" Type="Microsoft.ReportingServices.Rendering.HtmlRenderer.Html5RenderingExtension,Microsoft.ReportingServices.HtmlRendering" Visible="false">
        <Configuration>
          <DeviceInfo>
            <DataVisualizationFitSizing>Approximate</DataVisualizationFitSizing>
          </DeviceInfo>
        </Configuration>
      </Extension>
      <Extension Name="RPL" Type="Microsoft.ReportingServices.Rendering.RPLRendering.RPLRenderer,Microsoft.ReportingServices.RPLRendering" Visible="false" LogAllExecutionRequests="false" />
    </Render>

After restarting “Power BI Report Server” service and refresh your report, you will see that button is still there but there is no dropdown menu anymore since we disabled all options.

Until next challenge, stay safe.

PowerBI Reporting Services: How to get a previous version of overwritten report

It is 2020 and Microsoft still didn’t give us version control for reports, I invite you to take a moment of silence with for this nonsense.

You are working on your fancy powerbi report to impress management yourself and listening “Chemical Brothers-Galvanise” because you are just a cool kid. You added new features, it is time to update production report and publish it on PowerBI Report Server. You are feeling good and chorus is coming, your finger is on the button. You can’t wait anymore and “PUSH THAT BUTTON!“. Oops, you did it again. You accidentally overwrote your report with an older version and now wondering how you are going to get your report back. You are confident that somewhere on internet, someone should have blogged about this, after all you can’t be the only one! Well, you are an oracle.

I will give 2 PowerShell scripts for 2 different scenarios:

1- Rebuild a single RDL file: You are only interested in recovering one single RDL file

2- Rebuild all files(RDL,PBIX,RDS)

You need to perform a few steps for first scenario and adjust it according to your needs. I will explain the general idea, important tables to give an idea about the logic to individuals with no prior experience on this matter.

Preparation

First of all, Due to the fact that you published the report and persisted it to database, you have to find an old backup of Reporting Service database and restore it with a different name.

USE [master]
RESTORE DATABASE [REPORTSERVER_DATABASE_NAME] FROM  DISK = N'D:\REPORTSERVER_DATABASE_NAME.bak' WITH  FILE = 1,  STATS = 5
GO

Now we have our desired version of the report in the database.

Reports are stored in your PowerBI Report Server database on Microsoft SQL Server instance, in [Catalog] and [CatalogItemExtendedContent] tables. Feel free to check both table’s designs and explore.

Scenario 1

If you are working on scenario 1,you have to identify your report’s unique item identifier first and build the SQL query to retrieve necessary information from database tables to rebuild it.

We will note down [Catalog].[ItemID] of the report to use it as an unique filter in PowerShell script.

SELECT	[Catalog].[Path]
     , [Catalog].[ItemID]
FROM dbo.[Catalog] 

This query will return the data we need to rebuild specific RDL report.

SELECT	[Catalog].[Path]
        ,[Catalog].[Type]
	,ISNULL([CatalogItemExtendedContent].ContentType,'SSRS') as ContentType
        ,CONVERT(varbinary(max), [Catalog].[Content]) AS RDL_BinaryContent
FROM dbo.[Catalog] 
LEFT OUTER JOIN dbo.[CatalogItemExtendedContent] 
ON [Catalog].ItemID = [CatalogItemExtendedContent].ItemId
WHERE [Catalog].ItemID ='YOUR_REPORTS_ITEM_ID'

We are now ready to use our Powershell magic. You have to fill 4 variables into PS script:

  • SQL Server Instance Name
  • Reporting Service Database Name
  • Windows File Path to Export Files
  • Report Item Identifier

Be aware: The account runs this code needs SELECT permission on the ReportServer database!

# Set the variables!
[string] $server   = "$SQLINSTANCENAME";    
[string] $database = "$REPORTSERVER_DATABASE_NAME";       
[string] $folder   = "$EXPORT_PATH";  
  
# Extract data from report server database
$sql = "SELECT	[Catalog].[Path]
        ,[Catalog].[Type]
	,ISNULL([CatalogItemExtendedContent].ContentType,'SSRS') as ContentType
        ,CONVERT(varbinary(max), [Catalog].[Content]) AS RDL_BinaryContent
FROM dbo.[Catalog] 
LEFT OUTER JOIN dbo.[CatalogItemExtendedContent] 
ON [Catalog].ItemID = [CatalogItemExtendedContent].ItemId
WHERE [Catalog].ItemID ='YOUR_REPORTS_ITEM_ID'";		

Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Process started");
 
# Create Database Connection Object
# This script use Kerberos Authentication with executer's Windows credentials, If you'd like to use SQL Authentication, adjust it accordingly!
$connection = New-Object Data.SqlClient.SqlConnection;
$connection.ConnectionString = "Data Source=$server;Initial Catalog=$database;Integrated Security=True;";
$connection.Open();

Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Connection has been established with database");

# Build SQL Command Object
$command = New-Object Data.SqlClient.SqlCommand $sql, $connection;
$reader = $command.ExecuteReader();

$invalids = [System.IO.Path]::GetInvalidFileNameChars();

# Looping through all selected datasets.

While ($reader.Read())
{
    Try
    {
        $name = $reader.GetString(0);
		Write-Output "Reading $name"
        foreach ($invalid in $invalids)
           {    $name = $name.Replace($invalid, "-");    }

        If ($reader.GetInt32(1) -eq 2)
            {    $name = $name + ".rdl";    }
        ElseIf ($reader.GetInt32(1) -eq 5)
            {    $name = $name + ".rds";    }
        ElseIf ($reader.GetInt32(1) -eq 8)
            {    $name = $name + ".rsd";    }
        ElseIf ($reader.GetInt32(1) -eq 11)
            {    $name = $name + ".kpi";    }
        ElseIf ($reader.GetInt32(1) -eq 13)
	    {   $name = $name + ".pbix";    }

			
			
        Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Exporting {0}" -f $name);

        $name = [System.IO.Path]::Combine($folder, $name);

        # New BinaryWriter; existing file will be overwritten.
        $fs = New-Object System.IO.FileStream ($name), Create, Write;

        $BinaryWriter = New-Object System.IO.BinaryWriter($fs);

        # Read Content 
		$BinaryContent = $reader.GetSqlBinary(3).Value;
		
		
        $BinaryWriter.Write($BinaryContent, 0, $BinaryContent.Length);
        $BinaryWriter.Flush();
        $BinaryWriter.Close();
        $fs.Close();
    }
    Catch
    {
        Write-Output ($_.Exception.Message)
    }
    Finally
    {
        $fs.Dispose();
    }
}

# Cleanup
$reader.Close();
$command.Dispose();
$connection.Close();
$connection.Dispose();

Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Process Finished");

Now go and check your export folder. You successfully restored your report and saved your valuable time!

Scenario 2

Maybe you need more than one file or just want to be safe and rebuild everything. Then, welcome to scenario 2. this is more straight forward compared to first one. After restoring database, you can execute below PowerShell script directly. All you need to do, set the variables:

  • SQL Server Instance Name
  • Reporting Service Database Name
  • Windows File Path to Export Files

Be aware: The account runs this code needs SELECT permission on the ReportServer database!

# Set the variables!
[string] $server   = "$SQLINSTANCENAME";    
[string] $database = "$REPORTSERVER_DATABASE_NAME";       
[string] $folder   = "$EXPORT_PATH";  
        
# Extract data from report server database 
$sql = "SELECT	CT.[Path]
        ,CT.[Type]
		,ISNULL(cc.ContentType,'SSRS') as ContentType
        ,CONVERT(varbinary(max), cc.[Content]) AS PBI_BinaryContent
        ,CONVERT(varbinary(max), ct.[Content]) AS RDL_BinaryContent
FROM dbo.[Catalog] AS CT
		LEFT OUTER JOIN dbo.CatalogItemExtendedContent cc
			ON ct.ItemID = cc.ItemId
WHERE CT.[Type] IN (2, 8, 5,13)
	AND ISNULL(cc.ContentType,'CatalogItem') = 'CatalogItem'";		
 
 
Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Process Started");

# Create Database Connection Object
# This script use Kerberos Authentication with executer's Windows credentials, If you'd like to use SQL Authentication, adjust it accordingly!
$connection = New-Object Data.SqlClient.SqlConnection;
$connection.ConnectionString = "Data Source=$server;Initial Catalog=$database;Integrated Security=True;";
$connection.Open();


Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Connection has been established with database");

# Build SQL Command Object
$command = New-Object Data.SqlClient.SqlCommand $sql, $connection;
$reader = $command.ExecuteReader();

$invalids = [System.IO.Path]::GetInvalidFileNameChars();
 
# Looping through all selected datasets.

While ($reader.Read())
{
    Try
    { 
        $name = $reader.GetString(0);
		Write-Output "Reading $name"
        foreach ($invalid in $invalids)
           {    $name = $name.Replace($invalid, "-");    }

        If ($reader.GetInt32(1) -eq 2)
            {    $name = $name + ".rdl";    }
        ElseIf ($reader.GetInt32(1) -eq 5)
            {    $name = $name + ".rds";    }
        ElseIf ($reader.GetInt32(1) -eq 8)
            {    $name = $name + ".rsd";    }
        ElseIf ($reader.GetInt32(1) -eq 11)
            {    $name = $name + ".kpi";    }
        ElseIf ($reader.GetInt32(1) -eq 13)
	    {   $name = $name + ".pbix";    }

			
        Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Exporting {0}" -f $name);

        $name = [System.IO.Path]::Combine($folder, $name);

        # New BinaryWriter; existing file will be overwritten.
        $fs = New-Object System.IO.FileStream ($name), Create, Write;

        $BinaryWriter = New-Object System.IO.BinaryWriter($fs);

        # Read Content 
        if ($reader.GetString(2) -eq "SSRS") {
			$BinaryContent = $reader.GetSqlBinary(4).Value;
		} else{
			$BinaryContent = $reader.GetSqlBinary(3).Value;
		}
		
		
        $BinaryWriter.Write($BinaryContent, 0, $BinaryContent.Length);
        $BinaryWriter.Flush();
        $BinaryWriter.Close();
        $fs.Close();
    }
    Catch
    {
        Write-Output ($_.Exception.Message)
    }
    Finally
    {
        $fs.Dispose();
    }
}

# Cleanup
$reader.Close();
$command.Dispose();
$connection.Close();
$connection.Dispose();


Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) + ": Process Finished");

Hope this small script will save your valuable time.

Disable Download Button in Power BI Report Server

We are using on premise Power BI solution to give insights to analysts about company data and create fancy dashboards for management. We are publishing reports to Power BI Reporting Service. By default, end users can download reports using “Download” Button located at the right top of the portal.

Download button
Download Button 

Due to security concerns, we decided to disable/hide this “Download” button in Power BI Reporting Server. After a quick research, it turns out to be able to do that, you have to set the system property “ShowDownloadMenu ” to false. Cool, how can we do that?

According to below discussion, you can do this via Management Studio in SSRS 2017.

Disable Download buttons in Power BI Report Server

So, it looks pretty straight-forward. I listed steps below:

  1. Open SSMS, choose “Reporting Services” for Server Type and connect to Reporting Service as shown in Figure 2. You may also use Web Portal/Service URL to connect to it.
  2. Right-click on Servername in Object Explorer and click Properties.
  3. Click “Advanced” Tab and Set “ShowDownloadMenu” to False.
Connection

Easy peasy, right? Not that easy if you fall to the same trap like me. That is the reason why I write this blog post.

Based on my experience, this sort of binary fields in SSMS GUI which manages server/database level settings always set with a Dropdown list. For instance, Recovery model, Auto-Shrink, Auto-Close, Compatibility Level and so on. When you select this setting fields, you see a little arrow at the end of the line to change this setting as in below screenshot, or you basically click two times on the setting and it will change its value.

Arrow

I was trying to get the dropdown list to change it from true to False but it looked like a read-only field. Double click alsodidn’t work. I was searching on forums, trying to give more rights to my account. I even tried to connect with service account to see if it is able to change it. No luck.

FIX:

It took me half an hour to realize this field is not a Dropdown list, instead a simple text box which can be edited directly.  Seriously? How much effort needed to make it a list or changeable by double-clicking like it has been for ages? Poor design from SSMS team in my humble opinion, due to the fact that other settings are indeed dropdown list and has tiny arrow ON THE SAME GUI.

Arrow2
Arrow3