【问题标题】:Deploy SSRS reports on a customer's machine with PowerShell使用 PowerShell 在客户机器上部署 SSRS 报告
【发布时间】:2017-11-30 18:08:57
【问题描述】:

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

到目前为止我所管理的:

一个文件夹包含:

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

更新:

下载的 rdl 文件的数据集引用设置为纯数据集的名称 - 为什么...我花了几个小时才找到,引用必须包含数据集的完整(内部)路径...现在分页报表真的有效了,heureka!

问题

这不适用于

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

如何通过 PowerShell 上传移动报告?
如何上传自定义品牌包?
有更好的方法吗?我对 PowerShell 相当陌生,因此愿意接受任何建议! TIA

编辑

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

更新:还没有答案?

在我自己的答案的底部有一些悬而未决的问题......我很想给某人赏金,但它似乎丢失了......无论如何:如果 Anybode 可以回答至少部分剩余的未解决问题问题很有可能获得 150 分 :-)

【问题讨论】:

    标签: sql-server powershell reporting-services deployment ssrs-2017


    【解决方案1】:

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

    目前我发现的问题:

    • 删除共享数据集后,必须从头开始重新创建所有移动报表(不支持重新映射数据源)。这是设计read this, if you cannot believe it
    • 仅支持部署到可访问的服务器(通过目标 URL)
    • 目前不支持通过 SSRS 门户以外的方式上传移动报告
    • 目前不支持通过 SSRS 门户上传品牌包

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

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

    假设:

    • 所有 SSRS 对象(.rsd、.rdl 和 .rsmobile)都已下载并位于“DeployDirectory”下的适当目录中
      • 在我的情况下,所有共享数据集填充都在文件夹“MyProduct Data”中
      • 就我而言,所有报告都位于“EventLog”、“Public Reports”和“Report Audit”子文件夹中
      • 可以自动化文件夹结构,但在此脚本中,这部分是硬编码以满足我的需要。
    • PowerShell 模块 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"
    

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

    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"
    

    #创建共享数据源

    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"
    

    #Modify 共享数据集文件:必须更改对服务器 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"
    

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

    $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"
    

    #修改分页报表文件:新写入的共享数据集必须写入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"
    

    #Modify 移动报告文件:这更复杂...文件实际上是 ZIP。这些 ZIP 包含多个文件。 metadata.xmlsources.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"
    

    #打开所有解压文件夹中的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"
    

    #打开所有解压文件夹中的所有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"
    

    #重命名所有原始.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"
    

    注意

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

    仍有待解决的问题:

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

    这个我可以同时回答(见第二个回答):

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

    【讨论】:

      【解决方案2】:

      上传品牌宣传包

      有了这个,我终于设法上传了一个品牌包

      此存储过程将读取和写入所有Catalog 条目:

      CREATE PROCEDURE InstallBrandingPackage
      (
          --Arguments
           @BrandingZIPPath VARCHAR(300)
          ,@BrandingColorsPath VARCHAR(300)
          ,@BrandingLogopath VARCHAR(300)
          ,@BrandingType VARCHAR(100)
          ,@BrandingName VARCHAR(100)
          ,@BrandingVersion VARCHAR(10)
      
      )
      AS
      BEGIN
          BEGIN TRANSACTION;
          SET XACT_ABORT ON;
      
          DECLARE @BrandingZIPName VARCHAR(150)=RIGHT(@BrandingZIPPath,CHARINDEX('\',REVERSE(@BrandingZIPPath))-1);
          DECLARE @BrandingZIP VARBINARY(MAX);
          DECLARE @BrandingColorsJSON VARBINARY(MAX);
          DECLARE @BrandingLogoPNG VARBINARY(MAX);
      
          CREATE TABLE #tmpBranding(FileType VARCHAR(100),Content VARBINARY(MAX));
          DECLARE @cmd VARCHAR(MAX);
          SET @cmd=
          'INSERT INTO #tmpBranding(FileType,Content)
              SELECT ''zip'',BulkColumn FROM OPENROWSET(BULK ''' + @BrandingZIPPath + ''', SINGLE_BLOB) AS x';
          EXEC(@cmd);
          SET @cmd=
          'INSERT INTO #tmpBranding(FileType,Content)
              SELECT ''colors'',BulkColumn FROM OPENROWSET(BULK ''' + @BrandingColorsPath + ''', SINGLE_BLOB) AS x';
          EXEC(@cmd);
          SET @cmd=
          'INSERT INTO #tmpBranding(FileType,Content)
              SELECT ''logo'',BulkColumn FROM OPENROWSET(BULK ''' + @BrandingLogopath + ''', SINGLE_BLOB) AS x';
          EXEC(@cmd);
      
          SET @BrandingZIP=(SELECT Content FROM #tmpBranding WHERE FileType='zip');
          SET @BrandingColorsJSON=(SELECT Content FROM #tmpBranding WHERE FileType='colors');
          SET @BrandingLogoPNG=(SELECT Content FROM #tmpBranding WHERE FileType='logo');
      
          --needed variables and IDs taken from System Resources
          DECLARE @SystemResourceID UNIQUEIDENTIFIER
                 ,@SystemResourcePath VARCHAR(500)
                 ,@PolicyID UNIQUEIDENTIFIER
                 ,@UserID UNIQUEIDENTIFIER;
          SELECT TOP 1 @SystemResourceID=ItemID
                      ,@SystemResourcePath=[Path]
                      ,@PolicyID=PolicyID 
                      ,@UserID=CreatedByID 
          FROM ReportServer.dbo.[Catalog] WHERE [Name] = 'System Resources';
      
          --Delete all existing
          DELETE FROM ReportServer.dbo.[Catalog] WHERE [Path] LIKE '%' +  @BrandingType + '%';
      
          --New Variables
          DECLARE @NewZipID UNIQUEIDENTIFIER = NEWID();
          DECLARE @NewPathID UNIQUEIDENTIFIER = NEWID();
          DECLARE @NewPath VARCHAR(100) = '/' + LOWER(CAST(NEWID() AS VARCHAR(100)));
          DECLARE @NewPathName VARCHAR(100) ='fbac82c8-9bad-4dba-929f-c04e7ca4111f'; --It seems, that this special GUID is needed, otherwise no Logo is displayed
          DECLARE @NewBrandID UNIQUEIDENTIFIER = NEWID();
          DECLARE @ColorsID UNIQUEIDENTIFIER = NEWID();
          DECLARE @LogoID UNIQUEIDENTIFIER = NEWID();
          DECLARE @dt DATETIME=GETDATE();
      
          DECLARE @BrandProperties NVARCHAR(MAX)=
          CAST((
              SELECT @BrandingType AS [Resource.Type]
                    ,@BrandingName AS [Resource.Name]
                    ,@BrandingVersion AS [Resource.Version]
                    ,LOWER(CAST(@NewZipID AS VARCHAR(100))) AS [Resource.PackageId]
                    ,LOWER(CAST(@ColorsID AS VARCHAR(100))) AS [Item.colors]
                    ,LOWER(CAST(@LogoID AS VARCHAR(100))) AS [Item.logo]
              FOR XML PATH('Properties'),TYPE
          ) AS NVARCHAR(MAX));
      
          --Universal Brand
          INSERT INTO ReportServer.dbo.[Catalog](ItemID,[Path],[Name],ParentID,[Type]
                     ,Content
                     ,Property
                     ,[Hidden],CreatedByID,CreationDate,ModifiedByID,ModifiedDate
                     ,MimeType,PolicyID,PolicyRoot,ExecutionFlag)  
          VALUES(@NewBrandID,@SystemResourcePath + '/' + @BrandingType, @BrandingType, @SystemResourceID,1
                ,NULL
                ,@BrandProperties
                ,0,@UserID,@dt,@UserID,@dt,NULL,@PolicyID,0,1);
      
          --ZIP file dummy
          DECLARE @currentPath VARCHAR(500) = @SystemResourcePath + '/' +  @BrandingType + '/' + @BrandingZIPName;
          INSERT INTO ReportServer.dbo.[Catalog](ItemID,[Path],[Name],ParentID,[Type]
                     ,Content
                     ,Property
                     ,[Hidden],CreatedByID,CreationDate,ModifiedByID,ModifiedDate
                     ,MimeType,PolicyID,PolicyRoot,ExecutionFlag)  
          VALUES(@NewZipID,@currentPath,@BrandingZIPName,@NewBrandID,3
                ,@BrandingZIP
                ,'<Properties />'
                ,0,@UserID,@dt,@UserID,@dt,'application/octet-stream',@PolicyID,0,1);
      
      
          --Brand path
          SET @currentPath = @SystemResourcePath + '/' +  @BrandingType + '/' + @NewPathName;
          INSERT INTO ReportServer.dbo.[Catalog](ItemID,[Path],[Name],ParentID,[Type]
                     ,Content
                     ,Property
                     ,[Hidden],CreatedByID,CreationDate,ModifiedByID,ModifiedDate
                     ,MimeType,PolicyID,PolicyRoot,ExecutionFlag)  
          VALUES(@NewPathID,@currentPath,@NewPathName,@NewBrandID,1
                ,NULL
                ,'<Properties />'
                ,0,@UserID,@dt,@UserID,@dt,NULL,@PolicyID,0,1);
      
          --colors
          INSERT INTO ReportServer.dbo.[Catalog](ItemID,[Path],[Name],ParentID,[Type]
                     ,Content
                     ,Property
                     ,[Hidden],CreatedByID,CreationDate,ModifiedByID,ModifiedDate
                     ,MimeType,PolicyID,PolicyRoot,ExecutionFlag)  
          VALUES(@ColorsID,@currentPath + '/colors','colors',@NewPathID,3
                ,@BrandingColorsJSON
                ,'<Properties />'
                ,0,@UserID,@dt,@UserID,@dt,'application/octet-stream',@PolicyID,0,1);
      
          --logo
          INSERT INTO ReportServer.dbo.[Catalog](ItemID,[Path],[Name],ParentID,[Type]
                     ,Content
                     ,Property
                     ,[Hidden],CreatedByID,CreationDate,ModifiedByID,ModifiedDate
                     ,MimeType,PolicyID,PolicyRoot,ExecutionFlag)  
          VALUES(@LogoID,@currentPath + '/logo','logo',@NewPathID,3
                ,@BrandingLogoPNG
                ,'<Properties />'
                ,0,@UserID,@dt,@UserID,@dt,'image/png',@PolicyID,0,1);
      
          COMMIT;
      END
      

      我使用这个 PowerShell 行解压缩包,提取参数并调用过程:

      #Unzip BrandingPackage 
      Add-Type -AssemblyName System.IO.Compression.FileSystem
      Add-Type -AssemblyName System.Collections
      $BrandingPackagePath = ($PSScriptRoot + "\FrequentisReportCenter.zip")
      $BrandingPackageUnzipped = ($PSScriptRoot + "\FrequentisReportCenter.zip.Unzipped")
      [System.IO.Compression.ZipFile]::ExtractToDirectory($BrandingPackagePath,$BrandingPackageUnzipped)
      Write-Host "BrandingPackage unzipped"
      $xml = New-Object System.Xml.XmlDocument
      $nsMngr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
      $nsMngr.AddNamespace("ns","http://schemas.microsoft.com/sqlserver/reporting/2016/01/systemresourcepackagemetadata")
      $xml.Load(($BrandingPackageUnzipped + "\" + "metadata.xml"))
      $BrandingType=$xml["SystemResourcePackage"].Attributes["type"].Value
      $BrandingVersion=$xml["SystemResourcePackage"].Attributes["version"].Value
      $BrandingName=$xml["SystemResourcePackage"].Attributes["name"].Value
      $PathColors=($BrandingPackageUnzipped + "\" + $xml.SelectNodes("//ns:Contents/ns:Item[@key='colors']",$nsMngr)[0].Attributes["path"].Value)
      $PathLogo=($BrandingPackageUnzipped + "\" + $xml.SelectNodes("//ns:Contents/ns:Item[@key='logo']",$nsMngr)[0].Attributes["path"].Value)
      #BrandingPackage values fetched
      
      $cmd.CommandText="MyDatabase.dbo.InstallBrandingPackage `
                                                        @BrandingZIPPath=@ZIPPath,`
                                                        @BrandingColorsPath=@ColorsPath,`
                                                        @BrandingLogoPath=@LogoPath,`
                                                        @BrandingType=@Type,`
                                                        @BrandingName=@Name,`
                                                        @BrandingVersion=@Version"
      $cmd.Parameters.AddWithValue("@ZIPPath",$BrandingPackagePath)
      $cmd.Parameters.AddWithValue("@ColorsPath",$PathColors)
      $cmd.Parameters.AddWithValue("@LogoPath",$PathLogo)
      $cmd.Parameters.AddWithValue("@Type",$BrandingType)
      $cmd.Parameters.AddWithValue("@Name",$BrandingName)
      $cmd.Parameters.AddWithValue("@Version",$BrandingVersion)
      $cmd.ExecuteNonQuery()
      #BrandingPackage written
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-04
        相关资源
        最近更新 更多