Развертывание отчетов SSRS на компьютере клиента с помощью PowerShell

мы разрабатываем некоторые отчеты локально. Эти отчеты должны быть установлен на машине клиента. Но мы не можем связаться с этой машиной онлайн.

Что мне удалось до сих пор:

папке, содержащей:

этот скрипт создаст все необходимые папки в ReportServer, загрузит источник данных, затем наборы данных и, наконец, отчеты. это работает, я могу открыть портал и можно увидеть мои объекты.

обновление:

загруженные файлы rdl имели набор данных-ссылки на имя простого набора данных-почему когда-либо... Мне потребовалось несколько часов, чтобы найти, что ссылка должна включать полную (внутренний) путь к набору данных... Теперь разбитые на страницы отчеты действительно работают, Эврика!

Вопросы

Это не работает для

  • мобильные отчеты (он же панели мониторинга, но не PowerBI)
  • наш файл брендинга

как мобильные отчеты могут быть загружены через PowerShell?
Как можно загрузить пользовательский пакет брендинга?
Есть ли лучший подход? Я новичок в PowerShell и поэтому открыт для любых советов! ТИА!--3-->

редактировать

удалил скрипт фрагмент, поскольку я сам опубликовал исчерпывающий ответ...

UPDATE: пока нет ответа?

в нижней части моего собственного ответа есть несколько открытых вопросов... Я бы с удовольствием отдал награду кому-нибудь, но она, кажется, потеряна... В любом случае: если Anybode может ответить хотя бы на часть оставшихся открытых вопросов, есть хороший шанс на 150 очков :-)

2 ответов


Microsoft решила оставить нас бедных технических сотрудников наедине с этим...

темы, которые я нашел до сих пор:

  • после удаления общего набора данных все мобильные отчеты должны быть созданы заново с нуля (повторное сопоставление источников данных не поддерживается). Это конструкция, прочтите это, если вы не можете в это поверить
  • развертывание поддерживается только на доступном сервере (через целевой URL)
  • там в настоящее время нет поддержки для загрузки мобильного отчета, кроме как через портал SSRS
  • в настоящее время нет поддержки для загрузки пакета брендинга, кроме как через портал SSRS

как никто, кажется, не в состоянии помочь-даже с щедростью! - Я скажу, что я нашел до сих пор:

следующий PowerShellScript является рабочим автономное развертывание на отключенной машине.

предположения:

  • все SSRS-объекты (.ОСБ. ,rdl and .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"

#изменить общие файлы набора данных: необходимо изменить жестко закодированную ссылку на 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"

#изменить файлы отчетов с разбиением на страницы: недавно написанные общие наборы данных должны быть записаны в отчет-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"

#изменить мобильные файлы отчетов: это больше сложный... Файлы на самом деле молнии. Эти молнии содержат несколько файлов. The 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"

#откройте все метаданные.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"

#открыты все источники.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"

внимание

Allthough the созданные ZIP-файлы (новые .rsmobile файлы) действительны и содержат правильный контент, невозможно загрузить их через портал SSRS (ошибка:неверный пакет отчетов). Но - довольно забавно! - при использовании explorer send to compressed directory и переименуйте полученный ZIP-файл соответственно, это можно загрузить.

вопросы:

  • как можно создать .rsmobile (ZIP-файл), что он может быть загружен? (должен быть таким же способом молнии, как windows это неявно, когда отправка в сжатую папку)
  • как можно загрузить мобильный отчет программно?

на это я мог бы ответить тем временем (см. Второй ответ):

  • как можно загрузить пакет брендинга программно?

загрузка пакета брендинга

С этим мне, наконец, удалось загрузить пакет брендинга

эта хранимая процедура будет читать и писать все 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