使用PowerShell在客户的计算机上部署SSRS报告

Shn*_*ugo 6 sql-server deployment powershell reporting-services ssrs-2017

我们正在本地开发一些报告.这些报告将安装在客户的计算机上.但是我们无法在线访问这台机器.

到目前为止我管理的内容:

一个文件夹包含:

此脚本将在ReportServer中创建所有需要的文件夹,加载数据源,然后加载数据集,最后加载报告.这工作,我可以打开门户网站,可以看到我的对象.

更新:

下载的rdl文件将其数据集引用设置为普通数据集的名称 - 为什么......我花了几个小时才发现,引用必须包含数据集的完整(内部)路径...现在分页报道确实有效,heureka!

问题

这不起作用

  • 移动报告(又称仪表板,但不是PowerBI)
  • 我们的品牌档案

如何通过PowerShell上传移动报告?
如何上传自定义品牌包?
有更好的方法吗?我是PowerShell的新手,因此可以接受任何建议!TIA

编辑

删除了脚本片段,因为我自己发布了一个全面的答案...

更新:还没有答案?

在我自己的答案的底部有一些悬而未决的问题......我很乐意给予某人赏金,但它似乎丢失了......无论如何:如果Anybode可能至少回答剩下的一些开放问题,那么就有了150分的好机会:-)

Shn*_*ugo 5

微软决定让我们这些可怜的技术人员独自处理这个......

目前我发现的问题:

  • 删除共享数据集后,必须从头开始重新创建所有移动报告(不支持数据源的重新映射)。这是设计使然如果您不相信,请阅读此内容
  • 仅支持部署到可访问的服务器(通过目标 URL)
  • 目前不支持通过 SSRS 门户上传移动报告
  • 目前不支持通过 SSRS 门户上传品牌包

因为似乎没有人能够提供帮助——即使有赏金!- 我将陈述到目前为止我发现的内容:

以下 PowerShellScript 是在断开连接的计算机上运行的独立部署。

假设:

  • 所有 SSRS 对象(.rsd、.rdl 和 .rsmobile)均已下载并位于“DeployDirectory”下的相应目录中
    • 就我而言,所有共享数据集填充都位于文件夹“MyProduct Data”中
    • 就我而言,所有报告都位于子文件夹“EventLog”、“Public Reports”和“Report Audit”中
    • 可以自动化文件夹结构,但在这个脚本中,这部分是根据我的需要进行硬编码的。
  • PowerShell-Module ReportingServicesTools 放置在“DeployDirectory”下同名的目录中
  • 共享数据集的名称是全局唯一的(SSRS 不强制要求)

祝你好运!

$DeployDirectory=".\MyProduct Reports\"
$DbURL="1.2.3.4"
$srvURI="http://1.2.3.4/ReportServer"
$srvURL="http://1.2.3.4/reports"

#Write RS Report folders
$rootDir="/MyProduct Reports"
Run Code Online (Sandbox Code Playgroud)

#导入模块并创建文件夹。这也可能是自动化的(在光盘上找到的目录结构之外,但这取决于你......)

Import-Module  .\ReportingServicesTools
New-RsFolder -ReportServerUri $srvURI -Path "/"      -Name "MyProduct Reports"
New-RsFolder -ReportServerUri $srvURI -Path $rootDir -Name "MyProduct Data" 
New-RsFolder -ReportServerUri $srvURI -Path $rootDir -Name "EventLog" 
New-RsFolder -ReportServerUri $srvURI -Path $rootDir -Name "Public Reports" 
New-RsFolder -ReportServerUri $srvURI -Path $rootDir -Name "Report Audit" 
Write-Host "RS Report folders written"
Run Code Online (Sandbox Code Playgroud)

#创建共享数据源

New-RsDataSource -RsFolder ($rootDir + "/MyProduct Data") -Name "MyProduct_DatabaseConnection" -Extension "SQL" -ConnectionString ("Data Source=" +  $DbURL + ";Integrated Security=True;Initial Catalog=master;") -CredentialRetrieval "Integrated"
Write-Host "Shared data source created"
Run Code Online (Sandbox Code Playgroud)

#修改共享数据集文件:必须更改对服务器 URL 的硬编码引用

$allRSDs = Get-ChildItem -Recurse -Path $DeployDirectory | Where-Object -FilterScript {$_.Extension -eq ".rsd"}
Write-Host "RSDs fetched"

$xml = New-Object System.Xml.XmlDocument
$nsMngr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsMngr.AddNamespace("rd","http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")
$allRSDs | % {
               $FileName=$_.FullName;
               $xml.Load($FileName);
               $xml.SelectNodes("//rd:ReportServerUrl",$nsMngr) | 
               % {$_.InnerText=$srvURI};
               $newContent = $xml.InnerXml;
               Set-Content -Path $FileName -Value $newContent
             }
Write-Host "Shared data set files modified"

Write-RsFolderContent -Recurse -ReportServerUri $srvURI -Path ($DeployDirectory + "MyProduct Data") -RsFolder ($rootDir + "/MyProduct Data") 
Write-Host "Shared DataSets created"
Run Code Online (Sandbox Code Playgroud)

#将所有创建的共享数据集从数据库中读取到表变量中

$con = New-Object System.Data.SqlClient.SqlConnection
$con.ConnectionString=("Data Source=" + $DbURL + ";Integrated Security=True;Initial Catalog=master;")
$con.Open();
Write-Host "connection opened"

$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.Connection = $con
Write-Host "command created"

$cmd.CommandText = "SELECT ItemID, [name] AS DataSetName, [Path] AS DataSetPath, LEN([name]) AS SortOrder `
                    FROM ReportServer.dbo.[Catalog]` 
                    WHERE [Type]=8"
$adapt = New-Object System.Data.SqlClient.SqlDataAdapter
$adapt.SelectCommand = $cmd
$ds = New-Object System.Data.DataSet
$adapt.Fill($ds)
$allDs = New-Object System.Data.DataTable
$allDs = $ds.Tables[0]
Write-Host "shared datasets fetched into cache"

Class shDs {[string]$ItemId=""; [string]$DataSetName=""; [string]$DataSetPath="";}
function Get-SharedDataSet([string]$DataSetName){
    $retVal = New-Object shDs
    $Search = ("'" + $DataSetName + "' LIKE DataSetName + '%'") 
    $Sort = ("SortOrder DESC")
    $dsRow = $allDs.Select($Search,$Sort)[0]
    $retVal.ItemID=$dsRow["ItemID"].ToString().Trim()
    $retVal.DataSetPath=$dsRow["DataSetPath"].ToString().Trim()
    $retVal.DataSetName=$dsRow["DataSetName"].ToString().Trim()
    return $retVal
}
Write-Host "function to fetch referenced shared dataset created"
$con.Close()
Write-Host "connection closed"
Run Code Online (Sandbox Code Playgroud)

#修改分页报告文件:新写入的共享数据集必须写入report-XML中

$allRDLs = (Get-ChildItem -Recurse -Path $DeployDirectory | 
                Where-Object -FilterScript {$_.Extension -eq ".rdl"})
$xml = New-Object System.Xml.XmlDocument
$nsMngr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsMngr.AddNamespace("rd","http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")
$nsMngr.AddNamespace("ns","http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition")
$allRDLs | % {
               $FileName=$_.FullName;
               $xml.Load($FileName);
               $xml.SelectNodes("//rd:ReportServerUrl",$nsMngr) | 
                  % {$_.InnerText=$srvURI};
               $xml.SelectNodes("//ns:SharedDataSetReference",$nsMngr) | 
                  % {
                       $it = ("/" + $_.Innertext);
                       $ref=$it.SubString($it.LastIndexOf("/")+1);
                       $ds = Get-SharedDataSet($ref);
                       $_.InnerText=$ds.DataSetPath
                       Write-Host ("DataSetPath: " + $_.InnerText)
                    };
               $newContent = $xml.InnerXml;
               Set-Content -Path $FileName -Value $newContent
             }
Write-Host "paginated report files modified"

Write-RsFolderContent -Recurse -ReportServerUri $srvURI -Path ($DeployDirectory + "EventLog") -RsFolder ($rootDir + "/EventLog") 
Write-RsFolderContent -Recurse -ReportServerUri $srvURI -Path ($DeployDirectory + "Public Reports") -RsFolder ($rootDir + "/Public Reports") 
Write-RsFolderContent -Recurse -ReportServerUri $srvURI -Path ($DeployDirectory + "Report Audit") -RsFolder ($rootDir + "/Report Audit")
Write-Host "paginated reports created"
Run Code Online (Sandbox Code Playgroud)

#修改移动报告文件:这更复杂......文件实际上是ZIP。这些 ZIP 包含多个文件。和metadata.xml包含sources.xml硬编码引用,必须更改

$allMobs = (Get-ChildItem -Recurse -Path $DeployDirectory | 
                Where-Object -FilterScript {$_.Extension -eq ".rsmobile"})

#Unzip SomeName.rsmobile into SomeName.rsmobile.Unzipped 
Add-Type -AssemblyName System.IO.Compression.FileSystem
Add-Type -AssemblyName System.Collections
$unzippedList = New-Object System.Collections.ArrayList
Class zippedMobs {[string]$DirectoryName; [string]$rsMobileName; [string]$FileName;}
Get-ChildItem -Recurse $path | 
    Where-Object -FilterScript {$_.Extension -eq ".rsmobile"} | 
    % {
       $zm = New-Object zippedMobs;
       $zm.DirectoryName = ($_.FullName + ".Unzipped");
       $zm.rsMobileName=$_.FullName;
       $zm.FileName=$_.Name;
       $unzippedList.Add($zm);
       [System.IO.Compression.ZipFile]::ExtractToDirectory($zm.rsMobileName,$zm.DirectoryName)
      }
Write-Host "Mobile Reports: Files unzipped"
Run Code Online (Sandbox Code Playgroud)

#打开所有解压文件夹中的所有metadata.xml文件并修改

$xml = New-Object System.Xml.XmlDocument
$nsMngr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsMngr.AddNamespace("ns","http://schemas.microsoft.com/sqlserver/reporting/2016/02/mobilereportpackage")
$nsMngr.AddNamespace("mrp","http://schemas.microsoft.com/sqlserver/reporting/2016/02/mobilereportpublisher")
$unzippedList | % {
         $FileName=($_.DirectoryName + "\metadata.xml");
         $xml.Load($FileName);
         $xml.SelectNodes("//ns:dataSet",$nsMngr) | 
            % {
                $ref=$_.Attributes["name"].Value;
                $ds = Get-SharedDataSet($ref);
                $_.Attributes["mrp:Server"].Value=$srvURL;
                $_["id"].InnerText=$ds.ItemID;
                $_["path"].InnerText=$ds.DataSetPath
              };
         $newContent = $xml.InnerXml;
         Set-Content -Path $FileName -Value $newContent
        }
Write-Host "Mobile Reports: All metadata.xml re-mapped"
Run Code Online (Sandbox Code Playgroud)

#打开所有解压文件夹中的所有sources.xml文件并修改

$xml = New-Object System.Xml.XmlDocument
$unzippedList | % {
         $FileName=($_.DirectoryName + "\sources.xml");
         $xml.Load($FileName);
         $xml.SelectNodes("//Shared") | 
            % { 
             $ref=$_.Attributes["Name"].Value;
             $ds = Get-SharedDataSet($ref);
             $_.Attributes["ServerUri"].Value=$srvURL; 
             $_.Attributes["Guid"].Value=$ds.ItemID;
             $_.Attributes["DataItemLocation"].Value=$ds.DataSetPath
            };
         $newContent = $xml.InnerXml; 
         Set-Content -Path $FileName -Value $newContent
        }
Write-Host "Mobile Reports: All sources.xml re-mapped"
Run Code Online (Sandbox Code Playgroud)

#重命名所有原始.rsmobile文件

$unzippedList | % {Rename-Item -Path $_.rsMobileName -NewName ($_.FileName + ".old")}
Write-Host "Mobile Reports: Renamed all orginal .rsmobile files"
#Create new ZIP file for all mobile reports
$unzippedList | % {
                   [System.IO.Compression.ZipFile]::CreateFromDirectory($_.DirectoryName,$_.rsMobileName,[System.IO.Compression.CompressionLevel]::NoCompression, $FALSE)
                  }
Write-Host "Re-created all mobile report files"
Run Code Online (Sandbox Code Playgroud)

注意力

尽管创建的 ZIP 文件(新.rsmobile文件)有效且包含正确的内容,但无法通过 SSRS 门户上传它们(错误:无效的报告包)。但是——够有趣的了!- 当您使用资源管理器send to compressed directory并相应地重命名生成的 ZIP 文件时,可以上传该文件。

仍有待解决的问题:

  • 如何创建可.rsmobile上传的(ZIP 文件)?(必须与Windows在发送到压缩文件夹时隐式压缩的方式相同)
  • 如何以编程方式上传移动报告?

我可以同时回答这个问题(参见第二个答案):

  • 如何以编程方式上传品牌包?