Skip to content

Commit 7af9141

Browse files
authored
Add commands for certificate binding in Report Server (#2409)
1 parent 1e0518a commit 7af9141

22 files changed

Lines changed: 3033 additions & 85 deletions

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
214214
for SQL Server Reporting Services or Power BI Report Server. Supports waiting
215215
for dependent services, configurable wait time, and accepts pipeline input
216216
from `Get-SqlDscRSConfiguration`.
217+
- Added public commands `Get-SqlDscRSSslCertificateBinding`,
218+
`Add-SqlDscRSSslCertificateBinding`, `Remove-SqlDscRSSslCertificateBinding`,
219+
and `Set-SqlDscRSSslCertificateBinding` to manage SSL certificate bindings
220+
for SQL Server Reporting Services or Power BI Report Server. These commands
221+
wrap the `ListSSLCertificateBindings`, `CreateSSLCertificateBinding`, and
222+
`RemoveSSLCertificateBinding` CIM methods. The `Set-SqlDscRSSslCertificateBinding`
223+
command provides a declarative approach to set SSL bindings to an exact list.
217224
- Added public command `New-SqlDscRSEncryptionKey` to delete and regenerate the
218225
Reporting Services encryption key. Wraps the `DeleteEncryptionKey` CIM method.
219226
Warning: This operation cannot be undone and renders all encrypted content
@@ -237,6 +244,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
237244
by calling the `InitializeReportServer` CIM method. Used to complete initial
238245
configuration after database and URL setup
239246
([issue #2014](https://github.com/dsccommunity/SqlServerDsc/issues/2014)).
247+
- Added public command `Get-SqlDscRSSslCertificate` to list available SSL
248+
certificates that can be used for Reporting Services. Wraps the
249+
`ListSSLCertificates` CIM method.
240250
- Added public command `Get-SqlDscRSIPAddress` to list IP addresses available
241251
for URL reservations. Wraps the `ListIPAddresses` CIM method.
242252
- Added public command `Get-SqlDscRSDatabaseInstallation` to determine whether

azure-pipelines.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,83 @@ stages:
712712
testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml'
713713
testRunTitle: 'Integration Commands ($(TEST_CONFIGURATION) / $(JOB_VMIMAGE))'
714714

715+
- stage: Integration_Test_Commands_BIReportServer_Secure
716+
displayName: 'Integration Test Commands - BI Report Server SSL/TLS'
717+
dependsOn: Build #Integration_Test_Commands_SqlServer
718+
jobs:
719+
- job: Test_Integration
720+
displayName: 'Commands'
721+
strategy:
722+
matrix:
723+
PowerBI_WIN2022:
724+
JOB_VMIMAGE: 'windows-2022'
725+
TEST_CONFIGURATION: 'Integration_PowerBI'
726+
PowerBI_WIN2025:
727+
JOB_VMIMAGE: 'windows-2025'
728+
TEST_CONFIGURATION: 'Integration_PowerBI'
729+
pool:
730+
vmImage: $(JOB_VMIMAGE)
731+
timeoutInMinutes: '0'
732+
steps:
733+
- task: DownloadPipelineArtifact@2
734+
displayName: 'Download Build Artifact'
735+
inputs:
736+
buildType: 'current'
737+
artifactName: $(buildArtifactName)
738+
targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)'
739+
- task: PowerShell@2
740+
name: configureWinRM
741+
displayName: 'Configure WinRM'
742+
inputs:
743+
targetType: 'inline'
744+
script: 'winrm quickconfig -quiet'
745+
pwsh: false
746+
- powershell: |
747+
Import-Module -Name ./tests/TestHelpers/CommonTestHelper.psm1
748+
Remove-PowerShellModuleFromCI -Name @('SqlServer', 'SQLPS')
749+
Remove-Module -Name CommonTestHelper
750+
name: cleanCIWorker
751+
displayName: 'Clean CI worker'
752+
- powershell: |
753+
./build.ps1 -Tasks test -CodeCoverageThreshold 0 -PesterTag $(TEST_CONFIGURATION) -PesterPath @(
754+
# Run the integration tests in a specific group order.
755+
# Group 0
756+
'tests/Integration/Commands/Prerequisites.Integration.Tests.ps1'
757+
'tests/Integration/Commands/Prerequisites.RSDB.Integration.Tests.ps1'
758+
'tests/Integration/Commands/Save-SqlDscSqlServerMediaFile.Integration.Tests.ps1'
759+
'tests/Integration/Commands/Import-SqlDscPreferredModule.Integration.Tests.ps1'
760+
# Group 1
761+
'tests/Integration/Commands/Install-SqlDscPowerBIReportServer.Integration.Tests.ps1'
762+
# Group 2
763+
'tests/Integration/Commands/Request-SqlDscRSDatabaseScript.Integration.Tests.ps1'
764+
'tests/Integration/Commands/Request-SqlDscRSDatabaseRightsScript.Integration.Tests.ps1'
765+
# Group 3
766+
'tests/Integration/Commands/Enable-SqlDscRsSecureConnection.Integration.Tests.ps1'
767+
'tests/Integration/Commands/Set-SqlDscRSVirtualDirectory.Integration.Tests.ps1'
768+
'tests/Integration/Commands/Pre.Set-SqlDscRSUrlReservation.Integration.Tests.ps1'
769+
'tests/Integration/Commands/Add-SqlDscRSSslCertificateBinding.Integration.Tests.ps1'
770+
'tests/Integration/Commands/Set-SqlDscRSDatabaseConnection.Integration.Tests.ps1'
771+
'tests/Integration/Commands/Restart-SqlDscRSService.Integration.Tests.ps1'
772+
# Group 4
773+
'tests/Integration/Commands/Initialize-SqlDscRS.Integration.Tests.ps1'
774+
# Group 5 - Post-initialization validation
775+
'tests/Integration/Commands/Post.Certificate.RS.Integration.Tests.ps1'
776+
# Group 6
777+
'tests/Integration/Commands/Get-SqlDscRSSslCertificate.Integration.Tests.ps1'
778+
'tests/Integration/Commands/Get-SqlDscRSSslCertificateBinding.Integration.Tests.ps1'
779+
'tests/Integration/Commands/Remove-SqlDscRSSslCertificateBinding.Integration.Tests.ps1'
780+
'tests/Integration/Commands/Set-SqlDscRSSslCertificateBinding.Integration.Tests.ps1'
781+
)
782+
name: test
783+
displayName: 'Run Integration Test'
784+
- task: PublishTestResults@2
785+
displayName: 'Publish Test Results'
786+
condition: succeededOrFailed()
787+
inputs:
788+
testResultsFormat: 'NUnit'
789+
testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml'
790+
testRunTitle: 'Integration Commands ($(TEST_CONFIGURATION) / $(JOB_VMIMAGE))'
791+
715792
- stage: Integration_Test_Resources_SqlServer
716793
displayName: 'Integration Test Resources - SQL Server'
717794
dependsOn: Quality_Test_and_Unit_Test
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<#
2+
.SYNOPSIS
3+
Adds an SSL certificate binding for SQL Server Reporting Services.
4+
5+
.DESCRIPTION
6+
Adds an SSL certificate binding for SQL Server Reporting Services or
7+
Power BI Report Server by calling the `CreateSSLCertificateBinding`
8+
method on the `MSReportServer_ConfigurationSetting` CIM instance.
9+
10+
This command binds an SSL certificate to a specific application,
11+
IP address, and port for the Reporting Services instance. URL reservations
12+
must be set prior for the specified application to determine if the TLS/SSL
13+
certificate binding is valid.
14+
15+
The configuration CIM instance can be obtained using the
16+
`Get-SqlDscRSConfiguration` command and passed via the pipeline.
17+
18+
.PARAMETER Configuration
19+
Specifies the `MSReportServer_ConfigurationSetting` CIM instance for
20+
the Reporting Services instance. This can be obtained using the
21+
`Get-SqlDscRSConfiguration` command. This parameter accepts pipeline
22+
input.
23+
24+
.PARAMETER Application
25+
Specifies the application for which to create the SSL binding.
26+
Valid values are:
27+
- 'ReportServerWebService': The Report Server Web Service.
28+
- 'ReportServerWebApp': The Reports web application (SQL Server 2016+).
29+
- 'ReportManager': The Report Manager (SQL Server 2014 and earlier).
30+
31+
.PARAMETER CertificateHash
32+
Specifies the thumbprint (hash) of the SSL certificate to bind.
33+
The certificate must be installed in the local machine certificate
34+
store.
35+
36+
.PARAMETER IPAddress
37+
Specifies the IP address for the SSL binding. Use '0.0.0.0' to bind
38+
to all IP addresses. Default value is '0.0.0.0'.
39+
40+
.PARAMETER Port
41+
Specifies the port number for the SSL binding. Default value is 443.
42+
43+
.PARAMETER Lcid
44+
Specifies the language code identifier (LCID) for the operation.
45+
If not specified, defaults to the operating system language. Common
46+
values include 1033 for English (US).
47+
48+
.PARAMETER PassThru
49+
If specified, returns the configuration CIM instance after adding
50+
the SSL certificate binding.
51+
52+
.PARAMETER Force
53+
If specified, suppresses the confirmation prompt.
54+
55+
.EXAMPLE
56+
Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Add-SqlDscRSSslCertificateBinding -Application 'ReportServerWebService' -CertificateHash 'A1B2C3D4E5F6...'
57+
58+
Adds an SSL certificate binding for the Report Server Web Service
59+
using the default IP address (0.0.0.0) and port (443).
60+
61+
.EXAMPLE
62+
$config = Get-SqlDscRSConfiguration -InstanceName 'SSRS'
63+
Add-SqlDscRSSslCertificateBinding -Configuration $config -Application 'ReportServerWebApp' -CertificateHash 'A1B2C3D4E5F6...' -Port 8443 -Confirm:$false
64+
65+
Adds an SSL certificate binding on port 8443 without confirmation.
66+
67+
.EXAMPLE
68+
Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Add-SqlDscRSSslCertificateBinding -Application 'ReportServerWebService' -CertificateHash 'A1B2C3D4E5F6...' -PassThru
69+
70+
Adds the SSL binding and returns the configuration CIM instance.
71+
72+
.INPUTS
73+
`Microsoft.Management.Infrastructure.CimInstance`
74+
75+
Accepts MSReportServer_ConfigurationSetting CIM instance via pipeline.
76+
77+
.OUTPUTS
78+
None. By default, this command does not generate any output.
79+
80+
.OUTPUTS
81+
`Microsoft.Management.Infrastructure.CimInstance`
82+
83+
When PassThru is specified, returns the MSReportServer_ConfigurationSetting
84+
CIM instance.
85+
86+
.NOTES
87+
The Reporting Services service may need to be restarted for the change
88+
to take effect.
89+
90+
.LINK
91+
https://docs.microsoft.com/en-us/sql/reporting-services/wmi-provider-library-reference/configurationsetting-method-createsslcertificatebinding
92+
#>
93+
function Add-SqlDscRSSslCertificateBinding
94+
{
95+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')]
96+
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
97+
[OutputType([System.Object])]
98+
param
99+
(
100+
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
101+
[System.Object]
102+
$Configuration,
103+
104+
[Parameter(Mandatory = $true)]
105+
[ValidateSet('ReportServerWebService', 'ReportServerWebApp', 'ReportManager')]
106+
[System.String]
107+
$Application,
108+
109+
[Parameter(Mandatory = $true)]
110+
[System.String]
111+
$CertificateHash,
112+
113+
[Parameter()]
114+
[System.String]
115+
$IPAddress = '0.0.0.0',
116+
117+
[Parameter()]
118+
[System.Int32]
119+
$Port = 443,
120+
121+
[Parameter()]
122+
[System.Int32]
123+
$Lcid,
124+
125+
[Parameter()]
126+
[System.Management.Automation.SwitchParameter]
127+
$PassThru,
128+
129+
[Parameter()]
130+
[System.Management.Automation.SwitchParameter]
131+
$Force
132+
)
133+
134+
process
135+
{
136+
if ($Force.IsPresent -and -not $Confirm)
137+
{
138+
$ConfirmPreference = 'None'
139+
}
140+
141+
$instanceName = $Configuration.InstanceName
142+
143+
if (-not $PSBoundParameters.ContainsKey('Lcid'))
144+
{
145+
$Lcid = (Get-OperatingSystem).OSLanguage
146+
}
147+
148+
Write-Verbose -Message ($script:localizedData.Add_SqlDscRSSslCertificateBinding_Adding -f $CertificateHash, $Application, $instanceName)
149+
150+
$descriptionMessage = $script:localizedData.Add_SqlDscRSSslCertificateBinding_ShouldProcessDescription -f $CertificateHash, $Application, $instanceName
151+
$confirmationMessage = $script:localizedData.Add_SqlDscRSSslCertificateBinding_ShouldProcessConfirmation -f $CertificateHash, $Application
152+
$captionMessage = $script:localizedData.Add_SqlDscRSSslCertificateBinding_ShouldProcessCaption
153+
154+
if ($PSCmdlet.ShouldProcess($descriptionMessage, $confirmationMessage, $captionMessage))
155+
{
156+
$invokeRsCimMethodParameters = @{
157+
CimInstance = $Configuration
158+
MethodName = 'CreateSSLCertificateBinding'
159+
Arguments = @{
160+
Application = $Application
161+
CertificateHash = $CertificateHash.ToLower()
162+
IPAddress = $IPAddress
163+
Port = $Port
164+
Lcid = $Lcid
165+
}
166+
}
167+
168+
try
169+
{
170+
$null = Invoke-RsCimMethod @invokeRsCimMethodParameters -ErrorAction 'Stop'
171+
}
172+
catch
173+
{
174+
$PSCmdlet.ThrowTerminatingError(
175+
[System.Management.Automation.ErrorRecord]::new(
176+
($script:localizedData.Add_SqlDscRSSslCertificateBinding_FailedToAdd -f $instanceName, $_.Exception.Message),
177+
'ASRSSCB0001',
178+
[System.Management.Automation.ErrorCategory]::InvalidOperation,
179+
$Configuration
180+
)
181+
)
182+
}
183+
}
184+
185+
if ($PassThru.IsPresent)
186+
{
187+
return $Configuration
188+
}
189+
}
190+
}

source/Public/Get-SqlDscRSDatabaseInstallation.ps1

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@ function Get-SqlDscRSDatabaseInstallation
9999
}
100100
catch
101101
{
102-
$PSCmdlet.ThrowTerminatingError(
103-
[System.Management.Automation.ErrorRecord]::new(
104-
($script:localizedData.Get_SqlDscRSDatabaseInstallation_FailedToGet -f $instanceName, $_.Exception.Message),
105-
'GSRSDI0001',
106-
[System.Management.Automation.ErrorCategory]::InvalidOperation,
107-
$Configuration
108-
)
109-
)
102+
$errorMessage = $script:localizedData.Get_SqlDscRSDatabaseInstallation_FailedToGet -f $instanceName
103+
104+
$exception = New-Exception -Message $errorMessage -ErrorRecord $_
105+
106+
$errorRecord = New-ErrorRecord -Exception $exception -ErrorId 'GSRSDI0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject $Configuration
107+
108+
$PSCmdlet.ThrowTerminatingError($errorRecord)
110109
}
111110
}
112111
}

0 commit comments

Comments
 (0)