diff --git a/CHANGELOG.md b/CHANGELOG.md index bdb5444a11..98580ad42c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added public command `Set-SqlDscRSVirtualDirectory` to set the virtual directory + for Reporting Services applications. Wraps the `SetVirtualDirectory` CIM method + and supports ReportServerWebService, ReportServerWebApp, and ReportManager + applications ([issue #2015](https://github.com/dsccommunity/SqlServerDsc/issues/2015)). +- Added public commands `Get-SqlDscRSUrlReservation`, `Add-SqlDscRSUrlReservation`, + `Remove-SqlDscRSUrlReservation`, and `Set-SqlDscRSUrlReservation` to manage + URL reservations for SQL Server Reporting Services or Power BI Report Server. + These commands wrap the `ListReservedUrls`, `ReserveUrl`, and `RemoveURL` CIM + methods respectively. The `Set-SqlDscRSUrlReservation` command provides a + declarative approach to set URL reservations to an exact list, removing any + existing reservations not in the specified list + ([issue #2016](https://github.com/dsccommunity/SqlServerDsc/issues/2016)) + ([issue #2024](https://github.com/dsccommunity/SqlServerDsc/issues/2024)). - Added public command `Get-SqlDscRSConfiguration` to retrieve the `MSReportServer_ConfigurationSetting` CIM instance for SQL Server Reporting Services or Power BI Report Server. Supports auto-detection of the Reporting Services version or explicit version specification. The returned CIM instance can be piped to `Enable-SqlDscRsSecureConnection` or `Disable-SqlDscRsSecureConnection` ([issue #2022](https://github.com/dsccommunity/SqlServerDsc/issues/2022)). +- Added public command `Get-SqlDscRSWebPortalApplicationName` to get the + Reporting Services web portal application name based on the SQL Server + version. Returns 'ReportServerWebApp' for SQL Server 2016 (version 13) and + later, or 'ReportManager' for earlier versions. Accepts the setup configuration + object from `Get-SqlDscRSSetupConfiguration` via pipeline. - Added public command `Enable-SqlDscRsSecureConnection` to enable secure connection for SQL Server Reporting Services or Power BI Report Server by setting the secure connection level to 1. Accepts the configuration CIM @@ -131,6 +149,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactored to use the public commands `Enable-SqlDscRsSecureConnection` and `Disable-SqlDscRsSecureConnection` for setting the secure connection level instead of calling the CIM method directly. + - Refactored to use the public commands `Get-SqlDscRSUrlReservation`, + `Add-SqlDscRSUrlReservation`, `Remove-SqlDscRSUrlReservation`, and + `Set-SqlDscRSUrlReservation` for managing URL reservations instead of calling + the CIM methods directly. + - Refactored to use the public command `Set-SqlDscRSVirtualDirectory` for + setting virtual directories instead of calling the CIM method directly + ([issue #2015](https://github.com/dsccommunity/SqlServerDsc/issues/2015)). - `Assert-SetupActionProperties` - Refactored to use the command `Get-FileVersion` from the DscResource.Common module instead of the private function `Get-FileVersionInformation` diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1a9858e375..d3d624e74d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -539,6 +539,11 @@ stages: 'tests/Integration/Commands/Get-SqlDscRSConfiguration.Integration.Tests.ps1' 'tests/Integration/Commands/Enable-SqlDscRsSecureConnection.Integration.Tests.ps1' 'tests/Integration/Commands/Disable-SqlDscRsSecureConnection.Integration.Tests.ps1' + 'tests/Integration/Commands/Set-SqlDscRSVirtualDirectory.Integration.Tests.ps1' + 'tests/Integration/Commands/Get-SqlDscRSUrlReservation.Integration.Tests.ps1' + 'tests/Integration/Commands/Add-SqlDscRSUrlReservation.Integration.Tests.ps1' + 'tests/Integration/Commands/Remove-SqlDscRSUrlReservation.Integration.Tests.ps1' + 'tests/Integration/Commands/Set-SqlDscRSUrlReservation.Integration.Tests.ps1' # Group 8 'tests/Integration/Commands/Repair-SqlDscReportingService.Integration.Tests.ps1' # Group 9 @@ -609,6 +614,11 @@ stages: 'tests/Integration/Commands/Get-SqlDscRSConfiguration.Integration.Tests.ps1' 'tests/Integration/Commands/Enable-SqlDscRsSecureConnection.Integration.Tests.ps1' 'tests/Integration/Commands/Disable-SqlDscRsSecureConnection.Integration.Tests.ps1' + 'tests/Integration/Commands/Set-SqlDscRSVirtualDirectory.Integration.Tests.ps1' + 'tests/Integration/Commands/Get-SqlDscRSUrlReservation.Integration.Tests.ps1' + 'tests/Integration/Commands/Add-SqlDscRSUrlReservation.Integration.Tests.ps1' + 'tests/Integration/Commands/Remove-SqlDscRSUrlReservation.Integration.Tests.ps1' + 'tests/Integration/Commands/Set-SqlDscRSUrlReservation.Integration.Tests.ps1' # Group 8 'tests/Integration/Commands/Repair-SqlDscPowerBIReportServer.Integration.Tests.ps1' # Group 9 diff --git a/source/DSCResources/DSC_SqlRS/DSC_SqlRS.psm1 b/source/DSCResources/DSC_SqlRS/DSC_SqlRS.psm1 index 49a0b0e789..bbf82aa16f 100644 --- a/source/DSCResources/DSC_SqlRS/DSC_SqlRS.psm1 +++ b/source/DSCResources/DSC_SqlRS/DSC_SqlRS.psm1 @@ -25,7 +25,7 @@ $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' #> function Get-TargetResource { - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('SqlServerDsc.AnalyzerRules\Measure-CommandsNeededToLoadSMO', '', Justification = 'Neither command is needed for this function since it uses CIM methods when calling Get-ReportingServicesData')] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('SqlServerDsc.AnalyzerRules\Measure-CommandsNeededToLoadSMO', '', Justification = 'Neither command is needed for this function since it uses CIM methods when calling Get-SqlDscRSConfiguration')] [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param @@ -65,28 +65,28 @@ function Get-TargetResource Encrypt = $Encrypt } - $reportingServicesData = Get-ReportingServicesData -InstanceName $InstanceName + $rsConfiguration = Get-SqlDscRSConfiguration -InstanceName $InstanceName -ErrorAction 'SilentlyContinue' - if ( $null -ne $reportingServicesData.Configuration ) + if ($null -ne $rsConfiguration) { - if ( $reportingServicesData.Configuration.DatabaseServerName.Contains('\') ) + if ($rsConfiguration.DatabaseServerName.Contains('\')) { - $getTargetResourceResult.DatabaseServerName = $reportingServicesData.Configuration.DatabaseServerName.Split('\')[0] - $getTargetResourceResult.DatabaseInstanceName = $reportingServicesData.Configuration.DatabaseServerName.Split('\')[1] + $getTargetResourceResult.DatabaseServerName = $rsConfiguration.DatabaseServerName.Split('\')[0] + $getTargetResourceResult.DatabaseInstanceName = $rsConfiguration.DatabaseServerName.Split('\')[1] } else { - $getTargetResourceResult.DatabaseServerName = $reportingServicesData.Configuration.DatabaseServerName + $getTargetResourceResult.DatabaseServerName = $rsConfiguration.DatabaseServerName $getTargetResourceResult.DatabaseInstanceName = 'MSSQLSERVER' } - $isInitialized = $reportingServicesData.Configuration.IsInitialized + $isInitialized = $rsConfiguration.IsInitialized [System.Boolean] $getTargetResourceResult.IsInitialized = $isInitialized - if ( $isInitialized ) + if ($isInitialized) { - if ( $reportingServicesData.Configuration.SecureConnectionLevel ) + if ($rsConfiguration.SecureConnectionLevel) { $getTargetResourceResult.UseSsl = $true } @@ -95,27 +95,25 @@ function Get-TargetResource $getTargetResourceResult.UseSsl = $false } - $getTargetResourceResult.ReportServerVirtualDirectory = $reportingServicesData.Configuration.VirtualDirectoryReportServer - $getTargetResourceResult.ReportsVirtualDirectory = $reportingServicesData.Configuration.VirtualDirectoryReportManager + $getTargetResourceResult.ReportServerVirtualDirectory = $rsConfiguration.VirtualDirectoryReportServer + $getTargetResourceResult.ReportsVirtualDirectory = $rsConfiguration.VirtualDirectoryReportManager - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ListReservedUrls' - } - - $reservedUrls = Invoke-RsCimMethod @invokeRsCimMethodParameters + $reservedUrls = $rsConfiguration | Get-SqlDscRSUrlReservation -ErrorAction 'SilentlyContinue' $reportServerReservedUrl = @() $reportsReservedUrl = @() - for ( $i = 0; $i -lt $reservedUrls.Application.Count; ++$i ) + $rsSetupConfiguration = Get-SqlDscRSSetupConfiguration -InstanceName $InstanceName -ErrorAction 'SilentlyContinue' + $reportsApplicationName = $rsSetupConfiguration | Get-SqlDscRSWebPortalApplicationName -ErrorAction 'SilentlyContinue' + + for ($i = 0; $i -lt $reservedUrls.Application.Count; ++$i) { - if ( $reservedUrls.Application[$i] -eq 'ReportServerWebService' ) + if ($reservedUrls.Application[$i] -eq 'ReportServerWebService') { $reportServerReservedUrl += $reservedUrls.UrlString[$i] } - if ( $reservedUrls.Application[$i] -eq $reportingServicesData.ReportsApplicationName ) + if ($reservedUrls.Application[$i] -eq $reportsApplicationName) { $reportsReservedUrl += $reservedUrls.UrlString[$i] } @@ -128,7 +126,7 @@ function Get-TargetResource { <# Make sure the value returned is false, if the value returned was - either empty, $null or $false. Fic for issue #822. + either empty, $null or $false. Fix for issue #822. #> [System.Boolean] $getTargetResourceResult.IsInitialized = $false } @@ -206,14 +204,13 @@ function Get-TargetResource (Get-CimClass @getCimClassParameters).CimClassMethods[$methodName].Parameters ``` - Or run the following using the helper function in this code. Make sure - to have the helper function loaded in the session. + Or run the following using the Get-SqlDscRSConfiguration command. ``` $methodName = 'ReserveUrl' $instanceName = 'SQL2016' - $reportingServicesData = Get-ReportingServicesData -InstanceName $InstanceName - $reportingServicesData.Configuration.CimClass.CimClassMethods[$methodName].Parameters + $rsConfiguration = Get-SqlDscRSConfiguration -InstanceName $InstanceName + $rsConfiguration.CimClass.CimClassMethods[$methodName].Parameters ``` SecureConnectionLevel (the parameter UseSsl): @@ -279,25 +276,29 @@ function Set-TargetResource $Encrypt ) - $reportingServicesData = Get-ReportingServicesData -InstanceName $InstanceName + $rsConfiguration = Get-SqlDscRSConfiguration -InstanceName $InstanceName -ErrorAction 'SilentlyContinue' - if ( $null -ne $reportingServicesData.Configuration ) + if ($null -ne $rsConfiguration) { - if ( $reportingServicesData.SqlVersion -ge 14 ) + $rsSetupConfiguration = Get-SqlDscRSSetupConfiguration -InstanceName $InstanceName -ErrorAction 'SilentlyContinue' + $sqlVersion = $rsSetupConfiguration | Get-SqlDscRSVersion -ErrorAction 'SilentlyContinue' + $reportsApplicationName = $rsSetupConfiguration | Get-SqlDscRSWebPortalApplicationName -ErrorAction 'SilentlyContinue' + + if ($sqlVersion.Major -ge 14) { - if ( [string]::IsNullOrEmpty($ReportServerVirtualDirectory) ) + if ([System.String]::IsNullOrEmpty($ReportServerVirtualDirectory)) { $ReportServerVirtualDirectory = 'ReportServer' } - if ( [string]::IsNullOrEmpty($ReportsVirtualDirectory) ) + if ([System.String]::IsNullOrEmpty($ReportsVirtualDirectory)) { $ReportsVirtualDirectory = 'Reports' } - $reportingServicesServiceName = $reportingServicesData.Configuration.ServiceName + $reportingServicesServiceName = $rsConfiguration.ServiceName - if ( [System.String]::IsNullOrEmpty($reportingServicesServiceName) ) + if ([System.String]::IsNullOrEmpty($reportingServicesServiceName)) { $errorMessage = $script:localizedData.ServiceNameIsNullOrEmpty -f $InstanceName @@ -306,7 +307,7 @@ function Set-TargetResource $reportingServicesDatabaseName = 'ReportServer' } - elseif ( $InstanceName -eq 'MSSQLSERVER' ) + elseif ($InstanceName -eq 'MSSQLSERVER') { if ( [System.String]::IsNullOrEmpty($ReportServerVirtualDirectory) ) { @@ -347,7 +348,7 @@ function Set-TargetResource $language = $wmiOperatingSystem.OSLanguage $restartReportingService = $false - if ( -not $reportingServicesData.Configuration.IsInitialized ) + if (-not $rsConfiguration.IsInitialized) { Write-Verbose -Message "Initializing Reporting Services on $DatabaseServerName\$DatabaseInstanceName." @@ -366,77 +367,37 @@ function Set-TargetResource $ReportsReservedUrl = @('http://+:80') } - if ( $reportingServicesData.Configuration.VirtualDirectoryReportServer -ne $ReportServerVirtualDirectory ) + if ($rsConfiguration.VirtualDirectoryReportServer -ne $ReportServerVirtualDirectory) { Write-Verbose -Message "Setting report server virtual directory on $DatabaseServerName\$DatabaseInstanceName to '$ReportServerVirtualDirectory'." # cSpell: ignore Lcid - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'SetVirtualDirectory' - Arguments = @{ - Application = 'ReportServerWebService' - VirtualDirectory = $ReportServerVirtualDirectory - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory $ReportServerVirtualDirectory -Lcid $language -Force -ErrorAction 'Stop' $ReportServerReservedUrl | ForEach-Object -Process { Write-Verbose -Message "Adding report server URL reservation on $DatabaseServerName\$DatabaseInstanceName`: $_." - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ReserveUrl' - Arguments = @{ - Application = 'ReportServerWebService' - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $_ -Lcid $language -Force -ErrorAction 'Stop' } } - if ( $reportingServicesData.Configuration.VirtualDirectoryReportManager -ne $ReportsVirtualDirectory ) + if ($rsConfiguration.VirtualDirectoryReportManager -ne $ReportsVirtualDirectory) { Write-Verbose -Message "Setting reports virtual directory on $DatabaseServerName\$DatabaseInstanceName to '$ReportServerVirtualDirectory'." - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'SetVirtualDirectory' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - VirtualDirectory = $ReportsVirtualDirectory - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Set-SqlDscRSVirtualDirectory -Application $reportsApplicationName -VirtualDirectory $ReportsVirtualDirectory -Lcid $language -Force -ErrorAction 'Stop' $ReportsReservedUrl | ForEach-Object -Process { Write-Verbose -Message "Adding reports URL reservation on $DatabaseServerName\$DatabaseInstanceName`: $_." - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ReserveUrl' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Add-SqlDscRSUrlReservation -Application $reportsApplicationName -UrlString $_ -Lcid $language -Force -ErrorAction 'Stop' } } Write-Verbose -Message "Generate database creation script on $DatabaseServerName\$DatabaseInstanceName for database '$reportingServicesDatabaseName'." $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration + CimInstance = $rsConfiguration MethodName = 'GenerateDatabaseCreationScript' Arguments = @{ DatabaseName = $reportingServicesDatabaseName @@ -445,7 +406,7 @@ function Set-TargetResource } } - $reportingServicesDatabaseScript = Invoke-RsCimMethod @invokeRsCimMethodParameters + $reportingServicesDatabaseScript = Invoke-RsCimMethod @invokeRsCimMethodParameters -ErrorAction 'Stop' # Determine RS service account $reportingServicesServiceAccountUserName = (Get-CimInstance -ClassName Win32_Service | Where-Object -FilterScript { @@ -455,7 +416,7 @@ function Set-TargetResource Write-Verbose -Message "Generate database rights script on $DatabaseServerName\$DatabaseInstanceName for database '$reportingServicesDatabaseName' and user '$reportingServicesServiceAccountUserName'." $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration + CimInstance = $rsConfiguration MethodName = 'GenerateDatabaseRightsScript' Arguments = @{ DatabaseName = $reportingServicesDatabaseName @@ -465,7 +426,7 @@ function Set-TargetResource } } - $reportingServicesDatabaseRightsScript = Invoke-RsCimMethod @invokeRsCimMethodParameters + $reportingServicesDatabaseRightsScript = Invoke-RsCimMethod @invokeRsCimMethodParameters -ErrorAction 'Stop' Import-SqlDscPreferredModule @@ -498,7 +459,7 @@ function Set-TargetResource } $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration + CimInstance = $rsConfiguration MethodName = 'SetDatabaseConnection' Arguments = @{ Server = $reportingServicesConnection @@ -525,7 +486,7 @@ function Set-TargetResource } } - Invoke-RsCimMethod @invokeRsCimMethodParameters + Invoke-RsCimMethod @invokeRsCimMethodParameters -ErrorAction 'Stop' <# When initializing SSRS 2019, the call to InitializeReportServer @@ -558,7 +519,8 @@ function Set-TargetResource $restartReportingService = $false - $reportingServicesData = Get-ReportingServicesData -InstanceName $InstanceName + # Refresh the configuration after restart + $rsConfiguration = Get-SqlDscRSConfiguration -InstanceName $InstanceName -ErrorAction 'Stop' <# Only execute InitializeReportServer if SetDatabaseConnection hasn't @@ -566,9 +528,9 @@ function Set-TargetResource InitializeReportServer will fail on SQL Server Standard and lower editions. #> - if ( -not $reportingServicesData.Configuration.IsInitialized ) + if (-not $rsConfiguration.IsInitialized) { - Write-Verbose -Message "Did not help restarting the Reporting Services service, running the CIM method to initialize report server on $DatabaseServerName\$DatabaseInstanceName for instance ID '$($reportingServicesData.Configuration.InstallationID)'." + Write-Verbose -Message "Did not help restarting the Reporting Services service, running the CIM method to initialize report server on $DatabaseServerName\$DatabaseInstanceName for instance ID '$($rsConfiguration.InstallationID)'." <# Add an additional wait before calling InitializeReportServer to give @@ -584,21 +546,21 @@ function Set-TargetResource $restartReportingService = $true $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration + CimInstance = $rsConfiguration MethodName = 'InitializeReportServer' Arguments = @{ - InstallationId = $reportingServicesData.Configuration.InstallationID + InstallationId = $rsConfiguration.InstallationID } } - Invoke-RsCimMethod @invokeRsCimMethodParameters + Invoke-RsCimMethod @invokeRsCimMethodParameters -ErrorAction 'Stop' } else { Write-Verbose -Message "Reporting Services on $DatabaseServerName\$DatabaseInstanceName is initialized." } - if ( $PSBoundParameters.ContainsKey('UseSsl') -and $UseSsl -ne $reportingServicesData.Configuration.SecureConnectionLevel ) + if ( $PSBoundParameters.ContainsKey('UseSsl') -and $UseSsl -ne $rsConfiguration.SecureConnectionLevel ) { Write-Verbose -Message "Changing value for using SSL to '$UseSsl'." @@ -606,11 +568,11 @@ function Set-TargetResource if ($UseSsl) { - $reportingServicesData.Configuration | Enable-SqlDscRsSecureConnection -Force + $rsConfiguration | Enable-SqlDscRsSecureConnection -Force -ErrorAction 'Stop' } else { - $reportingServicesData.Configuration | Disable-SqlDscRsSecureConnection -Force + $rsConfiguration | Disable-SqlDscRsSecureConnection -Force -ErrorAction 'Stop' } } } @@ -652,43 +614,13 @@ function Set-TargetResource $restartReportingService = $true $currentConfig.ReportServerReservedUrl | ForEach-Object -Process { - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'RemoveURL' - Arguments = @{ - Application = 'ReportServerWebService' - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters - } - - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'SetVirtualDirectory' - Arguments = @{ - Application = 'ReportServerWebService' - VirtualDirectory = $ReportServerVirtualDirectory - Lcid = $language - } + $rsConfiguration | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $_ -Lcid $language -Force -ErrorAction 'Stop' } - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory $ReportServerVirtualDirectory -Lcid $language -Force -ErrorAction 'Stop' $currentConfig.ReportServerReservedUrl | ForEach-Object -Process { - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ReserveUrl' - Arguments = @{ - Application = 'ReportServerWebService' - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $_ -Lcid $language -Force -ErrorAction 'Stop' } } @@ -699,43 +631,13 @@ function Set-TargetResource $restartReportingService = $true $currentConfig.ReportsReservedUrl | ForEach-Object -Process { - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'RemoveURL' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Remove-SqlDscRSUrlReservation -Application $reportsApplicationName -UrlString $_ -Lcid $language -Force -ErrorAction 'Stop' } - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'SetVirtualDirectory' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - VirtualDirectory = $ReportsVirtualDirectory - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Set-SqlDscRSVirtualDirectory -Application $reportsApplicationName -VirtualDirectory $ReportsVirtualDirectory -Lcid $language -Force -ErrorAction 'Stop' $currentConfig.ReportsReservedUrl | ForEach-Object -Process { - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ReserveUrl' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters + $rsConfiguration | Add-SqlDscRSUrlReservation -Application $reportsApplicationName -UrlString $_ -Lcid $language -Force -ErrorAction 'Stop' } } @@ -746,36 +648,11 @@ function Set-TargetResource if ( ($null -ne $ReportServerReservedUrl) -and ($null -ne (Compare-Object @compareParameters)) ) { - $restartReportingService = $true - - $currentConfig.ReportServerReservedUrl | ForEach-Object -Process { - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'RemoveURL' - Arguments = @{ - Application = 'ReportServerWebService' - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters - } + Write-Verbose -Message "Updating report server URL reservations on $DatabaseServerName\$DatabaseInstanceName." - $ReportServerReservedUrl | ForEach-Object -Process { - Write-Verbose -Message "Adding report server URL reservation on $DatabaseServerName\$DatabaseInstanceName`: $_." - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ReserveUrl' - Arguments = @{ - Application = 'ReportServerWebService' - UrlString = $_ - Lcid = $language - } - } + $restartReportingService = $true - Invoke-RsCimMethod @invokeRsCimMethodParameters - } + $rsConfiguration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $ReportServerReservedUrl -Lcid $language -Force -ErrorAction 'Stop' } $compareParameters = @{ @@ -785,37 +662,11 @@ function Set-TargetResource if ( ($null -ne $ReportsReservedUrl) -and ($null -ne (Compare-Object @compareParameters)) ) { - $restartReportingService = $true - - $currentConfig.ReportsReservedUrl | ForEach-Object -Process { - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'RemoveURL' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - UrlString = $_ - Lcid = $language - } - } - - Invoke-RsCimMethod @invokeRsCimMethodParameters - } + Write-Verbose -Message "Updating reports URL reservations on $DatabaseServerName\$DatabaseInstanceName." - $ReportsReservedUrl | ForEach-Object -Process { - Write-Verbose -Message "Adding reports URL reservation on $DatabaseServerName\$DatabaseInstanceName`: $_." - - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'ReserveUrl' - Arguments = @{ - Application = $reportingServicesData.ReportsApplicationName - UrlString = $_ - Lcid = $language - } - } + $restartReportingService = $true - Invoke-RsCimMethod @invokeRsCimMethodParameters - } + $rsConfiguration | Set-SqlDscRSUrlReservation -Application $reportsApplicationName -UrlString $ReportsReservedUrl -Lcid $language -Force -ErrorAction 'Stop' } if ( $PSBoundParameters.ContainsKey('UseSsl') -and $UseSsl -ne $currentConfig.UseSsl ) @@ -826,11 +677,11 @@ function Set-TargetResource if ($UseSsl) { - $reportingServicesData.Configuration | Enable-SqlDscRsSecureConnection -Force + $rsConfiguration | Enable-SqlDscRsSecureConnection -Force -ErrorAction 'Stop' } else { - $reportingServicesData.Configuration | Disable-SqlDscRsSecureConnection -Force + $rsConfiguration | Disable-SqlDscRsSecureConnection -Force -ErrorAction 'Stop' } } } @@ -1047,68 +898,6 @@ function Test-TargetResource $result } -<# - .SYNOPSIS - Returns SQL Reporting Services data: configuration object used to initialize and configure - SQL Reporting Services and the name of the Reports Web application name (changed in SQL 2016) - - .PARAMETER InstanceName - Name of the SQL Server Reporting Services instance for which the data is being retrieved. -#> -function Get-ReportingServicesData -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [Parameter(Mandatory = $true)] - [System.String] - $InstanceName - ) - - $instanceNamesRegistryKey = 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS' - - if (Get-ItemProperty -Path $instanceNamesRegistryKey -Name $InstanceName -ErrorAction SilentlyContinue) - { - $instanceId = (Get-ItemProperty -Path $instanceNamesRegistryKey -Name $InstanceName).$InstanceName - - if (Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\MSSQLServer\CurrentVersion") - { - # SQL Server 2017 and 2019 SSRS stores current SQL Server version to a different Registry path. - $sqlVersion = [int]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceId\MSSQLServer\CurrentVersion" -Name 'CurrentVersion').CurrentVersion).Split('.')[0] - } - else - { - $sqlVersion = [int]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\Setup" -Name 'Version').Version).Split('.')[0] - } - - $reportingServicesConfiguration = Get-CimInstance -ClassName MSReportServer_ConfigurationSetting -Namespace "root\Microsoft\SQLServer\ReportServer\RS_$InstanceName\v$sqlVersion\Admin" - $reportingServicesConfiguration = $reportingServicesConfiguration | Where-Object -FilterScript { - $_.InstanceName -eq $InstanceName - } - - <# - SQL Server Reporting Services Web Portal application name changed - in SQL Server 2016. - https://docs.microsoft.com/en-us/sql/reporting-services/breaking-changes-in-sql-server-reporting-services-in-sql-server-2016 - #> - if ($sqlVersion -ge 13) - { - $reportsApplicationName = 'ReportServerWebApp' - } - else - { - $reportsApplicationName = 'ReportManager' - } - } - - @{ - Configuration = $reportingServicesConfiguration - ReportsApplicationName = $reportsApplicationName - SqlVersion = $sqlVersion - } -} - <# .SYNOPSIS A wrapper for Invoke-CimMethod to be able to handle errors in one place. diff --git a/source/Private/Get-OperatingSystem.ps1 b/source/Private/Get-OperatingSystem.ps1 new file mode 100644 index 0000000000..280fdfe594 --- /dev/null +++ b/source/Private/Get-OperatingSystem.ps1 @@ -0,0 +1,47 @@ +<# + .SYNOPSIS + Gets the operating system CIM instance. + + .DESCRIPTION + Gets the operating system CIM instance from Win32_OperatingSystem class. + This function is used to retrieve operating system information such as + the OS language (OSLanguage) which is needed for Reporting Services + URL reservation operations. + + .EXAMPLE + Get-OperatingSystem + + Returns the Win32_OperatingSystem CIM instance. + + .EXAMPLE + (Get-OperatingSystem).OSLanguage + + Returns the operating system language code (e.g., 1033 for English). + + .INPUTS + None. + + .OUTPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + Returns the Win32_OperatingSystem CIM instance. +#> +function Get-OperatingSystem +{ + [CmdletBinding()] + [OutputType([Microsoft.Management.Infrastructure.CimInstance])] + param () + + Write-Verbose -Message $script:localizedData.Get_OperatingSystem_Getting + + $operatingSystem = Get-CimInstance -ClassName 'Win32_OperatingSystem' -Namespace 'root/cimv2' -ErrorAction 'SilentlyContinue' + + if ($null -eq $operatingSystem) + { + Write-Error -Message $script:localizedData.Get_OperatingSystem_FailedToGet -Category 'ObjectNotFound' -ErrorId 'GOS0001' -TargetObject $null + + return + } + + return $operatingSystem +} diff --git a/source/Public/Add-SqlDscRSUrlReservation.ps1 b/source/Public/Add-SqlDscRSUrlReservation.ps1 new file mode 100644 index 0000000000..e26fd071ca --- /dev/null +++ b/source/Public/Add-SqlDscRSUrlReservation.ps1 @@ -0,0 +1,172 @@ +<# + .SYNOPSIS + Adds a URL reservation for SQL Server Reporting Services. + + .DESCRIPTION + Adds a URL reservation for SQL Server Reporting Services or + Power BI Report Server by calling the `ReserveUrl` method on + the `MSReportServer_ConfigurationSetting` CIM instance. + + This command reserves a URL for a specific application in the + Reporting Services instance. The application can be the Report Server + Web Service, the Reports web application (SQL Server 2016+), or the + Report Manager (SQL Server 2014 and earlier). + + The configuration CIM instance can be obtained using the + `Get-SqlDscRSConfiguration` command and passed via the pipeline. + + .PARAMETER Configuration + Specifies the `MSReportServer_ConfigurationSetting` CIM instance for + the Reporting Services instance. This can be obtained using the + `Get-SqlDscRSConfiguration` command. This parameter accepts pipeline + input. + + .PARAMETER Application + Specifies the application for which to reserve the URL. Valid values + are: + - 'ReportServerWebService': The Report Server Web Service. + - 'ReportServerWebApp': The Reports web application (SQL Server 2016+). + - 'ReportManager': The Report Manager (SQL Server 2014 and earlier). + + .PARAMETER UrlString + Specifies the URL string to reserve. The URL string format is typically + 'http://+:80' or 'https://+:443' where the plus sign (+) is a wildcard + that matches all hostnames. + + .PARAMETER Lcid + Specifies the language code identifier (LCID) for the URL reservation. + If not specified, defaults to the operating system language. Common + values include 1033 for English (US). + + .PARAMETER PassThru + If specified, returns the configuration CIM instance after adding + the URL reservation. + + .PARAMETER Force + If specified, suppresses the confirmation prompt. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' + + Adds a URL reservation for the Report Server Web Service on port 80. + + .EXAMPLE + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + Add-SqlDscRSUrlReservation -Configuration $config -Application 'ReportServerWebApp' -UrlString 'https://+:443' -Confirm:$false + + Adds a URL reservation for the Reports web application on port 443 + without confirmation. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:8080' -Lcid 1033 -PassThru + + Adds a URL reservation with a specific LCID and returns the configuration + CIM instance. + + .INPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + Accepts MSReportServer_ConfigurationSetting CIM instance via pipeline. + + .OUTPUTS + None. By default, this command does not generate any output. + + .OUTPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + When PassThru is specified, returns the MSReportServer_ConfigurationSetting + CIM instance. + + .NOTES + The Reporting Services service may need to be restarted for the change + to take effect. + + .LINK + https://docs.microsoft.com/en-us/sql/reporting-services/wmi-provider-library-reference/configurationsetting-method-reserveurl +#> +function Add-SqlDscRSUrlReservation +{ + # cSpell: ignore PBIRS + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] + [OutputType([System.Object])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration, + + [Parameter(Mandatory = $true)] + [ValidateSet('ReportServerWebService', 'ReportServerWebApp', 'ReportManager')] + [System.String] + $Application, + + [Parameter(Mandatory = $true)] + [System.String] + $UrlString, + + [Parameter()] + [System.Int32] + $Lcid, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Force + ) + + process + { + if ($Force.IsPresent -and -not $Confirm) + { + $ConfirmPreference = 'None' + } + + $instanceName = $Configuration.InstanceName + + if (-not $PSBoundParameters.ContainsKey('Lcid')) + { + $Lcid = (Get-OperatingSystem).OSLanguage + } + + Write-Verbose -Message ($script:localizedData.Add_SqlDscRSUrlReservation_Adding -f $UrlString, $Application, $instanceName) + + $descriptionMessage = $script:localizedData.Add_SqlDscRSUrlReservation_ShouldProcessDescription -f $UrlString, $Application, $instanceName + $confirmationMessage = $script:localizedData.Add_SqlDscRSUrlReservation_ShouldProcessConfirmation -f $UrlString, $Application + $captionMessage = $script:localizedData.Add_SqlDscRSUrlReservation_ShouldProcessCaption + + if ($PSCmdlet.ShouldProcess($descriptionMessage, $confirmationMessage, $captionMessage)) + { + $invokeRsCimMethodParameters = @{ + CimInstance = $Configuration + MethodName = 'ReserveUrl' + Arguments = @{ + Application = $Application + UrlString = $UrlString + Lcid = $Lcid + } + } + + try + { + $null = Invoke-RsCimMethod @invokeRsCimMethodParameters + } + catch + { + $errorMessage = $script:localizedData.Add_SqlDscRSUrlReservation_FailedToAdd -f $instanceName, $_.Exception.Message + + $errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'ASRUR0001' -ErrorCategory 'InvalidOperation' -TargetObject $Configuration + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + + if ($PassThru.IsPresent) + { + return $Configuration + } + } +} diff --git a/source/Public/Get-SqlDscRSUrlReservation.ps1 b/source/Public/Get-SqlDscRSUrlReservation.ps1 new file mode 100644 index 0000000000..ff50ef88e3 --- /dev/null +++ b/source/Public/Get-SqlDscRSUrlReservation.ps1 @@ -0,0 +1,90 @@ +<# + .SYNOPSIS + Gets the URL reservations for SQL Server Reporting Services. + + .DESCRIPTION + Gets the URL reservations for SQL Server Reporting Services or + Power BI Report Server by calling the `ListReservedUrls` method on + the `MSReportServer_ConfigurationSetting` CIM instance. + + The configuration CIM instance can be obtained using the + `Get-SqlDscRSConfiguration` command and passed via the pipeline. + + .PARAMETER Configuration + Specifies the `MSReportServer_ConfigurationSetting` CIM instance for + the Reporting Services instance. This can be obtained using the + `Get-SqlDscRSConfiguration` command. This parameter accepts pipeline + input. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Get-SqlDscRSUrlReservation + + Gets all URL reservations for the SSRS instance. + + .EXAMPLE + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + Get-SqlDscRSUrlReservation -Configuration $config + + Gets all URL reservations for the SSRS instance by passing the + configuration as a parameter. + + .INPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + Accepts MSReportServer_ConfigurationSetting CIM instance via pipeline. + + .OUTPUTS + `Microsoft.Management.Infrastructure.CimMethodResult` + + Returns the raw CIM method result containing Application and UrlString + arrays with the reserved URL information. + + .NOTES + The returned object contains two arrays: + - Application: Array of application names (e.g., 'ReportServerWebService', + 'ReportServerWebApp', 'ReportManager') + - UrlString: Array of URL strings (e.g., 'http://+:80') + + The arrays are correlated by index, so Application[0] corresponds to + UrlString[0]. +#> +function Get-SqlDscRSUrlReservation +{ + # cSpell: ignore PBIRS + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding()] + [OutputType([Microsoft.Management.Infrastructure.CimMethodResult])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration + ) + + process + { + $instanceName = $Configuration.InstanceName + + Write-Verbose -Message ($script:localizedData.Get_SqlDscRSUrlReservation_Getting -f $instanceName) + + $invokeRsCimMethodParameters = @{ + CimInstance = $Configuration + MethodName = 'ListReservedUrls' + } + + try + { + $result = Invoke-RsCimMethod @invokeRsCimMethodParameters + } + catch + { + $errorMessage = $script:localizedData.Get_SqlDscRSUrlReservation_FailedToGet -f $instanceName, $_.Exception.Message + + Write-Error -Message $errorMessage -Category 'InvalidOperation' -ErrorId 'GSRUR0001' -TargetObject $Configuration -Exception $_.Exception + + return + } + + return $result + } +} diff --git a/source/Public/Get-SqlDscRSVersion.ps1 b/source/Public/Get-SqlDscRSVersion.ps1 new file mode 100644 index 0000000000..1b01cea53f --- /dev/null +++ b/source/Public/Get-SqlDscRSVersion.ps1 @@ -0,0 +1,57 @@ +<# + .SYNOPSIS + Gets the SQL Server Reporting Services version. + + .DESCRIPTION + Gets the SQL Server Reporting Services version from the setup configuration. + This is used to determine version-specific behavior. + + The setup configuration object can be obtained using the + `Get-SqlDscRSSetupConfiguration` command and passed via the pipeline. + + .PARAMETER Configuration + Specifies the setup configuration object for the Reporting Services instance. + This can be obtained using the `Get-SqlDscRSSetupConfiguration` command. + This parameter accepts pipeline input. + + .EXAMPLE + Get-SqlDscRSSetupConfiguration -InstanceName 'SSRS' | Get-SqlDscRSVersion + + Returns the version for the SSRS instance (e.g. 15.0.1100.0 for SQL 2019). + + .INPUTS + `System.Management.Automation.PSCustomObject` + + Accepts setup configuration object via pipeline. + + .OUTPUTS + `System.Version` + + Returns the version of the Reporting Services instance. +#> +function Get-SqlDscRSVersion +{ + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding()] + [OutputType([System.Version])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration + ) + + process + { + if ([System.String]::IsNullOrEmpty($Configuration.CurrentVersion)) + { + Write-Error -Message $script:localizedData.Get_SqlDscRSVersion_VersionNotFound -Category 'ObjectNotFound' -ErrorId 'GSRSV0001' -TargetObject $Configuration + + return + } + + $version = [System.Version] $Configuration.CurrentVersion + + return $version + } +} diff --git a/source/Public/Get-SqlDscRSWebPortalApplicationName.ps1 b/source/Public/Get-SqlDscRSWebPortalApplicationName.ps1 new file mode 100644 index 0000000000..15b542f53a --- /dev/null +++ b/source/Public/Get-SqlDscRSWebPortalApplicationName.ps1 @@ -0,0 +1,80 @@ +<# + .SYNOPSIS + Gets the Reporting Services web portal application name based on version. + + .DESCRIPTION + Gets the Reporting Services web portal application name based on the SQL + Server major version. SQL Server 2016 (version 13) and later use + 'ReportServerWebApp', while earlier versions use 'ReportManager'. + + The setup configuration object can be obtained using the + `Get-SqlDscRSSetupConfiguration` command and passed via the pipeline. + + See more information at: + https://docs.microsoft.com/en-us/sql/reporting-services/breaking-changes-in-sql-server-reporting-services-in-sql-server-2016 + + .PARAMETER Configuration + Specifies the setup configuration object for the Reporting Services instance. + This can be obtained using the `Get-SqlDscRSSetupConfiguration` command. + This parameter accepts pipeline input. + + .EXAMPLE + Get-SqlDscRSSetupConfiguration -InstanceName 'SSRS' | Get-SqlDscRSWebPortalApplicationName + + Returns 'ReportServerWebApp' or 'ReportManager' based on the SQL Server + version, using pipeline input from the setup configuration object. + + .INPUTS + `System.Management.Automation.PSCustomObject` + + Accepts setup configuration object via pipeline. + + .OUTPUTS + `System.String` + + Returns either 'ReportServerWebApp' for SQL Server 2016 and later, + or 'ReportManager' for earlier versions. +#> +function Get-SqlDscRSWebPortalApplicationName +{ + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration + ) + + process + { + Write-Debug -Message $script:localizedData.Get_SqlDscRSWebPortalApplicationName_GettingApplicationName + + $sqlVersion = $Configuration | Get-SqlDscRSVersion + + if (-not $sqlVersion) + { + return + } + + $sqlMajorVersion = $sqlVersion.Major + + <# + SQL Server Reporting Services Web Portal application name changed + in SQL Server 2016 (version 13). + #> + if ($sqlMajorVersion -ge 13) + { + $reportsApplicationName = 'ReportServerWebApp' + } + else + { + $reportsApplicationName = 'ReportManager' + } + + Write-Debug -Message ($script:localizedData.Get_SqlDscRSWebPortalApplicationName_ApplicationName -f $reportsApplicationName) + + return $reportsApplicationName + } +} diff --git a/source/Public/Remove-SqlDscRSUrlReservation.ps1 b/source/Public/Remove-SqlDscRSUrlReservation.ps1 new file mode 100644 index 0000000000..7188005a5e --- /dev/null +++ b/source/Public/Remove-SqlDscRSUrlReservation.ps1 @@ -0,0 +1,172 @@ +<# + .SYNOPSIS + Removes a URL reservation for SQL Server Reporting Services. + + .DESCRIPTION + Removes a URL reservation for SQL Server Reporting Services or + Power BI Report Server by calling the `RemoveURL` method on + the `MSReportServer_ConfigurationSetting` CIM instance. + + This command removes a URL reservation for a specific application in the + Reporting Services instance. The application can be the Report Server + Web Service, the Reports web application (SQL Server 2016+), or the + Report Manager (SQL Server 2014 and earlier). + + The configuration CIM instance can be obtained using the + `Get-SqlDscRSConfiguration` command and passed via the pipeline. + + .PARAMETER Configuration + Specifies the `MSReportServer_ConfigurationSetting` CIM instance for + the Reporting Services instance. This can be obtained using the + `Get-SqlDscRSConfiguration` command. This parameter accepts pipeline + input. + + .PARAMETER Application + Specifies the application for which to remove the URL reservation. + Valid values are: + - 'ReportServerWebService': The Report Server Web Service. + - 'ReportServerWebApp': The Reports web application (SQL Server 2016+). + - 'ReportManager': The Report Manager (SQL Server 2014 and earlier). + + .PARAMETER UrlString + Specifies the URL string to remove. The URL string format is typically + 'http://+:80' or 'https://+:443' where the plus sign (+) is a wildcard + that matches all hostnames. + + .PARAMETER Lcid + Specifies the language code identifier (LCID) for the URL reservation. + If not specified, defaults to the operating system language. Common + values include 1033 for English (US). + + .PARAMETER PassThru + If specified, returns the configuration CIM instance after removing + the URL reservation. + + .PARAMETER Force + If specified, suppresses the confirmation prompt. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' + + Removes the URL reservation for the Report Server Web Service on port 80. + + .EXAMPLE + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + Remove-SqlDscRSUrlReservation -Configuration $config -Application 'ReportServerWebApp' -UrlString 'https://+:443' -Confirm:$false + + Removes the URL reservation for the Reports web application on port 443 + without confirmation. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:8080' -Force -PassThru + + Removes a URL reservation without confirmation and returns the + configuration CIM instance. + + .INPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + Accepts MSReportServer_ConfigurationSetting CIM instance via pipeline. + + .OUTPUTS + None. By default, this command does not generate any output. + + .OUTPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + When PassThru is specified, returns the MSReportServer_ConfigurationSetting + CIM instance. + + .NOTES + The Reporting Services service may need to be restarted for the change + to take effect. + + .LINK + https://docs.microsoft.com/en-us/sql/reporting-services/wmi-provider-library-reference/configurationsetting-method-removeurl +#> +function Remove-SqlDscRSUrlReservation +{ + # cSpell: ignore PBIRS + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + [OutputType([System.Object])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration, + + [Parameter(Mandatory = $true)] + [ValidateSet('ReportServerWebService', 'ReportServerWebApp', 'ReportManager')] + [System.String] + $Application, + + [Parameter(Mandatory = $true)] + [System.String] + $UrlString, + + [Parameter()] + [System.Int32] + $Lcid, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Force + ) + + process + { + if ($Force.IsPresent -and -not $Confirm) + { + $ConfirmPreference = 'None' + } + + $instanceName = $Configuration.InstanceName + + if (-not $PSBoundParameters.ContainsKey('Lcid')) + { + $Lcid = (Get-OperatingSystem).OSLanguage + } + + Write-Verbose -Message ($script:localizedData.Remove_SqlDscRSUrlReservation_Removing -f $UrlString, $Application, $instanceName) + + $descriptionMessage = $script:localizedData.Remove_SqlDscRSUrlReservation_ShouldProcessDescription -f $UrlString, $Application, $instanceName + $confirmationMessage = $script:localizedData.Remove_SqlDscRSUrlReservation_ShouldProcessConfirmation -f $UrlString, $Application + $captionMessage = $script:localizedData.Remove_SqlDscRSUrlReservation_ShouldProcessCaption + + if ($PSCmdlet.ShouldProcess($descriptionMessage, $confirmationMessage, $captionMessage)) + { + $invokeRsCimMethodParameters = @{ + CimInstance = $Configuration + MethodName = 'RemoveURL' + Arguments = @{ + Application = $Application + UrlString = $UrlString + Lcid = $Lcid + } + } + + try + { + $null = Invoke-RsCimMethod @invokeRsCimMethodParameters + } + catch + { + $errorMessage = $script:localizedData.Remove_SqlDscRSUrlReservation_FailedToRemove -f $instanceName, $_.Exception.Message + + $errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'RSRUR0001' -ErrorCategory 'InvalidOperation' -TargetObject $Configuration + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + + if ($PassThru.IsPresent) + { + return $Configuration + } + } +} diff --git a/source/Public/Set-SqlDscRSUrlReservation.ps1 b/source/Public/Set-SqlDscRSUrlReservation.ps1 new file mode 100644 index 0000000000..c5c803a86d --- /dev/null +++ b/source/Public/Set-SqlDscRSUrlReservation.ps1 @@ -0,0 +1,194 @@ +<# + .SYNOPSIS + Sets the URL reservations for a SQL Server Reporting Services or Power BI + Report Server application to the specified list. + + .DESCRIPTION + The `Set-SqlDscRSUrlReservation` command ensures that only the specified + URL reservations exist for the given application. It removes any existing + URL reservations that are not in the specified list and adds any URLs that + are not currently reserved. + + This command uses the `Get-SqlDscRSUrlReservation`, `Add-SqlDscRSUrlReservation`, + and `Remove-SqlDscRSUrlReservation` commands internally. + + .PARAMETER Configuration + Specifies the Reporting Services configuration CIM instance. This is typically + obtained by calling the `Get-SqlDscRSConfiguration` command. + + .PARAMETER Application + Specifies the Reporting Services application for which to set URL reservations. + Valid values are: ReportServerWebService, ReportServerWebApp, ReportManager. + + .PARAMETER UrlString + Specifies one or more URL strings to reserve. Any existing URL reservations + for the application that are not in this list will be removed. + + .PARAMETER Lcid + Specifies the locale identifier (LCID) for the URL reservation. If not + specified, the operating system language code is used. + + .PARAMETER PassThru + If specified, returns the Reporting Services configuration CIM instance. + + .PARAMETER Force + If specified, suppresses the confirmation prompt. + + .INPUTS + Microsoft.Management.Infrastructure.CimInstance + + Accepts a CIM instance for the Reporting Services configuration from the + pipeline. + + .OUTPUTS + None by default. + + Microsoft.Management.Infrastructure.CimInstance + + If `-PassThru` is specified, returns the Reporting Services configuration + CIM instance. + + .EXAMPLE + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80', 'https://+:443' -Force + + Sets the URL reservations for the ReportServerWebService application to + only 'http://+:80' and 'https://+:443'. Any other existing reservations + for this application will be removed. + + .EXAMPLE + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + $config | Set-SqlDscRSUrlReservation -Application 'ReportServerWebApp' -UrlString 'http://+:80' -Force -PassThru + + Sets the URL reservations for the ReportServerWebApp application on a + Power BI Report Server instance and returns the configuration object. + + .NOTES + This command calls the ReserveUrl and RemoveURL methods on the + MSReportServer_ConfigurationSetting CIM class. + + .LINK + Get-SqlDscRSUrlReservation + + .LINK + Add-SqlDscRSUrlReservation + + .LINK + Remove-SqlDscRSUrlReservation + + .LINK + https://docs.microsoft.com/en-us/sql/reporting-services/wmi-provider-library-reference/configurationsetting-method-reserveurl + + .LINK + https://docs.microsoft.com/en-us/sql/reporting-services/wmi-provider-library-reference/configurationsetting-method-removeurl +#> +function Set-SqlDscRSUrlReservation +{ + # cSpell: ignore PBIRS + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + [OutputType([System.Object])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration, + + [Parameter(Mandatory = $true)] + [ValidateSet('ReportServerWebService', 'ReportServerWebApp', 'ReportManager')] + [System.String] + $Application, + + [Parameter(Mandatory = $true)] + [System.String[]] + $UrlString, + + [Parameter()] + [System.Int32] + $Lcid, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Force + ) + + process + { + if ($Force.IsPresent -and -not $Confirm) + { + $ConfirmPreference = 'None' + } + + $instanceName = $Configuration.InstanceName + + $verboseDescriptionMessage = $script:localizedData.Set_SqlDscRSUrlReservation_ShouldProcessVerboseDescription -f $Application, $instanceName + $verboseWarningMessage = $script:localizedData.Set_SqlDscRSUrlReservation_ShouldProcessVerboseWarning -f $Application, $instanceName + $captionMessage = $script:localizedData.Set_SqlDscRSUrlReservation_ShouldProcessCaption + + if ($PSCmdlet.ShouldProcess($verboseDescriptionMessage, $verboseWarningMessage, $captionMessage)) + { + # Get current URL reservations + $currentReservations = $Configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Build a list of current URLs for the specified application + $currentUrls = @() + + if ($null -ne $currentReservations.Application -and $null -ne $currentReservations.UrlString) + { + for ($i = 0; $i -lt $currentReservations.Application.Count; $i++) + { + if ($currentReservations.Application[$i] -eq $Application) + { + $currentUrls += $currentReservations.UrlString[$i] + } + } + } + + Write-Verbose -Message ($script:localizedData.Set_SqlDscRSUrlReservation_CurrentUrls -f $Application, ($currentUrls -join ', ')) + Write-Verbose -Message ($script:localizedData.Set_SqlDscRSUrlReservation_DesiredUrls -f $Application, ($UrlString -join ', ')) + + # Determine URLs to remove (in current but not in desired) + $urlsToRemove = $currentUrls | Where-Object -FilterScript { $_ -notin $UrlString } + + # Determine URLs to add (in desired but not in current) + $urlsToAdd = $UrlString | Where-Object -FilterScript { $_ -notin $currentUrls } + + # Build common parameters for Add/Remove commands + $commonParams = @{ + Application = $Application + Force = $true + ErrorAction = 'Stop' + } + + if ($PSBoundParameters.ContainsKey('Lcid')) + { + $commonParams['Lcid'] = $Lcid + } + + # Remove URLs that should not exist + foreach ($urlToRemove in $urlsToRemove) + { + Write-Verbose -Message ($script:localizedData.Set_SqlDscRSUrlReservation_RemovingUrl -f $urlToRemove, $Application, $instanceName) + + $Configuration | Remove-SqlDscRSUrlReservation @commonParams -UrlString $urlToRemove + } + + # Add URLs that should exist + foreach ($urlToAdd in $urlsToAdd) + { + Write-Verbose -Message ($script:localizedData.Set_SqlDscRSUrlReservation_AddingUrl -f $urlToAdd, $Application, $instanceName) + + $Configuration | Add-SqlDscRSUrlReservation @commonParams -UrlString $urlToAdd + } + + if ($PassThru.IsPresent) + { + return $Configuration + } + } + } +} diff --git a/source/Public/Set-SqlDscRSVirtualDirectory.ps1 b/source/Public/Set-SqlDscRSVirtualDirectory.ps1 new file mode 100644 index 0000000000..1581c7db93 --- /dev/null +++ b/source/Public/Set-SqlDscRSVirtualDirectory.ps1 @@ -0,0 +1,175 @@ +<# + .SYNOPSIS + Sets the virtual directory for SQL Server Reporting Services. + + .DESCRIPTION + Sets the virtual directory for SQL Server Reporting Services or + Power BI Report Server by calling the `SetVirtualDirectory` method on + the `MSReportServer_ConfigurationSetting` CIM instance. + + This command must be called before URL reservations can be added for + a Reporting Services application. The virtual directory defines the + path segment in the URL used to access the application. + + The configuration CIM instance can be obtained using the + `Get-SqlDscRSConfiguration` command and passed via the pipeline. + + .PARAMETER Configuration + Specifies the `MSReportServer_ConfigurationSetting` CIM instance for + the Reporting Services instance. This can be obtained using the + `Get-SqlDscRSConfiguration` command. This parameter accepts pipeline + input. + + .PARAMETER Application + Specifies the application for which to set the virtual directory. + Valid values are: + - 'ReportServerWebService': The Report Server Web Service. + - 'ReportServerWebApp': The Reports web application (SQL Server 2016+). + - 'ReportManager': The Report Manager (SQL Server 2014 and earlier). + + .PARAMETER VirtualDirectory + Specifies the virtual directory name. This is the path segment used + in the URL to access the application. Common values are 'ReportServer' + for the web service and 'Reports' for the web portal. + + .PARAMETER Lcid + Specifies the language code identifier (LCID) for the virtual directory. + If not specified, defaults to the operating system language. Common + values include 1033 for English (US). + + .PARAMETER PassThru + If specified, returns the configuration CIM instance after setting + the virtual directory. + + .PARAMETER Force + If specified, suppresses the confirmation prompt. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' + + Sets the virtual directory for the Report Server Web Service to + 'ReportServer'. + + .EXAMPLE + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + Set-SqlDscRSVirtualDirectory -Configuration $config -Application 'ReportServerWebApp' -VirtualDirectory 'Reports' -Confirm:$false + + Sets the virtual directory for the Reports web application to 'Reports' + without confirmation. + + .EXAMPLE + Get-SqlDscRSConfiguration -InstanceName 'SSRS' | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -PassThru + + Sets the virtual directory and returns the configuration CIM instance. + + .INPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + Accepts MSReportServer_ConfigurationSetting CIM instance via pipeline. + + .OUTPUTS + None. By default, this command does not generate any output. + + .OUTPUTS + `Microsoft.Management.Infrastructure.CimInstance` + + When PassThru is specified, returns the MSReportServer_ConfigurationSetting + CIM instance. + + .NOTES + The virtual directory must be set before URL reservations can be added + for the application. After setting the virtual directory, use + `Add-SqlDscRSUrlReservation` to add URL reservations. + + The Reporting Services service may need to be restarted for the change + to take effect. + + .LINK + https://docs.microsoft.com/en-us/sql/reporting-services/wmi-provider-library-reference/configurationsetting-method-setvirtualdirectory +#> +function Set-SqlDscRSVirtualDirectory +{ + # cSpell: ignore PBIRS Lcid + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the examples use pipeline input the rule cannot validate.')] + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] + [OutputType([System.Object])] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Object] + $Configuration, + + [Parameter(Mandatory = $true)] + [ValidateSet('ReportServerWebService', 'ReportServerWebApp', 'ReportManager')] + [System.String] + $Application, + + [Parameter(Mandatory = $true)] + [System.String] + $VirtualDirectory, + + [Parameter()] + [System.Int32] + $Lcid, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Force + ) + + process + { + if ($Force.IsPresent -and -not $Confirm) + { + $ConfirmPreference = 'None' + } + + $instanceName = $Configuration.InstanceName + + if (-not $PSBoundParameters.ContainsKey('Lcid')) + { + $Lcid = (Get-OperatingSystem).OSLanguage + } + + Write-Verbose -Message ($script:localizedData.Set_SqlDscRSVirtualDirectory_Setting -f $VirtualDirectory, $Application, $instanceName) + + $descriptionMessage = $script:localizedData.Set_SqlDscRSVirtualDirectory_ShouldProcessDescription -f $VirtualDirectory, $Application, $instanceName + $confirmationMessage = $script:localizedData.Set_SqlDscRSVirtualDirectory_ShouldProcessConfirmation -f $VirtualDirectory, $Application + $captionMessage = $script:localizedData.Set_SqlDscRSVirtualDirectory_ShouldProcessCaption + + if ($PSCmdlet.ShouldProcess($descriptionMessage, $confirmationMessage, $captionMessage)) + { + $invokeRsCimMethodParameters = @{ + CimInstance = $Configuration + MethodName = 'SetVirtualDirectory' + Arguments = @{ + Application = $Application + VirtualDirectory = $VirtualDirectory + Lcid = $Lcid + } + } + + try + { + $null = Invoke-RsCimMethod @invokeRsCimMethodParameters + } + catch + { + $errorMessage = $script:localizedData.Set_SqlDscRSVirtualDirectory_FailedToSet -f $instanceName, $_.Exception.Message + + $errorRecord = New-ErrorRecord -Exception (New-InvalidOperationException -Message $errorMessage -PassThru) -ErrorId 'SSRSVD0001' -ErrorCategory 'InvalidOperation' -TargetObject $Configuration + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + + if ($PassThru.IsPresent) + { + return $Configuration + } + } +} diff --git a/source/en-US/SqlServerDsc.strings.psd1 b/source/en-US/SqlServerDsc.strings.psd1 index 8a30d40e58..f30f6e634b 100644 --- a/source/en-US/SqlServerDsc.strings.psd1 +++ b/source/en-US/SqlServerDsc.strings.psd1 @@ -296,6 +296,14 @@ ConvertFrom-StringData @' Get_SqlDscRSConfiguration_FailedToGetConfiguration = Failed to get the configuration CIM instance for Reporting Services instance '{0}': {1} (GSRSCD0003) Get_SqlDscRSConfiguration_ConfigurationNotFound = Could not find the configuration CIM instance for Reporting Services instance '{0}'. (GSRSCD0004) + ## Get-SqlDscRSWebPortalApplicationName + Get_SqlDscRSWebPortalApplicationName_GettingApplicationName = Getting web portal application name. + + Get_SqlDscRSWebPortalApplicationName_ApplicationName = Web portal application name is '{0}'. + + ## Get-SqlDscRSVersion + Get_SqlDscRSVersion_VersionNotFound = Could not determine the version. (GSRSV0001) + ## Enable-SqlDscRsSecureConnection Enable_SqlDscRsSecureConnection_Enabling = Enabling secure connection for Reporting Services instance '{0}'. Enable_SqlDscRsSecureConnection_ShouldProcessDescription = Enabling secure connection (secure connection level 1) for the Reporting Services instance '{0}'. @@ -706,4 +714,46 @@ ConvertFrom-StringData @' Get_SqlDscRSPackage_GettingVersionFromFile = Getting version information from file '{0}'. (GSDRSP0001) Get_SqlDscRSPackage_InvalidProductName = The product name '{0}' is not a valid Reporting Services package. Expected product names are: '{1}'. Use the Force parameter to skip this validation. (GSDRSP0002) Get_SqlDscRSPackage_ReturningVersionInfo = Returning version information for '{0}' version '{1}'. (GSDRSP0003) + + ## Get-OperatingSystem + Get_OperatingSystem_Getting = Getting operating system information. + Get_OperatingSystem_FailedToGet = Failed to get operating system information. Unable to find WMI object Win32_OperatingSystem. (GOS0001) + + ## Get-SqlDscRSUrlReservation + Get_SqlDscRSUrlReservation_Getting = Getting URL reservations for Reporting Services instance '{0}'. + Get_SqlDscRSUrlReservation_FailedToGet = Failed to get URL reservations for Reporting Services instance '{0}'. {1} (GSRUR0001) + + ## Add-SqlDscRSUrlReservation + Add_SqlDscRSUrlReservation_Adding = Adding URL reservation '{0}' for application '{1}' on Reporting Services instance '{2}'. + Add_SqlDscRSUrlReservation_ShouldProcessDescription = Adding URL reservation '{0}' for application '{1}' on Reporting Services instance '{2}'. + Add_SqlDscRSUrlReservation_ShouldProcessConfirmation = Are you sure you want to add URL reservation '{0}' for application '{1}'? + # This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages. + Add_SqlDscRSUrlReservation_ShouldProcessCaption = Add URL reservation for Reporting Services instance + Add_SqlDscRSUrlReservation_FailedToAdd = Failed to add URL reservation for Reporting Services instance '{0}'. {1} (ASRUR0001) + + ## Remove-SqlDscRSUrlReservation + Remove_SqlDscRSUrlReservation_Removing = Removing URL reservation '{0}' for application '{1}' on Reporting Services instance '{2}'. + Remove_SqlDscRSUrlReservation_ShouldProcessDescription = Removing URL reservation '{0}' for application '{1}' on Reporting Services instance '{2}'. + Remove_SqlDscRSUrlReservation_ShouldProcessConfirmation = Are you sure you want to remove URL reservation '{0}' for application '{1}'? + # This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages. + Remove_SqlDscRSUrlReservation_ShouldProcessCaption = Remove URL reservation for Reporting Services instance + Remove_SqlDscRSUrlReservation_FailedToRemove = Failed to remove URL reservation for Reporting Services instance '{0}'. {1} (RSRUR0001) + + ## Set-SqlDscRSUrlReservation + Set_SqlDscRSUrlReservation_ShouldProcessVerboseDescription = Setting URL reservations for application '{0}' on Reporting Services instance '{1}'. + Set_SqlDscRSUrlReservation_ShouldProcessVerboseWarning = Are you sure you want to set URL reservations for application '{0}' on Reporting Services instance '{1}'? Existing reservations not in the specified list will be removed. + # This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages. + Set_SqlDscRSUrlReservation_ShouldProcessCaption = Set URL reservations for Reporting Services instance + Set_SqlDscRSUrlReservation_CurrentUrls = Current URL reservations for application '{0}': {1} + Set_SqlDscRSUrlReservation_DesiredUrls = Desired URL reservations for application '{0}': {1} + Set_SqlDscRSUrlReservation_RemovingUrl = Removing URL reservation '{0}' for application '{1}' on Reporting Services instance '{2}'. + Set_SqlDscRSUrlReservation_AddingUrl = Adding URL reservation '{0}' for application '{1}' on Reporting Services instance '{2}'. + + ## Set-SqlDscRSVirtualDirectory + Set_SqlDscRSVirtualDirectory_Setting = Setting virtual directory '{0}' for application '{1}' on Reporting Services instance '{2}'. + Set_SqlDscRSVirtualDirectory_ShouldProcessDescription = Setting virtual directory '{0}' for application '{1}' on Reporting Services instance '{2}'. + Set_SqlDscRSVirtualDirectory_ShouldProcessConfirmation = Are you sure you want to set virtual directory '{0}' for application '{1}'? + # This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages. + Set_SqlDscRSVirtualDirectory_ShouldProcessCaption = Set virtual directory for Reporting Services instance + Set_SqlDscRSVirtualDirectory_FailedToSet = Failed to set virtual directory for Reporting Services instance '{0}'. {1} (SSRSVD0001) '@ diff --git a/tests/Integration/Commands/Add-SqlDscRSUrlReservation.Integration.Tests.ps1 b/tests/Integration/Commands/Add-SqlDscRSUrlReservation.Integration.Tests.ps1 new file mode 100644 index 0000000000..0584e78dfe --- /dev/null +++ b/tests/Integration/Commands/Add-SqlDscRSUrlReservation.Integration.Tests.ps1 @@ -0,0 +1,246 @@ +[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' + + # Do not use -Force. Doing so, or unloading the module in AfterAll, causes + # PowerShell class types to get new identities, breaking type comparisons. + Import-Module -Name $script:moduleName -ErrorAction 'Stop' +} + +Describe 'Add-SqlDscRSUrlReservation' { + Context 'When adding URL reservation for SQL Server Reporting Services' -Tag @('Integration_SQL2017_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Store original URL reservations to restore later + $script:originalReservations = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18080 + $script:testUrl = "http://+:$script:testPort" + } + + AfterAll { + # Clean up: remove the test URL reservation if it was added + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should add URL reservation using pipeline' { + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + # Verify the URL was added + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlString | Should -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First remove the test URL if it exists + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore + } + + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $result = $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When adding URL reservation for SQL Server Reporting Services' -Tag @('Integration_SQL2019_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18080 + $script:testUrl = "http://+:$script:testPort" + } + + AfterAll { + # Clean up: remove the test URL reservation if it was added + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should add URL reservation using pipeline' { + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + # Verify the URL was added + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlString | Should -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First remove the test URL if it exists + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore + } + + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $result = $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When adding URL reservation for SQL Server Reporting Services' -Tag @('Integration_SQL2022_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18080 + $script:testUrl = "http://+:$script:testPort" + } + + AfterAll { + # Clean up: remove the test URL reservation if it was added + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should add URL reservation using pipeline' { + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + # Verify the URL was added + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlString | Should -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First remove the test URL if it exists + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore + } + + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $result = $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When adding URL reservation for Power BI Report Server' -Tag @('Integration_PowerBI') { + # cSpell: ignore PBIRS + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18080 + $script:testUrl = "http://+:$script:testPort" + } + + AfterAll { + # Clean up: remove the test URL reservation if it was added + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should add URL reservation for PBIRS using pipeline' { + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + # Verify the URL was added + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlString | Should -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First remove the test URL if it exists + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore + } + + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + $result = $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'PBIRS' + } + } +} diff --git a/tests/Integration/Commands/Get-SqlDscRSUrlReservation.Integration.Tests.ps1 b/tests/Integration/Commands/Get-SqlDscRSUrlReservation.Integration.Tests.ps1 new file mode 100644 index 0000000000..6a806e2d14 --- /dev/null +++ b/tests/Integration/Commands/Get-SqlDscRSUrlReservation.Integration.Tests.ps1 @@ -0,0 +1,171 @@ +[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' + + # Do not use -Force. Doing so, or unloading the module in AfterAll, causes + # PowerShell class types to get new identities, breaking type comparisons. + Import-Module -Name $script:moduleName -ErrorAction 'Stop' +} + +Describe 'Get-SqlDscRSUrlReservation' { + Context 'When getting URL reservations for SQL Server Reporting Services' -Tag @('Integration_SQL2017_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + } + + It 'Should return URL reservations using pipeline' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return URL reservations using Configuration parameter' { + $result = Get-SqlDscRSUrlReservation -Configuration $script:configuration -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return result with expected properties' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # The result should be a CIM method result with URL reservation properties + $result | Should -Not -BeNullOrEmpty + $result.HRESULT | Should -Be 0 + + <# + Application and UrlString properties may be empty arrays if no URL + reservations exist (e.g., freshly installed but not initialized SSRS). + Just verify the properties exist. + #> + $result.PSObject.Properties.Name | Should -Contain 'Application' + $result.PSObject.Properties.Name | Should -Contain 'UrlString' + } + } + + Context 'When getting URL reservations for SQL Server Reporting Services' -Tag @('Integration_SQL2019_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + } + + It 'Should return URL reservations using pipeline' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return URL reservations using Configuration parameter' { + $result = Get-SqlDscRSUrlReservation -Configuration $script:configuration -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return result with expected properties' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # The result should be a CIM method result with URL reservation properties + $result | Should -Not -BeNullOrEmpty + $result.HRESULT | Should -Be 0 + + <# + Application and UrlString properties may be empty arrays if no URL + reservations exist (e.g., freshly installed but not initialized SSRS). + Just verify the properties exist. + #> + $result.PSObject.Properties.Name | Should -Contain 'Application' + $result.PSObject.Properties.Name | Should -Contain 'UrlString' + } + } + + Context 'When getting URL reservations for SQL Server Reporting Services' -Tag @('Integration_SQL2022_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + } + + It 'Should return URL reservations using pipeline' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return URL reservations using Configuration parameter' { + $result = Get-SqlDscRSUrlReservation -Configuration $script:configuration -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return result with expected properties' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # The result should be a CIM method result with URL reservation properties + $result | Should -Not -BeNullOrEmpty + $result.HRESULT | Should -Be 0 + + <# + Application and UrlString properties may be empty arrays if no URL + reservations exist (e.g., freshly installed but not initialized SSRS). + Just verify the properties exist. + #> + $result.PSObject.Properties.Name | Should -Contain 'Application' + $result.PSObject.Properties.Name | Should -Contain 'UrlString' + } + } + + Context 'When getting URL reservations for Power BI Report Server' -Tag @('Integration_PowerBI') { + # cSpell: ignore PBIRS + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + } + + It 'Should return URL reservations using pipeline' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return URL reservations using Configuration parameter' { + $result = Get-SqlDscRSUrlReservation -Configuration $script:configuration -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + } + + It 'Should return result with expected properties' { + $result = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # The result should be a CIM method result with URL reservation properties + $result | Should -Not -BeNullOrEmpty + $result.HRESULT | Should -Be 0 + + <# + Application and UrlString properties may be empty arrays if no URL + reservations exist (e.g., freshly installed but not initialized PBIRS). + Just verify the properties exist. + #> + $result.PSObject.Properties.Name | Should -Contain 'Application' + $result.PSObject.Properties.Name | Should -Contain 'UrlString' + } + } +} diff --git a/tests/Integration/Commands/README.md b/tests/Integration/Commands/README.md index 71adea6370..3016c2825a 100644 --- a/tests/Integration/Commands/README.md +++ b/tests/Integration/Commands/README.md @@ -165,6 +165,13 @@ Get-SqlDscInstalledInstance | 2 | 1 (Install-SqlDscReportingService), 0 (Prerequ Get-SqlDscRSPackage | 2 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - Get-SqlDscRSSetupConfiguration | 2 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - Test-SqlDscRSInstalled | 2 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Get-SqlDscRSConfiguration | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Enable-SqlDscRsSecureConnection | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Disable-SqlDscRsSecureConnection | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Get-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Add-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Remove-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - +Set-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscReportingService), 0 (Prerequisites) | SSRS | - Repair-SqlDscReportingService | 8 | 1 (Install-SqlDscReportingService) | SSRS | - Uninstall-SqlDscReportingService | 9 | 8 (Repair-SqlDscReportingService) | - | - @@ -184,6 +191,13 @@ Get-SqlDscInstalledInstance | 2 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prer Get-SqlDscRSPackage | 2 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - Get-SqlDscRSSetupConfiguration | 2 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - Test-SqlDscRSInstalled | 2 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Get-SqlDscRSConfiguration | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Enable-SqlDscRsSecureConnection | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Disable-SqlDscRsSecureConnection | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Get-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Add-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Remove-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - +Set-SqlDscRSUrlReservation | 3 | 1 (Install-SqlDscPowerBIReportServer), 0 (Prerequisites) | PBIRS | - Repair-SqlDscPowerBIReportServer | 8 | 1 (Install-SqlDscPowerBIReportServer) | PBIRS | - Uninstall-SqlDscPowerBIReportServer | 9 | 8 (Repair-SqlDscPowerBIReportServer) | - | - diff --git a/tests/Integration/Commands/Remove-SqlDscRSUrlReservation.Integration.Tests.ps1 b/tests/Integration/Commands/Remove-SqlDscRSUrlReservation.Integration.Tests.ps1 new file mode 100644 index 0000000000..16fa1d0d25 --- /dev/null +++ b/tests/Integration/Commands/Remove-SqlDscRSUrlReservation.Integration.Tests.ps1 @@ -0,0 +1,227 @@ +[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' + + # Do not use -Force. Doing so, or unloading the module in AfterAll, causes + # PowerShell class types to get new identities, breaking type comparisons. + Import-Module -Name $script:moduleName -ErrorAction 'Stop' +} + +Describe 'Remove-SqlDscRSUrlReservation' { + Context 'When removing URL reservation for SQL Server Reporting Services' -Tag @('Integration_SQL2017_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18081 + $script:testUrl = "http://+:$script:testPort" + + # Add a test URL reservation to remove + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + } + + AfterAll { + # Clean up: ensure the test URL reservation is removed + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should remove URL reservation using pipeline' { + { $script:configuration | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the URL was removed + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlReservations | Should -Not -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First add the test URL back + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $result = $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When removing URL reservation for SQL Server Reporting Services' -Tag @('Integration_SQL2019_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18081 + $script:testUrl = "http://+:$script:testPort" + + # Add a test URL reservation to remove + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + } + + AfterAll { + # Clean up: ensure the test URL reservation is removed + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should remove URL reservation using pipeline' { + { $script:configuration | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the URL was removed + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlReservations | Should -Not -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First add the test URL back + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $result = $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When removing URL reservation for SQL Server Reporting Services' -Tag @('Integration_SQL2022_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18081 + $script:testUrl = "http://+:$script:testPort" + + # Add a test URL reservation to remove + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + } + + AfterAll { + # Clean up: ensure the test URL reservation is removed + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should remove URL reservation using pipeline' { + { $script:configuration | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the URL was removed + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlReservations | Should -Not -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First add the test URL back + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' + $result = $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When removing URL reservation for Power BI Report Server' -Tag @('Integration_PowerBI') { + # cSpell: ignore PBIRS + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + + # Use a unique port for testing to avoid conflicts + $script:testPort = 18081 + $script:testUrl = "http://+:$script:testPort" + + # Add a test URL reservation to remove + $script:configuration | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + } + + AfterAll { + # Clean up: ensure the test URL reservation is removed + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'SilentlyContinue' + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should remove URL reservation for PBIRS using pipeline' { + { $script:configuration | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the URL was removed + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + $reservations.UrlReservations | Should -Not -Contain $script:testUrl + } + + It 'Should return configuration when using PassThru' { + # First add the test URL back + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -ErrorAction 'Stop' + + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' + $result = $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'PBIRS' + } + } +} diff --git a/tests/Integration/Commands/Set-SqlDscRSUrlReservation.Integration.Tests.ps1 b/tests/Integration/Commands/Set-SqlDscRSUrlReservation.Integration.Tests.ps1 new file mode 100644 index 0000000000..ee57dd98d6 --- /dev/null +++ b/tests/Integration/Commands/Set-SqlDscRSUrlReservation.Integration.Tests.ps1 @@ -0,0 +1,434 @@ +[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' + + # Do not use -Force. Doing so, or unloading the module in AfterAll, causes + # PowerShell class types to get new identities, breaking type comparisons. + Import-Module -Name $script:moduleName -ErrorAction 'Stop' +} + +Describe 'Set-SqlDscRSUrlReservation' { + Context 'When setting URL reservations for SQL Server Reporting Services' -Tag @('Integration_SQL2017_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Store original URL reservations to restore later + $script:originalReservations = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get current URLs for ReportServerWebService to restore later + $script:originalWebServiceUrls = @() + + if ($null -ne $script:originalReservations.Application) + { + for ($i = 0; $i -lt $script:originalReservations.Application.Count; $i++) + { + if ($script:originalReservations.Application[$i] -eq 'ReportServerWebService') + { + $script:originalWebServiceUrls += $script:originalReservations.UrlString[$i] + } + } + } + + # Use unique ports for testing to avoid conflicts + $script:testUrl1 = 'http://+:18081' + $script:testUrl2 = 'http://+:18082' + } + + AfterAll { + # Clean up: restore original URL reservations + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Remove test URLs if they exist + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'SilentlyContinue' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl2 -Force -ErrorAction 'SilentlyContinue' + + # Restore original URLs + foreach ($url in $script:originalWebServiceUrls) + { + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $url -Force -ErrorAction 'SilentlyContinue' + } + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should set URL reservations using pipeline' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'Stop' + + # Verify the URLs are set correctly + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + } + + It 'Should add multiple URLs and remove existing ones' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1, $script:testUrl2 -Force -ErrorAction 'Stop' + + # Verify both URLs are set + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + $currentUrls | Should -Contain $script:testUrl2 + } + + It 'Should return configuration when using PassThru' { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $result = $config | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting URL reservations for SQL Server Reporting Services' -Tag @('Integration_SQL2019_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Store original URL reservations to restore later + $script:originalReservations = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get current URLs for ReportServerWebService to restore later + $script:originalWebServiceUrls = @() + + if ($null -ne $script:originalReservations.Application) + { + for ($i = 0; $i -lt $script:originalReservations.Application.Count; $i++) + { + if ($script:originalReservations.Application[$i] -eq 'ReportServerWebService') + { + $script:originalWebServiceUrls += $script:originalReservations.UrlString[$i] + } + } + } + + # Use unique ports for testing to avoid conflicts + $script:testUrl1 = 'http://+:18081' + $script:testUrl2 = 'http://+:18082' + } + + AfterAll { + # Clean up: restore original URL reservations + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Remove test URLs if they exist + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'SilentlyContinue' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl2 -Force -ErrorAction 'SilentlyContinue' + + # Restore original URLs + foreach ($url in $script:originalWebServiceUrls) + { + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $url -Force -ErrorAction 'SilentlyContinue' + } + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should set URL reservations using pipeline' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'Stop' + + # Verify the URLs are set correctly + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + } + + It 'Should add multiple URLs and remove existing ones' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1, $script:testUrl2 -Force -ErrorAction 'Stop' + + # Verify both URLs are set + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + $currentUrls | Should -Contain $script:testUrl2 + } + + It 'Should return configuration when using PassThru' { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $result = $config | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting URL reservations for SQL Server Reporting Services' -Tag @('Integration_SQL2022_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Store original URL reservations to restore later + $script:originalReservations = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get current URLs for ReportServerWebService to restore later + $script:originalWebServiceUrls = @() + + if ($null -ne $script:originalReservations.Application) + { + for ($i = 0; $i -lt $script:originalReservations.Application.Count; $i++) + { + if ($script:originalReservations.Application[$i] -eq 'ReportServerWebService') + { + $script:originalWebServiceUrls += $script:originalReservations.UrlString[$i] + } + } + } + + # Use unique ports for testing to avoid conflicts + $script:testUrl1 = 'http://+:18081' + $script:testUrl2 = 'http://+:18082' + } + + AfterAll { + # Clean up: restore original URL reservations + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + # Remove test URLs if they exist + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'SilentlyContinue' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl2 -Force -ErrorAction 'SilentlyContinue' + + # Restore original URLs + foreach ($url in $script:originalWebServiceUrls) + { + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $url -Force -ErrorAction 'SilentlyContinue' + } + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should set URL reservations using pipeline' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'Stop' + + # Verify the URLs are set correctly + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + } + + It 'Should add multiple URLs and remove existing ones' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1, $script:testUrl2 -Force -ErrorAction 'Stop' + + # Verify both URLs are set + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + $currentUrls | Should -Contain $script:testUrl2 + } + + It 'Should return configuration when using PassThru' { + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + $result = $config | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting URL reservations for Power BI Report Server' -Tag @('Integration_PBIRS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + + # Store original URL reservations to restore later + $script:originalReservations = $script:configuration | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get current URLs for ReportServerWebService to restore later + $script:originalWebServiceUrls = @() + + if ($null -ne $script:originalReservations.Application) + { + for ($i = 0; $i -lt $script:originalReservations.Application.Count; $i++) + { + if ($script:originalReservations.Application[$i] -eq 'ReportServerWebService') + { + $script:originalWebServiceUrls += $script:originalReservations.UrlString[$i] + } + } + } + + # Use unique ports for testing to avoid conflicts + $script:testUrl1 = 'http://+:18081' + $script:testUrl2 = 'http://+:18082' + } + + AfterAll { + # Clean up: restore original URL reservations + try + { + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + + # Remove test URLs if they exist + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'SilentlyContinue' + $config | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl2 -Force -ErrorAction 'SilentlyContinue' + + # Restore original URLs + foreach ($url in $script:originalWebServiceUrls) + { + $config | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $url -Force -ErrorAction 'SilentlyContinue' + } + } + catch + { + # Ignore errors during cleanup + } + } + + It 'Should set URL reservations using pipeline' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -ErrorAction 'Stop' + + # Verify the URLs are set correctly + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + } + + It 'Should add multiple URLs and remove existing ones' { + $script:configuration | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1, $script:testUrl2 -Force -ErrorAction 'Stop' + + # Verify both URLs are set + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + $reservations = $config | Get-SqlDscRSUrlReservation -ErrorAction 'Stop' + + # Get URLs for the specified application + $currentUrls = @() + + for ($i = 0; $i -lt $reservations.Application.Count; $i++) + { + if ($reservations.Application[$i] -eq 'ReportServerWebService') + { + $currentUrls += $reservations.UrlString[$i] + } + } + + $currentUrls | Should -Contain $script:testUrl1 + $currentUrls | Should -Contain $script:testUrl2 + } + + It 'Should return configuration when using PassThru' { + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + $result = $config | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString $script:testUrl1 -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'PBIRS' + } + } +} diff --git a/tests/Integration/Commands/Set-SqlDscRSVirtualDirectory.Integration.Tests.ps1 b/tests/Integration/Commands/Set-SqlDscRSVirtualDirectory.Integration.Tests.ps1 new file mode 100644 index 0000000000..c66f6103fe --- /dev/null +++ b/tests/Integration/Commands/Set-SqlDscRSVirtualDirectory.Integration.Tests.ps1 @@ -0,0 +1,123 @@ +[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' + + # Do not use -Force. Doing so, or unloading the module in AfterAll, causes + # PowerShell class types to get new identities, breaking type comparisons. + Import-Module -Name $script:moduleName -ErrorAction 'Stop' +} + +Describe 'Set-SqlDscRSVirtualDirectory' { + Context 'When setting virtual directory for SQL Server Reporting Services' -Tag @('Integration_SQL2017_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + } + + It 'Should set virtual directory for ReportServerWebService using pipeline' { + { $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the virtual directory was set + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + $config.VirtualDirectoryReportServer | Should -Be 'ReportServer' + } + + It 'Should return configuration when using PassThru' { + $result = $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting virtual directory for SQL Server Reporting Services' -Tag @('Integration_SQL2019_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + } + + It 'Should set virtual directory for ReportServerWebService using pipeline' { + { $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the virtual directory was set + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + $config.VirtualDirectoryReportServer | Should -Be 'ReportServer' + } + + It 'Should return configuration when using PassThru' { + $result = $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting virtual directory for SQL Server Reporting Services' -Tag @('Integration_SQL2022_RS') { + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + } + + It 'Should set virtual directory for ReportServerWebService using pipeline' { + { $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the virtual directory was set + $config = Get-SqlDscRSConfiguration -InstanceName 'SSRS' -ErrorAction 'Stop' + + $config.VirtualDirectoryReportServer | Should -Be 'ReportServer' + } + + It 'Should return configuration when using PassThru' { + $result = $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting virtual directory for Power BI Report Server' -Tag @('Integration_PowerBI') { + # cSpell: ignore PBIRS + BeforeAll { + $script:configuration = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + } + + It 'Should set virtual directory for ReportServerWebService using pipeline' { + { $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -ErrorAction 'Stop' } | Should -Not -Throw + + # Verify the virtual directory was set + $config = Get-SqlDscRSConfiguration -InstanceName 'PBIRS' -ErrorAction 'Stop' + + $config.VirtualDirectoryReportServer | Should -Be 'ReportServer' + } + + It 'Should return configuration when using PassThru' { + $result = $script:configuration | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force -PassThru -ErrorAction 'Stop' + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'PBIRS' + } + } +} diff --git a/tests/Unit/DSC_SqlRS.Tests.ps1 b/tests/Unit/DSC_SqlRS.Tests.ps1 index e4344e547e..f5305c9ca0 100644 --- a/tests/Unit/DSC_SqlRS.Tests.ps1 +++ b/tests/Unit/DSC_SqlRS.Tests.ps1 @@ -99,8 +99,8 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { } -PassThru | Add-Member -MemberType ScriptProperty -Name 'UrlString' -Value { return @( - $mockDynamicReportsApplicationUrlString, - $mockDynamicReportServerApplicationUrlString + $mockDynamicReportServerApplicationUrlString, + $mockDynamicReportsApplicationUrlString ) } -PassThru -Force } @@ -142,9 +142,7 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { Add-Member -MemberType NoteProperty -Name 'ServiceName' -Value $mockReportingServicesServiceName -PassThru -Force } - Mock -CommandName Invoke-RsCimMethod -MockWith $mockInvokeRsCimMethod_ListReservedUrls -ParameterFilter { - $MethodName -eq 'ListReservedUrls' - } + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith $mockInvokeRsCimMethod_ListReservedUrls InModuleScope -ScriptBlock { $script:mockNamedInstanceName = 'INSTANCE' @@ -162,11 +160,18 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { Context 'When the system is in the desired state' { BeforeAll { - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = 13 + InstanceName = $mockNamedInstanceName + CurrentVersion = '13.0.0.0' } } @@ -216,9 +221,7 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { $resultGetTargetResource.UseSsl | Should -BeFalse } - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ListReservedUrls' - } -Exactly -Times 1 -Scope It + Should -Invoke -CommandName Get-SqlDscRSUrlReservation -Exactly -Times 1 -Scope It } Context 'When SSL is not used' { @@ -256,11 +259,18 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { Context 'When the system is not in the desired state' { BeforeAll { - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_DefaultInstance)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_DefaultInstance)[0] - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = 13 + InstanceName = $mockDefaultInstanceName + CurrentVersion = '13.0.0.0' } } @@ -303,9 +313,7 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { $resultGetTargetResource.ReportsReservedUrl | Should -BeNullOrEmpty } - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ListReservedUrls' - } -Exactly -Times 0 -Scope It + Should -Invoke -CommandName Get-SqlDscRSUrlReservation -Exactly -Times 0 -Scope It } # Regression test for issue #822. @@ -345,10 +353,8 @@ Describe 'SqlRS\Get-TargetResource' -Tag 'Get' { Context 'When there is no Reporting Services instance' { BeforeAll { - Mock -CommandName Get-ReportingServicesData -MockWith { - return @{ - Configuration = $null - } + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return $null } } @@ -437,8 +443,8 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { } -PassThru | Add-Member -MemberType ScriptProperty -Name 'UrlString' -Value { return @( - $mockDynamicReportsApplicationUrlString, - $mockDynamicReportServerApplicationUrlString + $mockDynamicReportServerApplicationUrlString, + $mockDynamicReportsApplicationUrlString ) } -PassThru -Force } @@ -506,9 +512,7 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { $ClassName -eq 'Win32_OperatingSystem' } - Mock -CommandName Invoke-RsCimMethod -MockWith $mockInvokeRsCimMethod_ListReservedUrls -ParameterFilter { - $MethodName -eq 'ListReservedUrls' - } + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith $mockInvokeRsCimMethod_ListReservedUrls <# This is mocked here so that no calls are made to it directly, @@ -522,6 +526,10 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { Mock -CommandName Disable-SqlDscRsSecureConnection Mock -CommandName Restart-ReportingServicesService Mock -CommandName Start-Sleep + Mock -CommandName Set-SqlDscRSVirtualDirectory + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + Mock -CommandName Set-SqlDscRSUrlReservation Mock -CommandName Invoke-RsCimMethod Mock -CommandName Invoke-RsCimMethod -MockWith $mockInvokeRsCimMethod_GenerateDatabaseCreationScript -ParameterFilter { $MethodName -eq 'GenerateDatabaseCreationScript' @@ -567,14 +575,25 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { BeforeAll { $mockDynamicIsInitialized = $false - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = $TestCaseVersion + InstanceName = $mockNamedInstanceName + CurrentVersion = "$TestCaseVersion.0.0.0" } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] "$TestCaseVersion.0.0.0" + } + Mock -CommandName Test-TargetResource -MockWith { return $true } @@ -622,20 +641,20 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { $MethodName -eq 'GenerateDatabaseCreationScript' } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportsApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationName } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope It @@ -715,14 +734,25 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { ) } - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_ServiceNameNull)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_ServiceNameNull)[0] - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = 14 + InstanceName = $mockNamedInstanceName + CurrentVersion = '14.0.0.0' } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '14.0.0.0' + } + Mock -CommandName Get-CimInstance ` -MockWith $mockGetCimInstance_Language ` -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter @@ -743,17 +773,30 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { } It 'Should throw the correct error message when ServiceName is empty' { - Mock -CommandName Get-ReportingServicesData -MockWith { - return @{ - Configuration = New-Object -TypeName Microsoft.Management.Infrastructure.CimInstance -ArgumentList @( + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return ( + New-Object -TypeName Microsoft.Management.Infrastructure.CimInstance -ArgumentList @( 'MSReportServer_ConfigurationSetting' 'root/Microsoft/SQLServer/ReportServer/RS_SQL2016/v14/Admin' ) | Add-Member -MemberType NoteProperty -Name 'ServiceName' -Value '' -PassThru -Force - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = 14 + ) + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { + return @{ + InstanceName = $mockNamedInstanceName + CurrentVersion = '14.0.0.0' } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '14.0.0.0' + } + InModuleScope -ScriptBlock { Set-StrictMode -Version 1.0 @@ -773,14 +816,25 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { BeforeAll { $mockDynamicIsInitialized = $true - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = $TestCaseVersion + InstanceName = $mockNamedInstanceName + CurrentVersion = "$TestCaseVersion.0.0.0" } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] "$TestCaseVersion.0.0.0" + } + Mock -CommandName Get-TargetResource -MockWith { return @{ ReportServerReservedUrl = $mockReportServerApplicationUrl @@ -815,13 +869,13 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { Should -Invoke -CommandName Enable-SqlDscRsSecureConnection -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { $MethodName -eq 'InitializeReportServer' @@ -839,21 +893,21 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { $MethodName -eq 'GenerateDatabaseCreationScript' } -Exactly -Times 0 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportsApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope It Should -Invoke -CommandName Invoke-SqlDscQuery -Exactly -Times 0 -Scope It @@ -865,14 +919,25 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { BeforeAll { $mockDynamicIsInitialized = $true - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = $TestCaseVersion + InstanceName = $mockNamedInstanceName + CurrentVersion = "$TestCaseVersion.0.0.0" } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] "$TestCaseVersion.0.0.0" + } + Mock -CommandName Get-TargetResource -MockWith { return @{ ReportServerReservedUrl = $mockReportServerApplicationUrl @@ -908,13 +973,13 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { Should -Invoke -CommandName Enable-SqlDscRsSecureConnection -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { $MethodName -eq 'InitializeReportServer' @@ -932,21 +997,21 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { $MethodName -eq 'GenerateDatabaseCreationScript' } -Exactly -Times 0 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportsApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 2 -Scope It + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope It Should -Invoke -CommandName Invoke-SqlDscQuery -Exactly -Times 0 -Scope It @@ -973,14 +1038,25 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { BeforeEach { # This mocks the SQL Server Reporting Services 2014 and older - Mock -CommandName Get-ReportingServicesData -MockWith { + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + return (& $mockGetCimInstance_ConfigurationSetting_DefaultInstance)[0] + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportManager' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = (& $mockGetCimInstance_ConfigurationSetting_DefaultInstance)[0] - ReportsApplicationName = 'ReportManager' - SqlVersion = $TestCaseVersion + InstanceName = $mockDefaultInstanceName + CurrentVersion = "$TestCaseVersion.0.0.0" } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] "$TestCaseVersion.0.0.0" + } + Mock -CommandName Get-CimInstance ` -MockWith $mockGetCimInstance_Language ` -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter @@ -1009,20 +1085,20 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { $MethodName -eq 'GenerateDatabaseCreationScript' } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationNameLegacy + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportsApplicationNameLegacy } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationNameLegacy + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationNameLegacy } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope It @@ -1038,36 +1114,49 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { Context "When configuring a named instance of SQL Server Reporting Services 2019 that have been initialized by restarting the service" { BeforeAll { - $script:alreadyCalledGetReportingServicesData = $false + $script:alreadyCalledGetSqlDscRSConfiguration = $false $script:mockDynamicIsInitialized = $false $script:mockDynamicSecureConnectionLevel = $false - Mock -CommandName Get-ReportingServicesData -MockWith { - if ($script:alreadyCalledGetReportingServicesData) + Mock -CommandName Get-SqlDscRSConfiguration -MockWith { + if ($script:alreadyCalledGetSqlDscRSConfiguration) { $script:mockDynamicIsInitialized = $true } else { - $script:alreadyCalledGetReportingServicesData = $true + $script:alreadyCalledGetSqlDscRSConfiguration = $true } + return ( + New-Object -TypeName Microsoft.Management.Infrastructure.CimInstance -ArgumentList @( + 'MSReportServer_ConfigurationSetting' + 'root/Microsoft/SQLServer/ReportServer/RS_SQL2019/v15/Admin' + ) | Add-Member -MemberType NoteProperty -Name 'DatabaseServerName' -Value "$mockReportingServicesDatabaseServerName\$mockReportingServicesDatabaseNamedInstanceName" -PassThru | + Add-Member -MemberType NoteProperty -Name 'IsInitialized' -Value $script:mockDynamicIsInitialized -PassThru | + Add-Member -MemberType NoteProperty -Name 'InstanceName' -Value $mockNamedInstanceName -PassThru | + Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportServer' -Value $mockVirtualDirectoryReportServerName -PassThru | + Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportManager' -Value $mockVirtualDirectoryReportManagerName -PassThru | + Add-Member -MemberType NoteProperty -Name 'SecureConnectionLevel' -Value $script:mockDynamicSecureConnectionLevel -PassThru -Force | + Add-Member -MemberType NoteProperty -Name 'ServiceName' -Value $mockReportingServicesServiceName -PassThru -Force + ) + } + + Mock -CommandName Get-SqlDscRSWebPortalApplicationName -MockWith { + return 'ReportServerWebApp' + } + + Mock -CommandName Get-SqlDscRSSetupConfiguration -MockWith { return @{ - Configuration = New-Object -TypeName Microsoft.Management.Infrastructure.CimInstance -ArgumentList @( - 'MSReportServer_ConfigurationSetting' - 'root/Microsoft/SQLServer/ReportServer/RS_SQL2019/v15/Admin' - ) | Add-Member -MemberType NoteProperty -Name 'DatabaseServerName' -Value "$mockReportingServicesDatabaseServerName\$mockReportingServicesDatabaseNamedInstanceName" -PassThru | - Add-Member -MemberType NoteProperty -Name 'IsInitialized' -Value $script:mockDynamicIsInitialized -PassThru | - Add-Member -MemberType NoteProperty -Name 'InstanceName' -Value $mockNamedInstanceName -PassThru | - Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportServer' -Value $mockVirtualDirectoryReportServerName -PassThru | - Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportManager' -Value $mockVirtualDirectoryReportManagerName -PassThru | - Add-Member -MemberType NoteProperty -Name 'SecureConnectionLevel' -Value $script:mockDynamicSecureConnectionLevel -PassThru -Force | - Add-Member -MemberType NoteProperty -Name 'ServiceName' -Value $mockReportingServicesServiceName -PassThru -Force - ReportsApplicationName = 'ReportServerWebApp' - SqlVersion = $sqlVersion.Version + InstanceName = $mockNamedInstanceName + CurrentVersion = '15.0.0.0' } } + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '15.0.0.0' + } + Mock -CommandName Test-TargetResource -MockWith { return $true } @@ -1112,20 +1201,20 @@ Describe 'SqlRS\Set-TargetResource' -Tag 'Set' { $MethodName -eq 'GenerateDatabaseCreationScript' } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + Should -Invoke -CommandName Set-SqlDscRSVirtualDirectory -ParameterFilter { + $Application -eq $mockReportsApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportServerApplicationName } -Exactly -Times 1 -Scope It - Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Application -eq $mockReportsApplicationName } -Exactly -Times 1 -Scope It Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope It @@ -1526,254 +1615,3 @@ Describe 'SqlRS\Invoke-RsCimMethod' -Tag 'Helper' { } } } - -Describe 'SqlRS\Get-ReportingServicesData' -Tag 'Helper' { - BeforeAll { - $mockInstanceId = 'MSRS13.INSTANCE' # cSpell: disable-line - - $mockGetItemProperty_Sql2014 = { - return @{ - Version = '12.0.6024.0' - } - } - - $mockGetItemProperty_Sql2016 = { - return @{ - Version ='13.0.4001.0' - } - } - - $mockGetItemProperty_Sql2017 = { - return @{ - CurrentVersion = '14.0.6514.11481' - } - } - - $mockGetItemProperty_Sql2019 = { - return @{ - CurrentVersion = '15.0.2000.5' - } - } - - $mockGetItemProperty_InstanceNames_ParameterFilter = { - $Path -eq 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS' - } - - $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter = { - $Path -eq ('HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{0}\Setup' -f $mockInstanceId) - } - - $mockGetItemProperty_Sql2017AndSql2019_ParameterFilter = { - $Path -eq ('HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{0}\MSSQLServer\CurrentVersion' -f $mockInstanceId) - } - - # Inject a stub in the module scope to support testing cross-plattform - InModuleScope -ScriptBlock { - function script:Get-CimInstance - { - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('DscResource.AnalyzerRules\Measure-ParameterBlockParameterAttribute', '', Justification='The stub cannot use [Parameter()].')] - param - ( - $ClassName - ) - - return - } - } - } - - Context 'When there is a Reporting Services instance' { - BeforeAll { - Mock -CommandName Get-ItemProperty -MockWith { - return @{ - 'INSTANCE' = $mockInstanceId - } - } -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter - - Mock -CommandName Get-CimInstance -MockWith { - return @( - ( - New-Object -TypeName Microsoft.Management.Infrastructure.CimInstance -ArgumentList @( - 'MSReportServer_ConfigurationSetting' - 'root/Microsoft/SQLServer/ReportServer/RS_SQL2016/v13/Admin' - ) | Add-Member -MemberType NoteProperty -Name 'DatabaseServerName' -Value 'MockDatabaseServer\MockDatabaseInstance' -PassThru | - Add-Member -MemberType NoteProperty -Name 'IsInitialized' -Value $false -PassThru | - Add-Member -MemberType NoteProperty -Name 'InstanceName' -Value 'INSTANCE' -PassThru | - Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportServer' -Value 'ReportServer' -PassThru | - Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportManager' -Value 'Reports' -PassThru | - Add-Member -MemberType NoteProperty -Name 'SecureConnectionLevel' -Value $false -PassThru -Force - ), - ( - # Array is a regression test for issue #819. - New-Object -TypeName Object | - Add-Member -MemberType NoteProperty -Name 'DatabaseServerName' -Value 'MockDatabaseServer\MockDatabaseInstance' -PassThru | - Add-Member -MemberType NoteProperty -Name 'IsInitialized' -Value $true -PassThru | - Add-Member -MemberType NoteProperty -Name 'InstanceName' -Value 'DummyInstance' -PassThru -Force - ) - ) - } -ParameterFilter { - $ClassName -eq 'MSReportServer_ConfigurationSetting' - } - } - - Context 'When the instance is SQL Server Reporting Services 2014 or older' { - BeforeAll { - Mock -CommandName Test-Path -MockWith { - return $false - } - - Mock -CommandName Get-ItemProperty ` - -MockWith $mockGetItemProperty_Sql2014 ` - -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter - } - - It 'Should return the correct information' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName 'INSTANCE' - - $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] - $getReportingServicesDataResult.Configuration.InstanceName | Should -Be 'INSTANCE' - $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be 'MockDatabaseServer\MockDatabaseInstance' - $getReportingServicesDataResult.Configuration.IsInitialized | Should -BeFalse - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be 'ReportServer' - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be 'Reports' - $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 - $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportManager' - $getReportingServicesDataResult.SqlVersion | Should -Be '12' - } - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` - -Exactly -Times 2 -Scope 'It' - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter ` - -Exactly -Times 1 -Scope 'It' - - Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' - } - } - - Context 'When the instance is SQL Server Reporting Services 2016' { - BeforeAll { - Mock -CommandName Test-Path -MockWith { - return $false - } - - Mock -CommandName Get-ItemProperty ` - -MockWith $mockGetItemProperty_Sql2016 ` - -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter - } - - It 'Should return the correct information' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName 'INSTANCE' - - $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] - $getReportingServicesDataResult.Configuration.InstanceName | Should -Be 'INSTANCE' - $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be 'MockDatabaseServer\MockDatabaseInstance' - $getReportingServicesDataResult.Configuration.IsInitialized | Should -BeFalse - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be 'ReportServer' - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be 'Reports' - $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 - $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportServerWebApp' - $getReportingServicesDataResult.SqlVersion | Should -Be '13' - } - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` - -Exactly -Times 2 -Scope 'It' - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter ` - -Exactly -Times 1 -Scope 'It' - - Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' - } - } - - Context 'When the instance is SQL Server Reporting Services 2017' { - BeforeAll { - Mock -CommandName Test-Path -MockWith { - return $true - } - - Mock -CommandName Get-ItemProperty ` - -MockWith $mockGetItemProperty_Sql2017 ` - -ParameterFilter $mockGetItemProperty_Sql2017AndSql2019_ParameterFilter - } - - It 'Should return the correct information' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName 'INSTANCE' - - $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] - $getReportingServicesDataResult.Configuration.InstanceName | Should -Be 'INSTANCE' - $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be 'MockDatabaseServer\MockDatabaseInstance' - $getReportingServicesDataResult.Configuration.IsInitialized | Should -BeFalse - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be 'ReportServer' - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be 'Reports' - $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 - $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportServerWebApp' - $getReportingServicesDataResult.SqlVersion | Should -Be '14' - } - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` - -Exactly -Times 2 -Scope 'It' - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_Sql2017AndSql2019_ParameterFilter ` - -Exactly -Times 1 -Scope 'It' - - Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' - } - } - - Context 'When the instance is SQL Server Reporting Services 2019' { - BeforeAll { - Mock -CommandName Test-Path -MockWith { - return $true - } - - Mock -CommandName Get-ItemProperty ` - -MockWith $mockGetItemProperty_Sql2019 ` - -ParameterFilter $mockGetItemProperty_Sql2017AndSql2019_ParameterFilter - } - - It 'Should return the correct information' { - InModuleScope -ScriptBlock { - Set-StrictMode -Version 1.0 - - $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName 'INSTANCE' - - $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] - $getReportingServicesDataResult.Configuration.InstanceName | Should -Be 'INSTANCE' - $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be 'MockDatabaseServer\MockDatabaseInstance' - $getReportingServicesDataResult.Configuration.IsInitialized | Should -BeFalse - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be 'ReportServer' - $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be 'Reports' - $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 - $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportServerWebApp' - $getReportingServicesDataResult.SqlVersion | Should -Be '15' - } - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` - -Exactly -Times 2 -Scope 'It' - - Should -Invoke -CommandName Get-ItemProperty ` - -ParameterFilter $mockGetItemProperty_Sql2017AndSql2019_ParameterFilter ` - -Exactly -Times 1 -Scope 'It' - - Should -Invoke -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' - } - } - } -} diff --git a/tests/Unit/Private/Get-OperatingSystem.Tests.ps1 b/tests/Unit/Private/Get-OperatingSystem.Tests.ps1 new file mode 100644 index 0000000000..99bb772417 --- /dev/null +++ b/tests/Unit/Private/Get-OperatingSystem.Tests.ps1 @@ -0,0 +1,121 @@ +[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 -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName + + $env:SqlServerDscCI = $true + + InModuleScope -ScriptBlock { + <# + Stub for Get-CimInstance since it doesn't exist on macOS and + we need to be able to mock it. + #> + function script:Get-CimInstance + { + param + ( + [System.String] + $ClassName, + + [System.String] + $Namespace, + + [System.String] + $ErrorAction + ) + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + 'StubNotImplemented', + 'StubCalledError', + [System.Management.Automation.ErrorCategory]::InvalidOperation, + $MyInvocation.MyCommand + ) + ) + } + } +} + +AfterAll { + Remove-Item -Path 'env:SqlServerDscCI' -Force -ErrorAction 'SilentlyContinue' + + InModuleScope -ScriptBlock { + Remove-Item -Path 'function:script:Get-CimInstance' -Force -ErrorAction SilentlyContinue + } + + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') +} + +Describe 'Get-OperatingSystem' -Tag 'Private' { + Context 'When getting the operating system successfully' { + BeforeAll { + Mock -CommandName Get-CimInstance -MockWith { + return [PSCustomObject] @{ + OSLanguage = 1033 + Caption = 'Microsoft Windows Server 2022' + OSArchitecture = '64-bit' + } + } + } + + It 'Should return the operating system CIM instance' { + InModuleScope -ScriptBlock { + $result = Get-OperatingSystem + + $result | Should -Not -BeNullOrEmpty + $result.OSLanguage | Should -Be 1033 + $result.Caption | Should -Be 'Microsoft Windows Server 2022' + } + + Should -Invoke -CommandName Get-CimInstance -ParameterFilter { + $ClassName -eq 'Win32_OperatingSystem' -and + $Namespace -eq 'root/cimv2' + } -Exactly -Times 1 + } + } + + Context 'When failing to get the operating system' { + BeforeAll { + Mock -CommandName Get-CimInstance -MockWith { + return $null + } + } + + It 'Should throw a terminating error' { + InModuleScope -ScriptBlock { + { Get-OperatingSystem } | Should -Throw -ErrorId 'GOS0001,Get-OperatingSystem' + } + } + } +} diff --git a/tests/Unit/Public/Add-SqlDscRSUrlReservation.Tests.ps1 b/tests/Unit/Public/Add-SqlDscRSUrlReservation.Tests.ps1 new file mode 100644 index 0000000000..c5c7c11155 --- /dev/null +++ b/tests/Unit/Public/Add-SqlDscRSUrlReservation.Tests.ps1 @@ -0,0 +1,247 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Add-SqlDscRSUrlReservation' { + BeforeAll { + Mock -CommandName Get-OperatingSystem -MockWith { + return [PSCustomObject] @{ + OSLanguage = 1033 + } + } + } + + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Configuration] [-Application] [-UrlString] [[-Lcid] ] [-PassThru] [-Force] [-WhatIf] [-Confirm] []' + } + ) { + $result = (Get-Command -Name 'Add-SqlDscRSUrlReservation').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 adding URL reservation successfully' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should add URL reservation without errors' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and + $Arguments.Application -eq 'ReportServerWebService' -and + $Arguments.UrlString -eq 'http://+:80' -and + $Arguments.Lcid -eq 1033 + } -Exactly -Times 1 + } + + It 'Should not return anything by default' { + $result = $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false + + $result | Should -BeNullOrEmpty + } + } + + Context 'When adding URL reservation with PassThru' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should return the configuration CIM instance' { + $result = $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -PassThru -Confirm:$false + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When adding URL reservation with Force' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should add URL reservation without confirmation' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Force } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When adding URL reservation with custom Lcid' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should use the specified Lcid' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Lcid 1031 -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Lcid -eq 1031 + } -Exactly -Times 1 + } + + It 'Should not call Get-OperatingSystem when Lcid is specified' { + $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Lcid 1031 -Confirm:$false + + Should -Invoke -CommandName Get-OperatingSystem -Exactly -Times 0 + } + } + + Context 'When CIM method fails with ExtendedErrors' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method ReserveUrl() failed with an error. Error: Access denied;Permission error (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Throw -ErrorId 'ASRUR0001,Add-SqlDscRSUrlReservation' + } + } + + Context 'When CIM method fails with Error property' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method ReserveUrl() failed with an error. Error: Access denied (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Throw -ErrorId 'ASRUR0001,Add-SqlDscRSUrlReservation' + } + } + + Context 'When using WhatIf' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should not call Invoke-RsCimMethod' { + $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -WhatIf + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 0 + } + } + + Context 'When passing configuration as parameter' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should add URL reservation' { + { Add-SqlDscRSUrlReservation -Configuration $mockCimInstance -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When using different application types' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should accept ReportServerWebApp application' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportServerWebApp' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Application -eq 'ReportServerWebApp' + } -Exactly -Times 1 + } + + It 'Should accept ReportManager application' { + { $mockCimInstance | Add-SqlDscRSUrlReservation -Application 'ReportManager' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Application -eq 'ReportManager' + } -Exactly -Times 1 + } + } +} diff --git a/tests/Unit/Public/Get-SqlDscRSUrlReservation.Tests.ps1 b/tests/Unit/Public/Get-SqlDscRSUrlReservation.Tests.ps1 new file mode 100644 index 0000000000..25b51d9565 --- /dev/null +++ b/tests/Unit/Public/Get-SqlDscRSUrlReservation.Tests.ps1 @@ -0,0 +1,140 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Get-SqlDscRSUrlReservation' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + } + + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Configuration] []' + } + ) { + $result = (Get-Command -Name 'Get-SqlDscRSUrlReservation').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 URL reservations successfully' { + BeforeAll { + Mock -CommandName Invoke-RsCimMethod -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebService', 'ReportServerWebApp') + UrlString = @('http://+:80', 'http://+:80') + } + } + } + + It 'Should return URL reservations without errors' { + $result = $mockCimInstance | Get-SqlDscRSUrlReservation + + $result | Should -Not -BeNullOrEmpty + $result.Application | Should -HaveCount 2 + $result.UrlString | Should -HaveCount 2 + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ListReservedUrls' + } -Exactly -Times 1 + } + } + + Context 'When passing configuration as parameter' { + BeforeAll { + Mock -CommandName Invoke-RsCimMethod -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebService') + UrlString = @('http://+:80') + } + } + } + + It 'Should get URL reservations' { + $result = Get-SqlDscRSUrlReservation -Configuration $mockCimInstance + + $result | Should -Not -BeNullOrEmpty + $result.Application | Should -Contain 'ReportServerWebService' + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When CIM method fails with ExtendedErrors' { + BeforeAll { + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method ListReservedUrls() failed with an error. Error: Access denied;Permission error (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Get-SqlDscRSUrlReservation } | Should -Throw -ErrorId 'GSRUR0001,Get-SqlDscRSUrlReservation' + } + } + + Context 'When CIM method fails with Error property' { + BeforeAll { + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method ListReservedUrls() failed with an error. Error: Access denied (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Get-SqlDscRSUrlReservation } | Should -Throw -ErrorId 'GSRUR0001,Get-SqlDscRSUrlReservation' + } + } +} diff --git a/tests/Unit/Public/Get-SqlDscRSVersion.Tests.ps1 b/tests/Unit/Public/Get-SqlDscRSVersion.Tests.ps1 new file mode 100644 index 0000000000..46f766cec6 --- /dev/null +++ b/tests/Unit/Public/Get-SqlDscRSVersion.Tests.ps1 @@ -0,0 +1,165 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Get-SqlDscRSVersion' { + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Configuration] []' + } + ) { + $result = (Get-Command -Name 'Get-SqlDscRSVersion').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 the version successfully' { + It 'Should return the version for SQL Server 2016 (version 13)' { + $mockConfiguration = @{ + CurrentVersion = '13.0.4001.0' + } + + $result = $mockConfiguration | Get-SqlDscRSVersion + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 13 + $result.Minor | Should -Be 0 + $result.Build | Should -Be 4001 + $result.Revision | Should -Be 0 + } + + It 'Should return the version for SQL Server 2017 (version 14)' { + $mockConfiguration = @{ + CurrentVersion = '14.0.600.250' + } + + $result = $mockConfiguration | Get-SqlDscRSVersion + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 14 + $result.Minor | Should -Be 0 + $result.Build | Should -Be 600 + $result.Revision | Should -Be 250 + } + + It 'Should return the version for SQL Server 2019 (version 15)' { + $mockConfiguration = @{ + CurrentVersion = '15.0.1100.0' + } + + $result = $mockConfiguration | Get-SqlDscRSVersion + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 15 + } + + It 'Should return the version for SQL Server 2022 (version 16)' { + $mockConfiguration = @{ + CurrentVersion = '16.0.1000.6' + } + + $result = $mockConfiguration | Get-SqlDscRSVersion + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 16 + } + + It 'Should return the version for SQL Server 2014 (version 12)' { + $mockConfiguration = @{ + CurrentVersion = '12.0.4100.0' + } + + $result = $mockConfiguration | Get-SqlDscRSVersion + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 12 + } + } + + Context 'When CurrentVersion is null or empty' { + It 'Should write an error when CurrentVersion is null' { + $mockConfiguration = @{ + CurrentVersion = $null + } + + $mockConfiguration | Get-SqlDscRSVersion -ErrorVariable mockErrorVariable -ErrorAction 'SilentlyContinue' + + $mockErrorVariable | Should -HaveCount 1 + $mockErrorVariable[0].FullyQualifiedErrorId | Should -Be 'GSRSV0001,Get-SqlDscRSVersion' + } + + It 'Should write an error when CurrentVersion is empty' { + $mockConfiguration = @{ + CurrentVersion = '' + } + + $mockConfiguration | Get-SqlDscRSVersion -ErrorVariable mockErrorVariable -ErrorAction 'SilentlyContinue' + + $mockErrorVariable | Should -HaveCount 1 + $mockErrorVariable[0].FullyQualifiedErrorId | Should -Be 'GSRSV0001,Get-SqlDscRSVersion' + } + } + + Context 'When using parameter instead of pipeline input' { + It 'Should return the version when Configuration is passed as parameter' { + $mockConfiguration = @{ + CurrentVersion = '15.0.1100.0' + } + + $result = Get-SqlDscRSVersion -Configuration $mockConfiguration + + $result | Should -BeOfType [System.Version] + $result.Major | Should -Be 15 + } + } +} diff --git a/tests/Unit/Public/Get-SqlDscRSWebPortalApplicationName.Tests.ps1 b/tests/Unit/Public/Get-SqlDscRSWebPortalApplicationName.Tests.ps1 new file mode 100644 index 0000000000..821bbde7ef --- /dev/null +++ b/tests/Unit/Public/Get-SqlDscRSWebPortalApplicationName.Tests.ps1 @@ -0,0 +1,195 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Get-SqlDscRSWebPortalApplicationName' { + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Configuration] []' + } + ) { + $result = (Get-Command -Name 'Get-SqlDscRSWebPortalApplicationName').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 SQL Server version is 2016 (version 13) or later' { + BeforeAll { + Mock -CommandName Get-SqlDscRSVersion + } + + It 'Should return ReportServerWebApp for SQL Server 2016 (version 13)' { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '13.0.4001.0' + } + + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -Be 'ReportServerWebApp' + } + + It 'Should return ReportServerWebApp for SQL Server 2017 (version 14)' { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '14.0.600.0' + } + + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -Be 'ReportServerWebApp' + } + + It 'Should return ReportServerWebApp for SQL Server 2019 (version 15)' { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '15.0.1100.0' + } + + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -Be 'ReportServerWebApp' + } + + It 'Should return ReportServerWebApp for SQL Server 2022 (version 16)' { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '16.0.1000.0' + } + + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -Be 'ReportServerWebApp' + } + } + + Context 'When SQL Server version is earlier than 2016 (version 12 and below)' { + BeforeAll { + Mock -CommandName Get-SqlDscRSVersion + } + + It 'Should return ReportManager for SQL Server 2014 (version 12)' { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '12.0.4100.0' + } + + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -Be 'ReportManager' + } + + It 'Should return ReportManager for SQL Server 2012 (version 11)' { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '11.0.5000.0' + } + + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -Be 'ReportManager' + } + } + + Context 'When Get-SqlDscRSVersion returns null' { + BeforeAll { + Mock -CommandName Get-SqlDscRSVersion + } + + It 'Should return null when Get-SqlDscRSVersion returns null' { + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = $mockConfiguration | Get-SqlDscRSWebPortalApplicationName + + $result | Should -BeNullOrEmpty + } + } + + Context 'When using parameter instead of pipeline input' { + BeforeAll { + Mock -CommandName Get-SqlDscRSVersion -MockWith { + return [System.Version] '15.0.1100.0' + } + } + + It 'Should return the correct application name when Configuration is passed as parameter' { + $mockConfiguration = @{ + InstanceName = 'SSRS' + } + + $result = Get-SqlDscRSWebPortalApplicationName -Configuration $mockConfiguration + + $result | Should -Be 'ReportServerWebApp' + } + } +} diff --git a/tests/Unit/Public/Remove-SqlDscRSUrlReservation.Tests.ps1 b/tests/Unit/Public/Remove-SqlDscRSUrlReservation.Tests.ps1 new file mode 100644 index 0000000000..b34850ba49 --- /dev/null +++ b/tests/Unit/Public/Remove-SqlDscRSUrlReservation.Tests.ps1 @@ -0,0 +1,247 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Remove-SqlDscRSUrlReservation' { + BeforeAll { + Mock -CommandName Get-OperatingSystem -MockWith { + return [PSCustomObject] @{ + OSLanguage = 1033 + } + } + } + + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Configuration] [-Application] [-UrlString] [[-Lcid] ] [-PassThru] [-Force] [-WhatIf] [-Confirm] []' + } + ) { + $result = (Get-Command -Name 'Remove-SqlDscRSUrlReservation').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 removing URL reservation successfully' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should remove URL reservation without errors' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' -and + $Arguments.Application -eq 'ReportServerWebService' -and + $Arguments.UrlString -eq 'http://+:80' -and + $Arguments.Lcid -eq 1033 + } -Exactly -Times 1 + } + + It 'Should not return anything by default' { + $result = $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false + + $result | Should -BeNullOrEmpty + } + } + + Context 'When removing URL reservation with PassThru' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should return the configuration CIM instance' { + $result = $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -PassThru -Confirm:$false + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When removing URL reservation with Force' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should remove URL reservation without confirmation' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Force } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When removing URL reservation with custom Lcid' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should use the specified Lcid' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Lcid 1031 -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Lcid -eq 1031 + } -Exactly -Times 1 + } + + It 'Should not call Get-OperatingSystem when Lcid is specified' { + $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Lcid 1031 -Confirm:$false + + Should -Invoke -CommandName Get-OperatingSystem -Exactly -Times 0 + } + } + + Context 'When CIM method fails with ExtendedErrors' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method RemoveURL() failed with an error. Error: Access denied;Permission error (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Throw -ErrorId 'RSRUR0001,Remove-SqlDscRSUrlReservation' + } + } + + Context 'When CIM method fails with Error property' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method RemoveURL() failed with an error. Error: Access denied (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Throw -ErrorId 'RSRUR0001,Remove-SqlDscRSUrlReservation' + } + } + + Context 'When using WhatIf' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should not call Invoke-RsCimMethod' { + $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -WhatIf + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 0 + } + } + + Context 'When passing configuration as parameter' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should remove URL reservation' { + { Remove-SqlDscRSUrlReservation -Configuration $mockCimInstance -Application 'ReportServerWebService' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When using different application types' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should accept ReportServerWebApp application' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportServerWebApp' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Application -eq 'ReportServerWebApp' + } -Exactly -Times 1 + } + + It 'Should accept ReportManager application' { + { $mockCimInstance | Remove-SqlDscRSUrlReservation -Application 'ReportManager' -UrlString 'http://+:80' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Application -eq 'ReportManager' + } -Exactly -Times 1 + } + } +} diff --git a/tests/Unit/Public/Set-SqlDscRSUrlReservation.Tests.ps1 b/tests/Unit/Public/Set-SqlDscRSUrlReservation.Tests.ps1 new file mode 100644 index 0000000000..a0b9a54ccc --- /dev/null +++ b/tests/Unit/Public/Set-SqlDscRSUrlReservation.Tests.ps1 @@ -0,0 +1,331 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + Remove-Item -Path 'env:SqlServerDscCI' + + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') +} + +Describe 'Set-SqlDscRSUrlReservation' -Tag 'Public' { + Context 'When validating parameter sets' { + BeforeAll { + $command = Get-Command -Name 'Set-SqlDscRSUrlReservation' + } + + It 'Should have the correct parameters in parameter set __AllParameterSets' { + $ExpectedParameters = '[-Configuration] [-Application] [-UrlString] [[-Lcid] ] [-PassThru] [-Force] [-WhatIf] [-Confirm] []' + + $result = $command.ParameterSets | + Where-Object -FilterScript { $_.Name -eq '__AllParameterSets' } | + Select-Object -Property @{ + Name = 'ParameterListAsString' + Expression = { $_.ToString() } + } + + $result.ParameterListAsString | Should -Be $ExpectedParameters + } + } + + Context 'When setting URL reservations with no changes needed' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebService', 'ReportServerWebService') + UrlString = @('http://+:80', 'https://+:443') + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should not add or remove any URLs when current matches desired' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80', 'https://+:443' -Force + + Should -Invoke -CommandName Get-SqlDscRSUrlReservation -Exactly -Times 1 + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -Exactly -Times 0 + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -Exactly -Times 0 + } + } + + Context 'When adding new URL reservations' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebService') + UrlString = @('http://+:80') + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should add the new URL' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80', 'https://+:443' -Force + + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $UrlString -eq 'https://+:443' + } -Exactly -Times 1 + + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -Exactly -Times 0 + } + } + + Context 'When removing existing URL reservations' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebService', 'ReportServerWebService') + UrlString = @('http://+:80', 'https://+:443') + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should remove the URL not in the desired list' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Force + + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -ParameterFilter { + $UrlString -eq 'https://+:443' + } -Exactly -Times 1 + + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -Exactly -Times 0 + } + } + + Context 'When both adding and removing URL reservations' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebService', 'ReportServerWebService') + UrlString = @('http://+:80', 'http://+:8080') + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should add new and remove old URLs' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80', 'https://+:443' -Force + + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $UrlString -eq 'https://+:443' + } -Exactly -Times 1 + + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -ParameterFilter { + $UrlString -eq 'http://+:8080' + } -Exactly -Times 1 + } + } + + Context 'When using PassThru' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @() + UrlString = @() + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should return the configuration CIM instance' { + $result = $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Force -PassThru + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When using custom Lcid' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @() + UrlString = @() + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should pass Lcid to Add-SqlDscRSUrlReservation' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Lcid 1031 -Force + + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -ParameterFilter { + $Lcid -eq 1031 + } -Exactly -Times 1 + } + } + + Context 'When using WhatIf' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should not call any modification commands' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -WhatIf + + Should -Invoke -CommandName Get-SqlDscRSUrlReservation -Exactly -Times 0 + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -Exactly -Times 0 + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -Exactly -Times 0 + } + } + + Context 'When passing configuration as parameter' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @() + UrlString = @() + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should set URL reservations' { + { Set-SqlDscRSUrlReservation -Configuration $mockCimInstance -Application 'ReportServerWebService' -UrlString 'http://+:80' -Force } | Should -Not -Throw + + Should -Invoke -CommandName Get-SqlDscRSUrlReservation -Exactly -Times 1 + } + } + + Context 'When no current reservations exist for application' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = @('ReportServerWebApp') + UrlString = @('http://+:80') + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should add all specified URLs' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80', 'https://+:443' -Force + + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -Exactly -Times 2 + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -Exactly -Times 0 + } + } + + Context 'When current reservations is null' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Get-SqlDscRSUrlReservation -MockWith { + return [PSCustomObject] @{ + HRESULT = 0 + Application = $null + UrlString = $null + } + } + + Mock -CommandName Add-SqlDscRSUrlReservation + Mock -CommandName Remove-SqlDscRSUrlReservation + } + + It 'Should add all specified URLs' { + $mockCimInstance | Set-SqlDscRSUrlReservation -Application 'ReportServerWebService' -UrlString 'http://+:80' -Force + + Should -Invoke -CommandName Add-SqlDscRSUrlReservation -Exactly -Times 1 + Should -Invoke -CommandName Remove-SqlDscRSUrlReservation -Exactly -Times 0 + } + } +} diff --git a/tests/Unit/Public/Set-SqlDscRSVirtualDirectory.Tests.ps1 b/tests/Unit/Public/Set-SqlDscRSVirtualDirectory.Tests.ps1 new file mode 100644 index 0000000000..7bb876a2d9 --- /dev/null +++ b/tests/Unit/Public/Set-SqlDscRSVirtualDirectory.Tests.ps1 @@ -0,0 +1,249 @@ +[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' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:moduleName -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Set-SqlDscRSVirtualDirectory' { + BeforeAll { + Mock -CommandName Get-OperatingSystem -MockWith { + return [PSCustomObject] @{ + OSLanguage = 1033 + } + } + } + + Context 'When validating parameter sets' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-Configuration] [-Application] [-VirtualDirectory] [[-Lcid] ] [-PassThru] [-Force] [-WhatIf] [-Confirm] []' + } + ) { + $result = (Get-Command -Name 'Set-SqlDscRSVirtualDirectory').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 setting virtual directory successfully' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should set virtual directory without errors' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and + $Arguments.Application -eq 'ReportServerWebService' -and + $Arguments.VirtualDirectory -eq 'ReportServer' -and + $Arguments.Lcid -eq 1033 + } -Exactly -Times 1 + } + + It 'Should not return anything by default' { + $result = $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Confirm:$false + + $result | Should -BeNullOrEmpty + } + } + + Context 'When setting virtual directory with PassThru' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should return the configuration CIM instance' { + $result = $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -PassThru -Confirm:$false + + $result | Should -Not -BeNullOrEmpty + $result.InstanceName | Should -Be 'SSRS' + } + } + + Context 'When setting virtual directory with Force' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should set virtual directory without confirmation' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Force } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When setting virtual directory with custom Lcid' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should use the specified Lcid' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Lcid 1031 -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Lcid -eq 1031 + } -Exactly -Times 1 + } + + It 'Should not call Get-OperatingSystem when Lcid is specified' { + $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Lcid 1031 -Confirm:$false + + Should -Invoke -CommandName Get-OperatingSystem -Exactly -Times 0 + } + } + + Context 'When CIM method fails' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod -MockWith { + throw 'Method SetVirtualDirectory() failed with an error. Error: Access denied (HRESULT:-2147024891)' + } + } + + It 'Should throw a terminating error' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Confirm:$false } | Should -Throw -ErrorId 'SSRSVD0001,Set-SqlDscRSVirtualDirectory' + } + } + + Context 'When using WhatIf' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should not call Invoke-RsCimMethod' { + $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -WhatIf + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 0 + } + } + + Context 'When passing configuration as parameter' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should set virtual directory' { + { Set-SqlDscRSVirtualDirectory -Configuration $mockCimInstance -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -Exactly -Times 1 + } + } + + Context 'When using different application types' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should accept ReportServerWebApp application' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebApp' -VirtualDirectory 'Reports' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Application -eq 'ReportServerWebApp' + } -Exactly -Times 1 + } + + It 'Should accept ReportManager application' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportManager' -VirtualDirectory 'Reports' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.Application -eq 'ReportManager' + } -Exactly -Times 1 + } + } + + Context 'When using different virtual directory names' { + BeforeAll { + $mockCimInstance = [PSCustomObject] @{ + InstanceName = 'SSRS' + } + + Mock -CommandName Invoke-RsCimMethod + } + + It 'Should accept custom virtual directory name' { + { $mockCimInstance | Set-SqlDscRSVirtualDirectory -Application 'ReportServerWebService' -VirtualDirectory 'ReportServer_Custom' -Confirm:$false } | Should -Not -Throw + + Should -Invoke -CommandName Invoke-RsCimMethod -ParameterFilter { + $Arguments.VirtualDirectory -eq 'ReportServer_Custom' + } -Exactly -Times 1 + } + } +}