Skip to content

Commit 4eae9db

Browse files
authored
Improve integration tests for RS Service Account (#2404)
1 parent f9c6fd6 commit 4eae9db

19 files changed

+1971
-180
lines changed

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
### Added
99

10+
- SqlServerDsc
11+
- Added class `ReportServerUri` to represent URLs returned by the
12+
`GetReportServerUrls` CIM method on `MSReportServer_Instance`.
13+
- Added public command `Get-SqlDscRSUrl` to get the Report Server URLs for
14+
SQL Server Reporting Services or Power BI Report Server. This command
15+
invokes the `GetReportServerUrls` CIM method on `MSReportServer_Instance`
16+
and returns an array of `ReportServerUri` objects containing the instance
17+
name, application name, and URL for each configured URL.
18+
- Added public command `Get-SqlDscRSConfigFile` to get the RsReportServer.config
19+
configuration file for SQL Server Reporting Services (SSRS) or Power BI
20+
Report Server (PBIRS) as an XML document object. Supports three parameter
21+
sets: `ByInstanceName` (looks up path via registry), `ByConfiguration`
22+
(accepts pipeline input from `Get-SqlDscRSSetupConfiguration`), and `ByPath`
23+
(reads from a direct file path). The returned XML object supports standard
24+
XML navigation and XPath queries for accessing configuration settings.
1025
- Added public command `Get-SqlDscRSLogPath` to get the log file folder path
1126
for SQL Server Reporting Services or Power BI Report Server. Returns the
1227
ErrorDumpDirectory from the instance's setup configuration, which can be
@@ -194,6 +209,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
194209
for SQL Server Reporting Services or Power BI Report Server. Supports waiting
195210
for dependent services, configurable wait time, and accepts pipeline input
196211
from `Get-SqlDscRSConfiguration`.
212+
- Added public command `New-SqlDscRSEncryptionKey` to delete and regenerate the
213+
Reporting Services encryption key. Wraps the `DeleteEncryptionKey` CIM method.
214+
Warning: This operation cannot be undone and renders all encrypted content
215+
unreadable.
216+
- Added public command `Remove-SqlDscRSEncryptionKey` to remove all encrypted
217+
content from the report server database. Wraps the `DeleteEncryptionKey` CIM
218+
method with `DeleteEncryptedContent` mode.
219+
- Added public command `Remove-SqlDscRSEncryptedInformation` to remove all encrypted
220+
information from the report server database, including stored credentials and
221+
connection strings. Wraps the `DeleteEncryptedInformation` CIM method.
197222
- Added public commands `Get-SqlDscRSServiceAccount` and
198223
`Set-SqlDscRSServiceAccount` to get and set the Windows service account for
199224
SQL Server Reporting Services or Power BI Report Server. `Set-SqlDscRSServiceAccount`
@@ -213,6 +238,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
213238
- Added wiki article `Troubleshooting-Report-Server` documenting how to
214239
retrieve and analyze log files and Windows event logs for Power BI Report
215240
Server and SQL Server Reporting Services.
241+
- Updated wiki article `Change-Report-Server-Service-Account` with SQL Server
242+
2017 specific workflow. SQL Server 2017 RS requires using
243+
`Remove-SqlDscRSEncryptedInformation` and `Set-SqlDscRSDatabaseConnection`
244+
instead of `Remove-SqlDscRSEncryptionKey` and `New-SqlDscRSEncryptionKey`
245+
which fail with "rsCannotValidateEncryptedData" and "Keyset does not exist"
246+
errors on SQL Server 2017.
216247

217248
### Changed
218249

azure-pipelines.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,20 @@ stages:
143143
$pesterConfig.Run.Path = '.\tests\QA'
144144
$pesterConfig.Run.Throw = $true
145145
$pesterConfig.Output.Verbosity = 'Detailed'
146+
$pesterConfig.TestResult.Enabled = $true
147+
$pesterConfig.TestResult.OutputFormat = 'NUnitXml'
148+
$pesterConfig.TestResult.OutputPath = ".\$(buildFolderName)\$(testResultFolderName)\NUnit_QA.xml"
146149
147150
Invoke-Pester -Configuration $pesterConfig
148151
name: qualityTest
149152
displayName: 'Run SqlServerDsc QA Test'
153+
- task: PublishTestResults@2
154+
displayName: 'Publish Test Results'
155+
condition: succeededOrFailed()
156+
inputs:
157+
testResultsFormat: 'NUnit'
158+
testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit_QA.xml'
159+
testRunTitle: 'QA'
150160

151161
- job: Test_HQRM
152162
displayName: 'HQRM Test'
@@ -570,15 +580,18 @@ stages:
570580
'tests/Integration/Commands/Restart-SqlDscRSService.Integration.Tests.ps1'
571581
'tests/Integration/Commands/Test-SqlDscRSInitialized.Integration.Tests.ps1'
572582
'tests/Integration/Commands/Get-SqlDscRSLogPath.Integration.Tests.ps1'
583+
'tests/Integration/Commands/Get-SqlDscRSConfigFile.Integration.Tests.ps1'
573584
# Group 4
574585
'tests/Integration/Commands/Initialize-SqlDscRS.Integration.Tests.ps1'
575586
# Group 5 - Post-initialization validation
576587
'tests/Integration/Commands/Post.Initialization.RS.Integration.Tests.ps1'
588+
'tests/Integration/Commands/Get-SqlDscRSUrl.Integration.Tests.ps1'
577589
# Group 6 - Service account change
578590
'tests/Integration/Commands/Set-SqlDscRSServiceAccount.Integration.Tests.ps1'
579591
'tests/Integration/Commands/Get-SqlDscRSServiceAccount.Integration.Tests.ps1'
580592
'tests/Integration/Commands/Post.DatabaseRights.RS.Integration.Tests.ps1'
581593
'tests/Integration/Commands/Post.EncryptedInformation.RS.Integration.Tests.ps1'
594+
'tests/Integration/Commands/Post.DatabaseConnection.RS.Integration.Tests.ps1'
582595
'tests/Integration/Commands/Remove-SqlDscRSEncryptionKey.Integration.Tests.ps1'
583596
'tests/Integration/Commands/New-SqlDscRSEncryptionKey.Integration.Tests.ps1'
584597
'tests/Integration/Commands/Post.UrlReservationRecreate.RS.Integration.Tests.ps1'
@@ -668,10 +681,12 @@ stages:
668681
'tests/Integration/Commands/Restart-SqlDscRSService.Integration.Tests.ps1'
669682
'tests/Integration/Commands/Test-SqlDscRSInitialized.Integration.Tests.ps1'
670683
'tests/Integration/Commands/Get-SqlDscRSLogPath.Integration.Tests.ps1'
684+
'tests/Integration/Commands/Get-SqlDscRSConfigFile.Integration.Tests.ps1'
671685
# Group 4
672686
'tests/Integration/Commands/Initialize-SqlDscRS.Integration.Tests.ps1'
673687
# Group 5 - Post-initialization validation
674688
'tests/Integration/Commands/Post.Initialization.RS.Integration.Tests.ps1'
689+
'tests/Integration/Commands/Get-SqlDscRSUrl.Integration.Tests.ps1'
675690
# Group 6 - Service account change
676691
'tests/Integration/Commands/Set-SqlDscRSServiceAccount.Integration.Tests.ps1'
677692
'tests/Integration/Commands/Get-SqlDscRSServiceAccount.Integration.Tests.ps1'
@@ -684,6 +699,7 @@ stages:
684699
# Group 8
685700
'tests/Integration/Commands/Repair-SqlDscPowerBIReportServer.Integration.Tests.ps1'
686701
'tests/Integration/Commands/Remove-SqlDscRSUrlReservation.Integration.Tests.ps1'
702+
'tests/Integration/Commands/Remove-SqlDscRSEncryptedInformation.Integration.Tests.ps1'
687703
# Group 9
688704
'tests/Integration/Commands/Uninstall-SqlDscPowerBIReportServer.Integration.Tests.ps1'
689705
)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<#
2+
.SYNOPSIS
3+
Represents a Reporting Services URL returned by the GetReportServerUrls
4+
CIM method.
5+
6+
.DESCRIPTION
7+
This class represents a URL for a Reporting Services application, including
8+
the instance name, application name (such as ReportServerWebService or
9+
ReportServerWebApp), and the URL itself.
10+
11+
.PARAMETER InstanceName
12+
The name of the Reporting Services instance.
13+
14+
.PARAMETER ApplicationName
15+
The name of the Reporting Services application. Common values include:
16+
- ReportServerWebService
17+
- ReportServerWebApp
18+
- ReportManager (for older versions)
19+
20+
.PARAMETER Uri
21+
The URL for accessing the Reporting Services application.
22+
23+
.EXAMPLE
24+
[ReportServerUri]::new()
25+
26+
Creates a new empty ReportServerUri instance.
27+
28+
.EXAMPLE
29+
$uri = [ReportServerUri]::new()
30+
$uri.InstanceName = 'SSRS'
31+
$uri.ApplicationName = 'ReportServerWebService'
32+
$uri.Uri = 'http://localhost:80/ReportServer'
33+
34+
Creates a new ReportServerUri instance with property values.
35+
#>
36+
class ReportServerUri
37+
{
38+
[System.String]
39+
$InstanceName
40+
41+
[System.String]
42+
$ApplicationName
43+
44+
[System.String]
45+
$Uri
46+
47+
ReportServerUri()
48+
{
49+
}
50+
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
<#
2+
.SYNOPSIS
3+
Gets the RsReportServer.config configuration file as an XML object.
4+
5+
.DESCRIPTION
6+
Gets the RsReportServer.config configuration file for SQL Server
7+
Reporting Services (SSRS) or Power BI Report Server (PBIRS) as an
8+
XML document object. This allows programmatic access to configuration
9+
settings using standard XML navigation or XPath queries.
10+
11+
The configuration file path is automatically determined from the
12+
instance's setup configuration in the registry when using the
13+
`InstanceName` or `SetupConfiguration` parameter. Alternatively, a direct
14+
file path can be specified using the `Path` parameter.
15+
16+
.PARAMETER InstanceName
17+
Specifies the name of the Reporting Services instance. This is typically
18+
'SSRS' for SQL Server Reporting Services or 'PBIRS' for Power BI Report
19+
Server. This parameter is mandatory when not passing a configuration object
20+
or a direct path.
21+
22+
.PARAMETER SetupConfiguration
23+
Specifies the configuration object from `Get-SqlDscRSSetupConfiguration`.
24+
This can be piped from `Get-SqlDscRSSetupConfiguration`. The object must
25+
have a `ConfigFilePath` property containing the path to the configuration
26+
file. This parameter accepts pipeline input.
27+
28+
.PARAMETER Path
29+
Specifies the direct path to the RsReportServer.config file. Use this
30+
parameter to read configuration files from non-standard locations or
31+
backup copies.
32+
33+
.EXAMPLE
34+
Get-SqlDscRSConfigFile -InstanceName 'SSRS'
35+
36+
Returns the rsreportserver.config file content as an XML object for
37+
the SSRS instance.
38+
39+
.EXAMPLE
40+
Get-SqlDscRSConfigFile -InstanceName 'PBIRS'
41+
42+
Returns the rsreportserver.config file content as an XML object for
43+
the Power BI Report Server instance.
44+
45+
.EXAMPLE
46+
Get-SqlDscRSSetupConfiguration -InstanceName 'SSRS' | Get-SqlDscRSConfigFile
47+
48+
Gets the setup configuration for SSRS and pipes it to Get-SqlDscRSConfigFile
49+
to retrieve the configuration file as XML.
50+
51+
.EXAMPLE
52+
Get-SqlDscRSConfigFile -Path 'C:\Backup\rsreportserver.config'
53+
54+
Reads the configuration file from the specified path.
55+
56+
.EXAMPLE
57+
$config = Get-SqlDscRSConfigFile -InstanceName 'SSRS'
58+
$config.Configuration.Service.IsSchedulingService
59+
60+
Gets the config file and accesses the scheduling service setting directly
61+
using dot notation.
62+
63+
.EXAMPLE
64+
$config = Get-SqlDscRSConfigFile -InstanceName 'SSRS'
65+
$config.SelectSingleNode('//Authentication/AuthenticationTypes')
66+
67+
Uses XPath to query the authentication types configuration section.
68+
69+
.EXAMPLE
70+
$config = Get-SqlDscRSConfigFile -InstanceName 'SSRS'
71+
$config.SelectNodes('//Extension[@Name]') | ForEach-Object { $_.Name }
72+
73+
Uses XPath to list all extension names defined in the configuration.
74+
75+
.EXAMPLE
76+
$config = Get-SqlDscRSConfigFile -InstanceName 'SSRS'
77+
$config.Configuration.URLReservations.Application |
78+
Where-Object { $_.Name -eq 'ReportServerWebService' } |
79+
Select-Object -ExpandProperty URLs
80+
81+
Gets the URL reservations for the Report Server Web Service application.
82+
83+
.EXAMPLE
84+
$config = Get-SqlDscRSConfigFile -InstanceName 'SSRS'
85+
$smtpServer = $config.SelectSingleNode('//RSEmailDPConfiguration/SMTPServer')
86+
if ($smtpServer) { $smtpServer.InnerText }
87+
88+
Uses XPath to retrieve the SMTP server configuration for email delivery.
89+
90+
.INPUTS
91+
`System.Object`
92+
93+
Accepts the setup configuration object from `Get-SqlDscRSSetupConfiguration` via
94+
pipeline.
95+
96+
.OUTPUTS
97+
`System.Xml.XmlDocument`
98+
99+
Returns the configuration file content as an XML document object.
100+
101+
.NOTES
102+
For more information about the RsReportServer.config configuration file,
103+
see the Microsoft documentation:
104+
https://learn.microsoft.com/en-us/sql/reporting-services/report-server/rsreportserver-config-configuration-file
105+
#>
106+
function Get-SqlDscRSConfigFile
107+
{
108+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input and XPath the rule cannot validate.')]
109+
[CmdletBinding(DefaultParameterSetName = 'ByInstanceName')]
110+
[OutputType([System.Xml.XmlDocument])]
111+
param
112+
(
113+
[Parameter(Mandatory = $true, ParameterSetName = 'ByInstanceName')]
114+
[System.String]
115+
$InstanceName,
116+
117+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByConfiguration')]
118+
[System.Object]
119+
$SetupConfiguration,
120+
121+
[Parameter(Mandatory = $true, ParameterSetName = 'ByPath')]
122+
[System.String]
123+
$Path
124+
)
125+
126+
process
127+
{
128+
$configFilePath = $null
129+
130+
switch ($PSCmdlet.ParameterSetName)
131+
{
132+
'ByInstanceName'
133+
{
134+
Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigFile_GettingConfigFile -f $InstanceName)
135+
136+
$setupConfiguration = Get-SqlDscRSSetupConfiguration -InstanceName $InstanceName
137+
138+
if (-not $setupConfiguration)
139+
{
140+
$errorMessage = $script:localizedData.Get_SqlDscRSConfigFile_InstanceNotFound -f $InstanceName
141+
142+
$errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'GSRSCF0001' -ErrorCategory 'ObjectNotFound' -TargetObject $InstanceName
143+
144+
$PSCmdlet.ThrowTerminatingError($errorRecord)
145+
}
146+
147+
if ([System.String]::IsNullOrEmpty($setupConfiguration.ConfigFilePath))
148+
{
149+
$errorMessage = $script:localizedData.Get_SqlDscRSConfigFile_ConfigFilePathNotFound -f $InstanceName
150+
151+
$errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'GSRSCF0002' -ErrorCategory 'ObjectNotFound' -TargetObject $InstanceName
152+
153+
$PSCmdlet.ThrowTerminatingError($errorRecord)
154+
}
155+
156+
$configFilePath = $setupConfiguration.ConfigFilePath
157+
}
158+
159+
'ByConfiguration'
160+
{
161+
Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigFile_GettingConfigFile -f $SetupConfiguration.InstanceName)
162+
163+
if ([System.String]::IsNullOrEmpty($SetupConfiguration.ConfigFilePath))
164+
{
165+
$errorMessage = $script:localizedData.Get_SqlDscRSConfigFile_ConfigFilePathNotFound -f $SetupConfiguration.InstanceName
166+
167+
$errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'GSRSCF0002' -ErrorCategory 'ObjectNotFound' -TargetObject $SetupConfiguration.InstanceName
168+
169+
$PSCmdlet.ThrowTerminatingError($errorRecord)
170+
}
171+
172+
$configFilePath = $SetupConfiguration.ConfigFilePath
173+
}
174+
175+
'ByPath'
176+
{
177+
Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigFile_ReadingFromPath -f $Path)
178+
179+
if (-not (Test-Path -Path $Path -PathType 'Leaf'))
180+
{
181+
$errorMessage = $script:localizedData.Get_SqlDscRSConfigFile_FileNotFound -f $Path
182+
183+
$errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'GSRSCF0004' -ErrorCategory 'ObjectNotFound' -TargetObject $Path
184+
185+
$PSCmdlet.ThrowTerminatingError($errorRecord)
186+
}
187+
188+
$configFilePath = $Path
189+
}
190+
}
191+
192+
Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigFile_FoundConfigFile -f $configFilePath)
193+
194+
try
195+
{
196+
[xml] $configXml = Get-Content -Path $configFilePath -Raw -Force -ErrorAction 'Stop'
197+
}
198+
catch
199+
{
200+
$errorMessage = $script:localizedData.Get_SqlDscRSConfigFile_FailedToReadConfigFile -f $configFilePath, $_.Exception.Message
201+
202+
$errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ -PassThru) -ErrorId 'GSRSCF0003' -ErrorCategory 'ReadError' -TargetObject $configFilePath
203+
204+
$PSCmdlet.ThrowTerminatingError($errorRecord)
205+
}
206+
207+
return $configXml
208+
}
209+
}

0 commit comments

Comments
 (0)