diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b46e9f862..f1095316ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added public command `Get-SqlDscRSConfigurationSetting` to retrieve SQL Server + Reporting Services configuration settings from the MSReportServer_ConfigurationSetting + WMI class. The command returns configuration information including initialization + status, database configuration, virtual directories, service account, TLS configuration, + and other settings. It supports retrieving settings for all instances or a specific + instance by name. The command uses `Get-SqlDscRSSetupConfiguration` to discover + instances and determine the SQL version for proper WMI namespace construction. + Properties returned are limited to those available in the MSReportServer_ConfigurationSetting + class, with `SecureConnectionLevel` converted to boolean `IsTlsConfigured` property + [issue #2011](https://github.com/dsccommunity/SqlServerDsc/issues/2011). - Added public command `Set-SqlDscDatabaseOwner` to change the owner of a SQL Server database [issue #2177](https://github.com/dsccommunity/SqlServerDsc/issues/2177). This command uses the SMO `SetOwner()` method and supports both `ServerObject` diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f88596af6b..977847b415 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -518,6 +518,7 @@ stages: # Group 2 'tests/Integration/Commands/Get-SqlDscInstalledInstance.Integration.Tests.ps1' 'tests/Integration/Commands/Get-SqlDscRSSetupConfiguration.Integration.Tests.ps1' + 'tests/Integration/Commands/Get-SqlDscRSConfigurationSetting.Integration.Tests.ps1' 'tests/Integration/Commands/Test-SqlDscRSInstalled.Integration.Tests.ps1' # Group 8 'tests/Integration/Commands/Repair-SqlDscReportingService.Integration.Tests.ps1' @@ -583,6 +584,7 @@ stages: # Group 2 'tests/Integration/Commands/Get-SqlDscInstalledInstance.Integration.Tests.ps1' 'tests/Integration/Commands/Get-SqlDscRSSetupConfiguration.Integration.Tests.ps1' + 'tests/Integration/Commands/Get-SqlDscRSConfigurationSetting.Integration.Tests.ps1' 'tests/Integration/Commands/Test-SqlDscRSInstalled.Integration.Tests.ps1' # Group 8 'tests/Integration/Commands/Repair-SqlDscBIReportServer.Integration.Tests.ps1' diff --git a/source/Public/Get-SqlDscRSConfigurationSetting.ps1 b/source/Public/Get-SqlDscRSConfigurationSetting.ps1 new file mode 100644 index 0000000000..7b11128ff5 --- /dev/null +++ b/source/Public/Get-SqlDscRSConfigurationSetting.ps1 @@ -0,0 +1,214 @@ +<# + .SYNOPSIS + Gets the SQL Server Reporting Services configuration settings from the + MSReportServer_ConfigurationSetting WMI class. + + .DESCRIPTION + Gets the SQL Server Reporting Services configuration settings from the + MSReportServer_ConfigurationSetting WMI class for installed Reporting Services + instances. This includes information like initialization status, database + configuration, virtual directories, service account, and other configuration + settings. + + When no InstanceName is specified, it returns configuration information for all + installed Reporting Services instances. + + .PARAMETER InstanceName + Specifies the instance name to return configuration information for. + If not specified, configuration information for all Reporting Services + instances will be returned. + + .EXAMPLE + Get-SqlDscRSConfigurationSetting + + Returns configuration settings for all SQL Server Reporting Services instances. + + .EXAMPLE + Get-SqlDscRSConfigurationSetting -InstanceName 'SSRS' + + Returns configuration settings for the SQL Server Reporting Services + instance 'SSRS'. + + .OUTPUTS + Returns a PSCustomObject array with the following properties from + MSReportServer_ConfigurationSetting: + - InstanceName: The name of the Reporting Services instance. + - Version: The version of the Reporting Services instance. + - PathName: The Reporting Services configuration file path. + - InstallationID: The Reporting Services unique installation identifier. + - IsInitialized: Whether the instance is initialized. + - IsSharePointIntegrated: Whether the instance is SharePoint integrated. + - IsWebServiceEnabled: Whether the Web service is enabled. + - IsWindowsServiceEnabled: Whether the Windows service is enabled. + - IsTlsConfigured: Whether TLS is configured (true if SecureConnectionLevel >= 1, false if 0). + - DatabaseServerName: The database server name. + - DatabaseName: The database name. + - DatabaseLogonType: The database login type. + - DatabaseLogonAccount: The database login account. + - ServiceAccount: The Windows service account (from WindowsServiceIdentityActual). + - WebServiceApplicationName: The Web service application name (ReportServerWebService). + - WebServiceVirtualDirectory: The Web service virtual directory (from VirtualDirectoryReportServer). + - WebPortalApplicationName: The Web portal application name (ReportServerWebApp or ReportManager). + - WebPortalVirtualDirectory: The Web portal virtual directory (from VirtualDirectoryReportManager). +#> +function Get-SqlDscRSConfigurationSetting +{ + [CmdletBinding()] + [OutputType([System.Management.Automation.PSCustomObject])] + param + ( + [Parameter()] + [System.String] + $InstanceName + ) + + $reportingServicesInstances = @() + + # Get all Reporting Services instances or filter by specified instance name + $getRSSetupConfigurationParams = @{} + + if ($PSBoundParameters.ContainsKey('InstanceName')) + { + Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigurationSetting_GetSpecificInstance -f $InstanceName) + $getRSSetupConfigurationParams.InstanceName = $InstanceName + } + else + { + Write-Verbose -Message $script:localizedData.Get_SqlDscRSConfigurationSetting_GetAllInstances + } + + $setupConfigurations = Get-SqlDscRSSetupConfiguration @getRSSetupConfigurationParams + + foreach ($setupConfig in $setupConfigurations) + { + Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigurationSetting_ProcessingInstance -f $setupConfig.InstanceName) + + # Initialize return object with InstanceName and null/default values + $returnObject = [PSCustomObject]@{ + InstanceName = $setupConfig.InstanceName + Version = $null + PathName = $null + InstallationID = $null + IsInitialized = $null + IsSharePointIntegrated = $null + IsWebServiceEnabled = $null + IsWindowsServiceEnabled = $null + IsTlsConfigured = $null + DatabaseServerName = $null + DatabaseName = $null + DatabaseLogonType = $null + DatabaseLogonAccount = $null + ServiceAccount = $null + WebServiceApplicationName = 'ReportServerWebService' + WebServiceVirtualDirectory = $null + WebPortalApplicationName = $null + WebPortalVirtualDirectory = $null + } + + # Error if CurrentVersion is empty (cannot determine namespace) + if ([System.String]::IsNullOrEmpty($setupConfig.CurrentVersion)) + { + $errorMessage = $script:localizedData.Get_SqlDscRSConfigurationSetting_CurrentVersionEmpty -f $setupConfig.InstanceName + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + $errorMessage, + 'GSDCRSCS0001', # cspell: disable-line + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $setupConfig.InstanceName + ) + ) + } + + # Parse CurrentVersion to get major version number + try + { + $reportServerCurrentVersion = [System.Version] $setupConfig.CurrentVersion + $sqlMajorVersion = $reportServerCurrentVersion.Major + + Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigurationSetting_FoundInstance -f $setupConfig.InstanceName, $sqlMajorVersion) + } + catch + { + $errorMessage = $script:localizedData.Get_SqlDscRSConfigurationSetting_InvalidVersion -f $setupConfig.CurrentVersion, $setupConfig.InstanceName + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + $errorMessage, + 'GSDCRSCS0002', # cspell: disable-line + [System.Management.Automation.ErrorCategory]::InvalidArgument, + $setupConfig.CurrentVersion + ) + ) + } + + # Get MSReportServer_ConfigurationSetting instance + $getCimInstanceParameters = @{ + Filter = "InstanceName='{0}'" -f $returnObject.InstanceName + Namespace = 'root\Microsoft\SQLServer\ReportServer\RS_{0}\v{1}\Admin' -f $returnObject.InstanceName, $sqlMajorVersion + ClassName = 'MSReportServer_ConfigurationSetting' + ErrorAction = 'Stop' + } + + try + { + $reportingServicesConfiguration = Get-CimInstance @getCimInstanceParameters + } + catch + { + $errorMessage = $script:localizedData.Get_SqlDscRSConfigurationSetting_ConfigurationNotFound -f $setupConfig.InstanceName, $getCimInstanceParameters.Namespace, $_.Exception.Message + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + $errorMessage, + 'GSDCRSCS0003', # cspell: disable-line + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $setupConfig.InstanceName + ) + ) + } + + # Determine Web Portal Application Name based on SQL version + if ($sqlMajorVersion -ge 13) + { + $returnObject.WebPortalApplicationName = 'ReportServerWebApp' + } + else + { + $returnObject.WebPortalApplicationName = 'ReportManager' + } + + # Populate return object with properties from MSReportServer_ConfigurationSetting + $returnObject.Version = $reportingServicesConfiguration.Version + $returnObject.PathName = $reportingServicesConfiguration.PathName + $returnObject.InstallationID = $reportingServicesConfiguration.InstallationID + $returnObject.IsInitialized = $reportingServicesConfiguration.IsInitialized + $returnObject.IsSharePointIntegrated = $reportingServicesConfiguration.IsSharePointIntegrated + $returnObject.IsWebServiceEnabled = $reportingServicesConfiguration.IsWebServiceEnabled + $returnObject.IsWindowsServiceEnabled = $reportingServicesConfiguration.IsWindowsServiceEnabled + $returnObject.IsTlsConfigured = $reportingServicesConfiguration.SecureConnectionLevel -ge 1 + $returnObject.DatabaseServerName = $reportingServicesConfiguration.DatabaseServerName + $returnObject.DatabaseName = $reportingServicesConfiguration.DatabaseName + $returnObject.DatabaseLogonType = $reportingServicesConfiguration.DatabaseLogonType + $returnObject.DatabaseLogonAccount = $reportingServicesConfiguration.DatabaseLogonAccount + $returnObject.ServiceAccount = $reportingServicesConfiguration.WindowsServiceIdentityActual + $returnObject.WebServiceVirtualDirectory = $reportingServicesConfiguration.VirtualDirectoryReportServer + $returnObject.WebPortalVirtualDirectory = $reportingServicesConfiguration.VirtualDirectoryReportManager + + $reportingServicesInstances += $returnObject + } + + if ($reportingServicesInstances.Count -eq 0) + { + if ($PSBoundParameters.ContainsKey('InstanceName')) + { + Write-Verbose -Message ($script:localizedData.Get_SqlDscRSConfigurationSetting_InstanceNotFound -f $InstanceName) + } + else + { + Write-Verbose -Message $script:localizedData.Get_SqlDscRSConfigurationSetting_NoInstancesFound + } + } + + return $reportingServicesInstances +} diff --git a/source/en-US/SqlServerDsc.strings.psd1 b/source/en-US/SqlServerDsc.strings.psd1 index af4fbf7ff8..d76f6f40d0 100644 --- a/source/en-US/SqlServerDsc.strings.psd1 +++ b/source/en-US/SqlServerDsc.strings.psd1 @@ -288,6 +288,17 @@ ConvertFrom-StringData @' Get_SqlDscRSSetupConfiguration_InstanceNotFound = Could not find a Microsoft SQL Server Reporting Services instance with the name '{0}'. Get_SqlDscRSSetupConfiguration_NoInstancesFound = No SQL Server Reporting Services instances were found. + ## Get-SqlDscRSConfigurationSetting + Get_SqlDscRSConfigurationSetting_GetAllInstances = Getting all SQL Server Reporting Services configuration settings. + Get_SqlDscRSConfigurationSetting_GetSpecificInstance = Getting SQL Server Reporting Services configuration settings for instance '{0}'. + Get_SqlDscRSConfigurationSetting_FoundInstance = Found a Microsoft SQL Server Reporting Services instance with the name '{0}' (SQL version {1}). + Get_SqlDscRSConfigurationSetting_ProcessingInstance = Processing configuration settings for instance '{0}'. + Get_SqlDscRSConfigurationSetting_InstanceNotFound = Could not find a Microsoft SQL Server Reporting Services instance with the name '{0}'. + Get_SqlDscRSConfigurationSetting_NoInstancesFound = No SQL Server Reporting Services instances were found. + Get_SqlDscRSConfigurationSetting_CurrentVersionEmpty = Cannot get configuration settings for Reporting Services instance '{0}' because CurrentVersion is not available. The instance may not be properly installed or initialized. + Get_SqlDscRSConfigurationSetting_InvalidVersion = Cannot parse CurrentVersion '{0}' for Reporting Services instance '{1}'. The version format is invalid. + Get_SqlDscRSConfigurationSetting_ConfigurationNotFound = Could not find MSReportServer_ConfigurationSetting for instance '{0}' in namespace '{1}'. Error: {2} + ## Test-SqlDscRSInstalled Test_SqlDscRSInstalled_Checking = Checking if Reporting Services instance '{0}' is installed. Test_SqlDscRSInstalled_Found = Reporting Services instance '{0}' was found. diff --git a/tests/Integration/Commands/Get-SqlDscRSConfigurationSetting.Integration.Tests.ps1 b/tests/Integration/Commands/Get-SqlDscRSConfigurationSetting.Integration.Tests.ps1 new file mode 100644 index 0000000000..b68cd47a6c --- /dev/null +++ b/tests/Integration/Commands/Get-SqlDscRSConfigurationSetting.Integration.Tests.ps1 @@ -0,0 +1,178 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies have not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.' + } +} + +BeforeAll { + $script:moduleName = 'SqlServerDsc' + + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' +} + +Describe 'Get-SqlDscRSConfigurationSetting' { + Context 'When getting the configuration settings for SQL Server Reporting Services instance' -Tag @('Integration_SQL2017_RS') { + It 'Should return the correct configuration settings for SSRS instance' { + # Get the SSRS configuration settings + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Verify the result + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + # Temporary disabled because integration instances provide an empty version + #[System.Version] $result.Version | Should -BeGreaterOrEqual ([System.Version] '14.0.601.20') + $result.PathName | Should -Be 'C:\Program Files\SSRS\SSRS\ReportServer\rsreportserver.config' + $result.InstallationID | Should -Not -BeNullOrEmpty + $result.IsInitialized | Should -BeFalse + $result.IsSharePointIntegrated | Should -BeFalse + $result.IsWebServiceEnabled | Should -BeTrue + $result.IsWindowsServiceEnabled | Should -BeTrue + $result.IsTlsConfigured | Should -BeFalse + $result.DatabaseServerName | Should -BeNullOrEmpty + $result.DatabaseName | Should -BeNullOrEmpty + $result.DatabaseLogonType | Should -Be 2 + $result.DatabaseLogonAccount | Should -BeNullOrEmpty + $result.ServiceAccount | Should -Be 'NT SERVICE\SQLServerReportingServices' + $result.WebServiceApplicationName | Should -Be 'ReportServerWebService' + $result.WebServiceVirtualDirectory | Should -BeNullOrEmpty + $result.WebPortalApplicationName | Should -Be 'ReportServerWebApp' + $result.WebPortalVirtualDirectory | Should -BeNullOrEmpty + } + } + + Context 'When getting the configuration settings for SQL Server Reporting Services instance' -Tag @('Integration_SQL2019_RS') { + It 'Should return the correct configuration settings for SSRS instance' { + # Get the SSRS configuration settings + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Verify the result + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + # Temporary disabled because integration instances provide an empty version + #[System.Version] $result.Version | Should -BeGreaterOrEqual ([System.Version] '15.0.1103.41') + $result.PathName | Should -Be 'C:\Program Files\SSRS\SSRS\ReportServer\rsreportserver.config' + $result.InstallationID | Should -Not -BeNullOrEmpty + $result.IsInitialized | Should -BeFalse + $result.IsSharePointIntegrated | Should -BeFalse + $result.IsWebServiceEnabled | Should -BeTrue + $result.IsWindowsServiceEnabled | Should -BeTrue + $result.IsTlsConfigured | Should -BeFalse + $result.DatabaseServerName | Should -BeNullOrEmpty + $result.DatabaseName | Should -BeNullOrEmpty + $result.DatabaseLogonType | Should -Be 2 + $result.DatabaseLogonAccount | Should -BeNullOrEmpty + $result.ServiceAccount | Should -Be 'NT SERVICE\SQLServerReportingServices' + $result.WebServiceApplicationName | Should -Be 'ReportServerWebService' + $result.WebServiceVirtualDirectory | Should -BeNullOrEmpty + $result.WebPortalApplicationName | Should -Be 'ReportServerWebApp' + $result.WebPortalVirtualDirectory | Should -BeNullOrEmpty + } + } + + Context 'When getting the configuration settings for SQL Server Reporting Services instance' -Tag @('Integration_SQL2022_RS') { + It 'Should return the correct configuration settings for SSRS instance' { + # Get the SSRS configuration settings + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Verify the result + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + # Temporary disabled because integration instances provide an empty version + #[System.Version] $result.Version | Should -BeGreaterOrEqual ([System.Version] '16.0.1116.38') + $result.PathName | Should -Be 'C:\Program Files\SSRS\SSRS\ReportServer\rsreportserver.config' + $result.InstallationID | Should -Not -BeNullOrEmpty + $result.IsInitialized | Should -BeFalse + $result.IsSharePointIntegrated | Should -BeFalse + $result.IsWebServiceEnabled | Should -BeTrue + $result.IsWindowsServiceEnabled | Should -BeTrue + $result.IsTlsConfigured | Should -BeFalse + $result.DatabaseServerName | Should -BeNullOrEmpty + $result.DatabaseName | Should -BeNullOrEmpty + $result.DatabaseLogonType | Should -Be 2 + $result.DatabaseLogonAccount | Should -BeNullOrEmpty + $result.ServiceAccount | Should -Be 'NT SERVICE\SQLServerReportingServices' + $result.WebServiceApplicationName | Should -Be 'ReportServerWebService' + $result.WebServiceVirtualDirectory | Should -BeNullOrEmpty + $result.WebPortalApplicationName | Should -Be 'ReportServerWebApp' + $result.WebPortalVirtualDirectory | Should -BeNullOrEmpty + } + } + + Context 'When getting the configuration settings for Power BI Report Server instance' -Tag @('Integration_PowerBI') { + # cSpell: ignore PBIRS rsreportserver + It 'Should return the correct configuration settings for PBIRS instance' { + # Get the PBIRS configuration settings + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'PBIRS' -ErrorAction 'Stop' + + # Verify the result + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'PBIRS' + # Temporary disabled because integration instances provide an empty version + #[System.Version] $result.Version | Should -BeGreaterOrEqual ([System.Version] '15.0.1117.98') + $result.PathName | Should -Be 'C:\Program Files\PBIRS\PBIRS\ReportServer\rsreportserver.config' + $result.InstallationID | Should -Not -BeNullOrEmpty + $result.IsInitialized | Should -BeFalse + $result.IsSharePointIntegrated | Should -BeFalse + $result.IsWebServiceEnabled | Should -BeTrue + $result.IsWindowsServiceEnabled | Should -BeTrue + $result.IsTlsConfigured | Should -BeFalse + $result.DatabaseServerName | Should -BeNullOrEmpty + $result.DatabaseName | Should -BeNullOrEmpty + $result.DatabaseLogonType | Should -Be 2 + $result.DatabaseLogonAccount | Should -BeNullOrEmpty + $result.ServiceAccount | Should -Be 'NT SERVICE\PowerBIReportServer' + $result.WebServiceApplicationName | Should -Be 'ReportServerWebService' + $result.WebServiceVirtualDirectory | Should -BeNullOrEmpty + $result.WebPortalApplicationName | Should -Be 'ReportServerWebApp' + $result.WebPortalVirtualDirectory | Should -BeNullOrEmpty + } + } + + Context 'When getting all Reporting Services instances' -Tag @('Integration_SQL2017_RS', 'Integration_SQL2019_RS', 'Integration_SQL2022_RS', 'Integration_PowerBI') { + It 'Should return configuration settings for all instances' { + # Get all SSRS configuration settings + $result = Get-SqlDscRSConfigurationSetting -ErrorAction 'Stop' + + # Verify the result + $result | Should -Not -BeNullOrEmpty + $result | Should -BeOfType [System.Management.Automation.PSCustomObject] + + # Verify each instance has required properties + foreach ($instance in $result) + { + $instance.InstanceName | Should -Not -BeNullOrEmpty + # Temporary disabled because integration instances provide an empty version + #[System.Version] $instance.Version | Should -Not -BeNullOrEmpty + $instance.PathName | Should -Not -BeNullOrEmpty + $instance.InstallationID | Should -Not -BeNullOrEmpty + $instance.IsInitialized | Should -BeOfType [System.Boolean] + $instance.IsSharePointIntegrated | Should -BeOfType [System.Boolean] + $instance.IsWebServiceEnabled | Should -BeOfType [System.Boolean] + $instance.IsWindowsServiceEnabled | Should -BeOfType [System.Boolean] + $instance.IsTlsConfigured | Should -BeOfType [System.Boolean] + $instance.ServiceAccount | Should -Not -BeNullOrEmpty + $instance.WebServiceApplicationName | Should -Be 'ReportServerWebService' + $instance.WebPortalApplicationName | Should -Be 'ReportServerWebApp' + } + } + } +} diff --git a/tests/Unit/Public/Get-SqlDscRSConfigurationSetting.Tests.ps1 b/tests/Unit/Public/Get-SqlDscRSConfigurationSetting.Tests.ps1 new file mode 100644 index 0000000000..8d39cac20c --- /dev/null +++ b/tests/Unit/Public/Get-SqlDscRSConfigurationSetting.Tests.ps1 @@ -0,0 +1,442 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies have not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.' + } +} + +BeforeAll { + $script:dscModuleName = 'SqlServerDsc' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:dscModuleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Get-SqlDscRSConfigurationSetting' { + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[[-InstanceName] ] []' + } + ) { + $result = (Get-Command -Name 'Get-SqlDscRSConfigurationSetting').ParameterSets | + Where-Object -FilterScript { $_.Name -eq $ExpectedParameterSetName } | + Select-Object -Property @( + @{ Name = 'ParameterSetName'; Expression = { $_.Name } }, + @{ Name = 'ParameterListAsString'; Expression = { $_.ToString() } } + ) + + $result.ParameterSetName | Should -Be $ExpectedParameterSetName + $result.ParameterListAsString | Should -Be $ExpectedParameters + } + } + + Context 'When getting all Reporting Services instances' { + BeforeAll { + # Mock setup configuration objects + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = '15.0.1.0' + InstallFolder = 'C:\Program Files\Microsoft SQL Server Reporting Services' + ServiceName = 'SQLServerReportingServices' + ErrorDumpDirectory = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles' + } + + $mockPBIRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'PBIRS' + CurrentVersion = '15.0.1.0' + InstallFolder = 'C:\Program Files\Microsoft SQL Server Reporting Services' + ServiceName = 'PowerBIReportServer' + ErrorDumpDirectory = 'C:\Program Files\Microsoft SQL Server Reporting Services\PBIRS\LogFiles' + } + + # Mock MSReportServer_ConfigurationSetting objects + $mockSSRSConfiguration = [PSCustomObject]@{ + InstanceName = 'SSRS' + Version = '15.0.1.0' + PathName = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS' + InstallationID = '12345678-1234-1234-1234-123456789012' + IsInitialized = $true + IsSharePointIntegrated = $false + IsWebServiceEnabled = $true + IsWindowsServiceEnabled = $true + SecureConnectionLevel = 0 + DatabaseServerName = 'localhost' + DatabaseName = 'ReportServer' + DatabaseLogonType = 2 + DatabaseLogonAccount = '' + WindowsServiceIdentityActual = 'NT SERVICE\ReportServer' + VirtualDirectoryReportServer = 'ReportServer' + VirtualDirectoryReportManager = 'Reports' + } + + $mockPBIRSConfiguration = [PSCustomObject]@{ + InstanceName = 'PBIRS' + Version = '15.0.1.0' + PathName = 'C:\Program Files\Microsoft SQL Server Reporting Services\PBIRS' + InstallationID = '87654321-4321-4321-4321-210987654321' + IsInitialized = $true + IsSharePointIntegrated = $false + IsWebServiceEnabled = $true + IsWindowsServiceEnabled = $true + SecureConnectionLevel = 0 + DatabaseServerName = 'localhost' + DatabaseName = 'ReportServer' + DatabaseLogonType = 2 + DatabaseLogonAccount = '' + WindowsServiceIdentityActual = 'NT SERVICE\PowerBIReportServer' + VirtualDirectoryReportServer = 'ReportServer' + VirtualDirectoryReportManager = 'Reports' + + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @($mockSSRSSetupConfig, $mockPBIRSSetupConfig) + } + + Mock -CommandName Get-CimInstance -ParameterFilter { + $Filter -eq "InstanceName='SSRS'" -and + $Namespace -eq 'root\Microsoft\SQLServer\ReportServer\RS_SSRS\v15\Admin' -and + $ClassName -eq 'MSReportServer_ConfigurationSetting' + } -MockWith { + return @($mockSSRSConfiguration) + } + + Mock -CommandName Get-CimInstance -ParameterFilter { + $Filter -eq "InstanceName='PBIRS'" -and + $Namespace -eq 'root\Microsoft\SQLServer\ReportServer\RS_PBIRS\v15\Admin' -and + $ClassName -eq 'MSReportServer_ConfigurationSetting' + } -MockWith { + return @($mockPBIRSConfiguration) + } + } + + It 'Should return configuration settings for all instances' { + $result = Get-SqlDscRSConfigurationSetting + + $result | Should -Not -BeNullOrEmpty + $result.Count | Should -Be 2 + } + + It 'Should return correct properties for SSRS instance' { + $result = Get-SqlDscRSConfigurationSetting + $ssrsResult = $result | Where-Object -FilterScript { $_.InstanceName -eq 'SSRS' } + + $ssrsResult | Should -Not -BeNullOrEmpty + $ssrsResult.InstanceName | Should -Be 'SSRS' + $ssrsResult.Version | Should -Be '15.0.1.0' + $ssrsResult.PathName | Should -Be 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS' + $ssrsResult.IsInitialized | Should -BeTrue + $ssrsResult.ServiceAccount | Should -Be 'NT SERVICE\ReportServer' + $ssrsResult.IsTlsConfigured | Should -BeFalse + $ssrsResult.WebServiceVirtualDirectory | Should -Be 'ReportServer' + $ssrsResult.WebPortalVirtualDirectory | Should -Be 'Reports' + $ssrsResult.WebPortalApplicationName | Should -Be 'ReportServerWebApp' + $ssrsResult.WebServiceApplicationName | Should -Be 'ReportServerWebService' + } + + It 'Should call Get-SqlDscRSSetupConfiguration without InstanceName' { + $result = Get-SqlDscRSConfigurationSetting + Should -Invoke -CommandName Get-SqlDscRSSetupConfiguration -Exactly -Times 1 -Scope It -ParameterFilter { + -not $PSBoundParameters.ContainsKey('InstanceName') + } + } + + It 'Should call Get-CimInstance for each instance' { + $result = Get-SqlDscRSConfigurationSetting + Should -Invoke -CommandName Get-CimInstance -Exactly -Times 2 -Scope It + } + } + + Context 'When getting a specific Reporting Services instance' { + BeforeAll { + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = '13.0.7001.0' + InstallFolder = 'C:\Program Files\Microsoft SQL Server Reporting Services' + ServiceName = 'SQLServerReportingServices' + ErrorDumpDirectory = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles' + } + + $mockSSRSConfiguration = [PSCustomObject]@{ + InstanceName = 'SSRS' + Version = '13.0.7001.0' + PathName = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS' + InstallationID = '12345678-1234-1234-1234-123456789012' + IsInitialized = $true + IsSharePointIntegrated = $false + IsWebServiceEnabled = $true + IsWindowsServiceEnabled = $true + SecureConnectionLevel = 0 + DatabaseServerName = 'localhost' + DatabaseName = 'ReportServer' + DatabaseLogonType = 2 + DatabaseLogonAccount = '' + WindowsServiceIdentityActual = 'NT SERVICE\ReportServer' + VirtualDirectoryReportServer = 'ReportServer' + VirtualDirectoryReportManager = 'Reports' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -ParameterFilter { $InstanceName -eq 'SSRS' } -MockWith { + return @($mockSSRSSetupConfig) + } + + Mock -CommandName Get-CimInstance -ParameterFilter { $Filter -eq "InstanceName='SSRS'" } -MockWith { + return @($mockSSRSConfiguration) + } + } + + It 'Should return configuration settings for the specified instance' { + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'SSRS' + + $result | Should -Not -BeNullOrEmpty + $result.Count | Should -Be 1 + $result[0].InstanceName | Should -Be 'SSRS' + } + + It 'Should call Get-SqlDscRSSetupConfiguration with InstanceName' { + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'SSRS' + Should -Invoke -CommandName Get-SqlDscRSSetupConfiguration -Exactly -Times 1 -Scope It -ParameterFilter { + $InstanceName -eq 'SSRS' + } + } + } + + Context 'When instance has no CurrentVersion' { + BeforeAll { + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = $null + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @($mockSSRSSetupConfig) + } + } + + It 'Should throw a terminating error when the currentVersion is null' { + { Get-SqlDscRSConfigurationSetting } | + Should -Throw -ErrorId 'GSDCRSCS0001,Get-SqlDscRSConfigurationSetting' + } + } + + Context 'When instance has an invalid version' { + BeforeAll { + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = 'InvalidVersion' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @($mockSSRSSetupConfig) + } + } + + It 'Should throw a terminating error when the currentVersion is invalid' { + { Get-SqlDscRSConfigurationSetting } | + Should -Throw -ErrorId 'GSDCRSCS0002,Get-SqlDscRSConfigurationSetting' + } + } + + Context 'When MSReportServer_ConfigurationSetting is not found' { + BeforeAll { + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = '15.0.1.0' + InstallFolder = 'C:\Program Files\Microsoft SQL Server Reporting Services' + ServiceName = 'SQLServerReportingServices' + ErrorDumpDirectory = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @($mockSSRSSetupConfig) + } + + Mock -CommandName Get-CimInstance -MockWith { + throw [Microsoft.Management.Infrastructure.CimException]::new('Not found') + } + } + + It 'Should throw a terminating error when Get-CimInstance throws an error' { + { Get-SqlDscRSConfigurationSetting } | + Should -Throw -ErrorId 'GSDCRSCS0003,Get-SqlDscRSConfigurationSetting' + } + } + + Context 'When instance is SQL Server 2014 (version 12)' { + BeforeAll { + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = '12.0.5000.0' + InstallFolder = 'C:\Program Files\Microsoft SQL Server Reporting Services' + ServiceName = 'SQLServerReportingServices' + ErrorDumpDirectory = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles' + } + + $mockSSRSConfiguration = [PSCustomObject]@{ + InstanceName = 'SSRS' + Version = '12.0.5000.0' + PathName = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS' + InstallationID = '12345678-1234-1234-1234-123456789012' + IsInitialized = $true + IsSharePointIntegrated = $false + IsWebServiceEnabled = $true + IsWindowsServiceEnabled = $true + SecureConnectionLevel = 0 + DatabaseServerName = 'localhost' + DatabaseName = 'ReportServer' + DatabaseLogonType = 2 + DatabaseLogonAccount = '' + WindowsServiceIdentityActual = 'NT SERVICE\ReportServer' + VirtualDirectoryReportServer = 'ReportServer' + VirtualDirectoryReportManager = 'Reports' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @($mockSSRSSetupConfig) + } + + Mock -CommandName Get-CimInstance -ParameterFilter { + $Filter -eq "InstanceName='SSRS'" + } -MockWith { + return @($mockSSRSConfiguration) + } + } + + It 'Should use ReportManager for WebPortalApplicationName' { + $result = Get-SqlDscRSConfigurationSetting + + $result | Should -Not -BeNullOrEmpty + $result[0].WebPortalApplicationName | Should -Be 'ReportManager' + $result[0].WebPortalVirtualDirectory | Should -Be 'Reports' + } + + It 'Should convert SecureConnectionLevel 0 to IsTlsConfigured false' { + $result = Get-SqlDscRSConfigurationSetting + + $result | Should -Not -BeNullOrEmpty + $result[0].IsTlsConfigured | Should -BeFalse + } + } + + Context 'When instance is SQL Server 2016 (version 13)' { + BeforeAll { + $mockSSRSSetupConfig = [PSCustomObject]@{ + InstanceName = 'SSRS' + CurrentVersion = '13.0.7001.0' + InstallFolder = 'C:\Program Files\Microsoft SQL Server Reporting Services' + ServiceName = 'SQLServerReportingServices' + ErrorDumpDirectory = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS\LogFiles' + } + + $mockSSRSConfiguration = [PSCustomObject]@{ + InstanceName = 'SSRS' + Version = '13.0.7001.0' + PathName = 'C:\Program Files\Microsoft SQL Server Reporting Services\SSRS' + InstallationID = '12345678-1234-1234-1234-123456789012' + IsInitialized = $true + IsSharePointIntegrated = $false + IsWebServiceEnabled = $true + IsWindowsServiceEnabled = $true + SecureConnectionLevel = 1 + DatabaseServerName = 'localhost' + DatabaseName = 'ReportServer' + DatabaseLogonType = 2 + DatabaseLogonAccount = '' + WindowsServiceIdentityActual = 'NT SERVICE\ReportServer' + VirtualDirectoryReportServer = 'ReportServer' + VirtualDirectoryReportManager = 'Reports' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @($mockSSRSSetupConfig) + } + + Mock -CommandName Get-CimInstance -ParameterFilter { + $Filter -eq "InstanceName='SSRS'" + } -MockWith { + return @($mockSSRSConfiguration) + } + } + + It 'Should use ReportServerWebApp for WebPortalApplicationName' { + $result = Get-SqlDscRSConfigurationSetting + + $result | Should -Not -BeNullOrEmpty + $result[0].WebPortalApplicationName | Should -Be 'ReportServerWebApp' + $result[0].WebPortalVirtualDirectory | Should -Be 'Reports' + } + + It 'Should convert SecureConnectionLevel 1 to IsTlsConfigured true' { + $result = Get-SqlDscRSConfigurationSetting + + $result | Should -Not -BeNullOrEmpty + $result[0].IsTlsConfigured | Should -BeTrue + } + } + + Context 'When no instances are found' { + BeforeAll { + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @() + } + } + + It 'Should return empty array when no instances found' { + $result = Get-SqlDscRSConfigurationSetting + + $result | Should -BeNullOrEmpty + } + } + + Context 'When instance name is not found' { + BeforeAll { + Mock -CommandName Get-SqlDscRSSetupConfiguration -ParameterFilter { + $InstanceName -eq 'NonExistent' + } -MockWith { + return @() + } + } + + It 'Should return empty array when instance name not found' { + $result = Get-SqlDscRSConfigurationSetting -InstanceName 'NonExistent' + + $result | Should -BeNullOrEmpty + } + } +}