diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cbcccb92..5da47dbe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ - Changes to xSQLServerDatabase - Changed the readme, SQLInstance should have been SQLInstanceName. +- Changes to xSQLServerRSConfig + - BREAKING CHANGE: removed $SQLAdminCredential parameter. Use common parameter PsDscRunAsCredential (WMF 5.0+) to run the resource under different credentials. PsDscRunAsCredential Windows account must be a sysadmin on SQL Server (issue #568). + - Fixed virtual directory creation for SQL Server 2016. + - Added unit tests (issue #295). + - Added support for configuring URL reservations and virtual directory names (issue #570) ## 7.1.0.0 diff --git a/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.psm1 b/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.psm1 index f619d2b3f..c970216e9 100644 --- a/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.psm1 +++ b/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.psm1 @@ -22,21 +22,29 @@ function Get-TargetResource [System.String] $RSSQLInstanceName, - [parameter(Mandatory = $true)] - [System.Management.Automation.PSCredential] - $SQLAdminCredential + [parameter()] + [System.String] + $ReportServerVirtualDir, + + [parameter()] + [System.String] + $ReportsVirtualDir, + + [parameter()] + [System.String[]] + $ReportServerReservedUrl, + + [parameter()] + [System.String[]] + $ReportsReservedUrl ) if(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS" -Name $InstanceName -ErrorAction SilentlyContinue) { $InstanceKey = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS" -Name $InstanceName).$InstanceName - $SQLVersion = ((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceKey\Setup" -Name "Version").Version).Split(".")[0] - $RSConfig = Invoke-Command -ComputerName . -Credential $SQLAdminCredential -ScriptBlock { - $SQLVersion = $args[0] - $InstanceName = $args[1] - $RSConfig = Get-WmiObject -Class MSReportServer_ConfigurationSetting -Namespace "root\Microsoft\SQLServer\ReportServer\RS_$InstanceName\v$SQLVersion\Admin" - $RSConfig - } -ArgumentList @($SQLVersion,$InstanceName) + $SQLVersion = [int]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceKey\Setup" -Name "Version").Version).Split(".")[0] + + $RSConfig = Get-WmiObject -Class MSReportServer_ConfigurationSetting -Namespace "root\Microsoft\SQLServer\ReportServer\RS_$InstanceName\v$SQLVersion\Admin" if($RSConfig.DatabaseServerName.Contains("\")) { $RSSQLServer = $RSConfig.DatabaseServerName.Split("\")[0] @@ -48,6 +56,27 @@ function Get-TargetResource $RSSQLInstanceName = "MSSQLSERVER" } $IsInitialized = $RSConfig.IsInitialized + + if($IsInitialized) + { + # SSRS 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 + $RMApplicationName = if ($SQLVersion -ge 13) { 'ReportServerWebApp' } else { 'ReportManager'} + + $ReportServerVirtualDir = $RSConfig.VirtualDirectoryReportServer + $ReportsVirtualDir = $RSConfig.VirtualDirectoryReportManager + + $reservedUrls = $RSConfig.ListReservedUrls() + + $ReportServerReservedUrl = @() + $ReportsReservedUrl = @() + + for($i = 0; $i -lt $reservedUrls.Application.Count; ++$i) + { + if($reservedUrls.Application[$i] -eq "ReportServerWebService") { $ReportServerReservedUrl += $reservedUrls.UrlString[$i] } + if($reservedUrls.Application[$i] -eq "$RMApplicationName") { $ReportsReservedUrl += $reservedUrls.UrlString[$i] } + } + } } else { @@ -58,6 +87,10 @@ function Get-TargetResource InstanceName = $InstanceName RSSQLServer = $RSSQLServer RSSQLInstanceName = $RSSQLInstanceName + ReportServerVirtualDir = $ReportServerVirtualDir + ReportsVirtualDir = $ReportsVirtualDir + ReportServerReservedUrl = $ReportServerReservedUrl + ReportsReservedUrl = $ReportsReservedUrl IsInitialized = $IsInitialized } @@ -82,57 +115,80 @@ function Set-TargetResource [System.String] $RSSQLInstanceName, - [parameter(Mandatory = $true)] - [System.Management.Automation.PSCredential] - $SQLAdminCredential + [parameter()] + [System.String] + $ReportServerVirtualDir, + + [parameter()] + [System.String] + $ReportsVirtualDir, + + [parameter()] + [System.String[]] + $ReportServerReservedUrl, + + [parameter()] + [System.String[]] + $ReportsReservedUrl ) if(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS" -Name $InstanceName -ErrorAction SilentlyContinue) { - Invoke-Command -ComputerName . -Credential $SQLAdminCredential -ScriptBlock { - # this is a separate PS session, need to load Common Code again - Import-Module $using:currentPath\..\..\xSQLServerHelper.psm1 -Verbose -ErrorAction Stop - # smart import of the SQL module - Import-SQLPSModule + $InstanceKey = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS" -Name $InstanceName).$InstanceName + $SQLVersion = [int]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceKey\Setup" -Name "Version").Version).Split(".")[0] + if($InstanceName -eq "MSSQLSERVER") + { + $RSServiceName = "ReportServer" + if([string]::IsNullOrEmpty($ReportServerVirtualDir)) { $ReportServerVirtualDir = "ReportServer" } + if([string]::IsNullOrEmpty($ReportsVirtualDir)) { $ReportsVirtualDir = "Reports" } + $RSDatabase = "ReportServer" + } + else + { + $RSServiceName = "ReportServer`$$InstanceName" + if([string]::IsNullOrEmpty($ReportServerVirtualDir)) { $ReportServerVirtualDir = "ReportServer_$InstanceName" } + if([string]::IsNullOrEmpty($ReportsVirtualDir)) { $ReportsVirtualDir = "Reports_$InstanceName" } + $RSDatabase = "ReportServer`$$InstanceName" + } + if($RSSQLInstanceName -eq "MSSQLSERVER") + { + $RSConnection = "$RSSQLServer" + } + else + { + $RSConnection = "$RSSQLServer\$RSSQLInstanceName" + } + $Language = (Get-WMIObject -Class Win32_OperatingSystem -Namespace root/cimv2 -ErrorAction SilentlyContinue).OSLanguage + $RSConfig = Get-WmiObject -Class MSReportServer_ConfigurationSetting -Namespace "root\Microsoft\SQLServer\ReportServer\RS_$InstanceName\v$SQLVersion\Admin" - $InstanceName = $args[0] - $RSSQLServer = $args[1] - $RSSQLInstanceName = $args[2] - $InstanceKey = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS" -Name $InstanceName).$InstanceName - $SQLVersion = ((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceKey\Setup" -Name "Version").Version).Split(".")[0] - if($InstanceName -eq "MSSQLSERVER") - { - $RSServiceName = "ReportServer" - $RSVirtualDirectory = "ReportServer" - $RMVirtualDirectory = "Reports" - $RSDatabase = "ReportServer" - } - else - { - $RSServiceName = "ReportServer`$$InstanceName" - $RSVirtualDirectory = "ReportServer_$InstanceName" - $RMVirtualDirectory = "Reports_$InstanceName" - $RSDatabase = "ReportServer`$$InstanceName" - } - if($RSSQLInstanceName -eq "MSSQLSERVER") - { - $RSConnection = "$RSSQLServer" - } - else - { - $RSConnection = "$RSSQLServer\$RSSQLInstanceName" - } - $Language = (Get-WMIObject -Class Win32_OperatingSystem -Namespace root/cimv2 -ErrorAction SilentlyContinue).OSLanguage - $RSConfig = Get-WmiObject -Class MSReportServer_ConfigurationSetting -Namespace "root\Microsoft\SQLServer\ReportServer\RS_$InstanceName\v$SQLVersion\Admin" - if($RSConfig.VirtualDirectoryReportServer -ne $RSVirtualDirectory) + # SSRS 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 + $RMApplicationName = if ($SQLVersion -ge 13) { 'ReportServerWebApp' } else { 'ReportManager'} + + if(!$RSConfig.IsInitialized) + { + New-VerboseMessage -Message "Initializing Reporting Services on $RSSQLServer\$RSSQLInstanceName." + + if($ReportServerReservedUrl -eq $null) { $ReportServerReservedUrl = @("http://+:80") } + if($ReportsReservedUrl -eq $null) { $ReportsReservedUrl = @("http://+:80") } + + if($RSConfig.VirtualDirectoryReportServer -ne $ReportServerVirtualDir) { - $null = $RSConfig.SetVirtualDirectory("ReportServerWebService",$RSVirtualDirectory,$Language) - $null = $RSConfig.ReserveURL("ReportServerWebService","http://+:80",$Language) + New-VerboseMessage -Message "Setting report server virtual directory on $RSSQLServer\$RSSQLInstanceName to $ReportServerVirtualDir." + $null = $RSConfig.SetVirtualDirectory("ReportServerWebService",$ReportServerVirtualDir,$Language) + $ReportServerReservedUrl | ForEach-Object { + New-VerboseMessage -Message "Adding report server URL reservation on $RSSQLServer\$RSSQLInstanceName`: $_." + $null = $RSConfig.ReserveURL("ReportServerWebService",$_,$Language) + } } - if($RSConfig.VirtualDirectoryReportManager -ne $RMVirtualDirectory) + if($RSConfig.VirtualDirectoryReportManager -ne $ReportsVirtualDir) { - $null = $RSConfig.SetVirtualDirectory("ReportManager",$RMVirtualDirectory,$Language) - $null = $RSConfig.ReserveURL("ReportManager","http://+:80",$Language) + New-VerboseMessage -Message "Setting reports virtual directory on $RSSQLServer\$RSSQLInstanceName to $ReportServerVirtualDir." + $null = $RSConfig.SetVirtualDirectory($RMApplicationName,$ReportsVirtualDir,$Language) + $ReportsReservedUrl | ForEach-Object { + New-VerboseMessage -Message "Adding reports URL reservation on $RSSQLServer\$RSSQLInstanceName`: $_." + $null = $RSConfig.ReserveURL($RMApplicationName,$_,$Language) + } } $RSCreateScript = $RSConfig.GenerateDatabaseCreationScript($RSDatabase,$Language,$false) @@ -140,12 +196,64 @@ function Set-TargetResource $RSSvcAccountUsername = (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $RSServiceName}).StartName $RSRightsScript = $RSConfig.GenerateDatabaseRightsScript($RSSvcAccountUsername,$RSDatabase,$false,$true) + # smart import of the SQL module + Import-SQLPSModule Invoke-Sqlcmd -ServerInstance $RSConnection -Query $RSCreateScript.Script Invoke-Sqlcmd -ServerInstance $RSConnection -Query $RSRightsScript.Script - $RSConfig.SetDatabaseConnection($RSConnection,$RSDatabase,2,"","") - $RSConfig.InitializeReportServer($RSConfig.InstallationID) - } -ArgumentList @($InstanceName,$RSSQLServer,$RSSQLInstanceName) + $null = $RSConfig.SetDatabaseConnection($RSConnection,$RSDatabase,2,"","") + $null = $RSConfig.InitializeReportServer($RSConfig.InstallationID) + } + else + { + $currentConfig = Get-TargetResource @PSBoundParameters + + if(![string]::IsNullOrEmpty($ReportServerVirtualDir) -and ($ReportServerVirtualDir -ne $currentConfig.ReportServerVirtualDir)) + { + New-VerboseMessage -Message "Setting report server virtual directory on $RSSQLServer\$RSSQLInstanceName to $ReportServerVirtualDir." + + # to change a virtual directory, we first need to remove all URL reservations, + # change the virtual directory and re-add URL reservations + $currentConfig.ReportServerReservedUrl | ForEach-Object { $null = $RSConfig.RemoveURL("ReportServerWebService",$_,$Language) } + $RSConfig.SetVirtualDirectory("ReportServerWebService",$ReportServerVirtualDir,$Language) + $currentConfig.ReportServerReservedUrl | ForEach-Object { $null = $RSConfig.ReserveURL("ReportServerWebService",$_,$Language) } + } + + if(![string]::IsNullOrEmpty($ReportsVirtualDir) -and ($ReportsVirtualDir -ne $currentConfig.ReportsVirtualDir)) + { + New-VerboseMessage -Message "Setting reports virtual directory on $RSSQLServer\$RSSQLInstanceName to $ReportServerVirtualDir." + + # to change a virtual directory, we first need to remove all URL reservations, + # change the virtual directory and re-add URL reservations + $currentConfig.ReportsReservedUrl | ForEach-Object { $null = $RSConfig.RemoveURL($RMApplicationName,$_,$Language) } + $RSConfig.SetVirtualDirectory($RMApplicationName,$ReportsVirtualDir,$Language) + $currentConfig.ReportsReservedUrl | ForEach-Object { $null = $RSConfig.ReserveURL($RMApplicationName,$_,$Language) } + } + + if(($ReportServerReservedUrl -ne $null) -and ((Compare-Object -ReferenceObject $currentConfig.ReportServerReservedUrl -DifferenceObject $ReportServerReservedUrl) -ne $null)) + { + $currentConfig.ReportServerReservedUrl | ForEach-Object { + $null = $RSConfig.RemoveURL("ReportServerWebService",$_,$Language) + } + + $ReportServerReservedUrl | ForEach-Object { + New-VerboseMessage -Message "Adding report server URL reservation on $RSSQLServer\$RSSQLInstanceName`: $_." + $null = $RSConfig.ReserveURL("ReportServerWebService",$_,$Language) + } + } + + if(($ReportsReservedUrl -ne $null) -and ((Compare-Object -ReferenceObject $currentConfig.ReportsReservedUrl -DifferenceObject $ReportsReservedUrl) -ne $null)) + { + $currentConfig.ReportsReservedUrl | ForEach-Object { + $null = $RSConfig.RemoveURL($RMApplicationName,$_,$Language) + } + + $ReportsReservedUrl | ForEach-Object { + New-VerboseMessage -Message "Adding reports URL reservation on $RSSQLServer\$RSSQLInstanceName`: $_." + $null = $RSConfig.ReserveURL($RMApplicationName,$_,$Language) + } + } + } } if(!(Test-TargetResource @PSBoundParameters)) @@ -173,13 +281,57 @@ function Test-TargetResource [System.String] $RSSQLInstanceName, - [parameter(Mandatory = $true)] - [System.Management.Automation.PSCredential] - $SQLAdminCredential + [parameter()] + [System.String] + $ReportServerVirtualDir, + + [parameter()] + [System.String] + $ReportsVirtualDir, + + [parameter()] + [System.String[]] + $ReportServerReservedUrl, + + [parameter()] + [System.String[]] + $ReportsReservedUrl ) - $result = (Get-TargetResource @PSBoundParameters).IsInitialized + $result = $true + + $currentConfig = Get-TargetResource @PSBoundParameters + if(!$currentConfig.IsInitialized) + { + New-VerboseMessage -Message "Reporting services $RSSQLServer\$RSSQLInstanceName are not initialized." + $result = $false + } + + if(![string]::IsNullOrEmpty($ReportServerVirtualDir) -and ($ReportServerVirtualDir -ne $currentConfig.ReportServerVirtualDir)) + { + New-VerboseMessage -Message "Report server virtual directory on $RSSQLServer\$RSSQLInstanceName is $($currentConfig.ReportServerVirtualDir), should be $ReportServerVirtualDir." + $result = $false + } + + if(![string]::IsNullOrEmpty($ReportsVirtualDir) -and ($ReportsVirtualDir -ne $currentConfig.ReportsVirtualDir)) + { + New-VerboseMessage -Message "Reports virtual directory on $RSSQLServer\$RSSQLInstanceName is $($currentConfig.ReportsVirtualDir), should be $ReportsVirtualDir." + $result = $false + } + + if(($ReportServerReservedUrl -ne $null) -and ((Compare-Object -ReferenceObject $currentConfig.ReportServerReservedUrl -DifferenceObject $ReportServerReservedUrl) -ne $null)) + { + New-VerboseMessage -Message "Report server reserved URLs on $RSSQLServer\$RSSQLInstanceName are $($currentConfig.ReportServerReservedUrl -join ', '), should be $($ReportServerReservedUrl -join ', ')." + $result = $false + } + + if(($ReportsReservedUrl -ne $null) -and ((Compare-Object -ReferenceObject $currentConfig.ReportsReservedUrl -DifferenceObject $ReportsReservedUrl) -ne $null)) + { + New-VerboseMessage -Message "Reports reserved URLs on $RSSQLServer\$RSSQLInstanceName are $($currentConfig.ReportsReservedUrl -join ', ')), should be $($ReportsReservedUrl -join ', ')." + $result = $false + } + $result } diff --git a/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.schema.mof b/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.schema.mof index 5891a288e..c39f79b22 100644 --- a/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.schema.mof +++ b/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.schema.mof @@ -4,6 +4,9 @@ class MSFT_xSQLServerRSConfig : OMI_BaseResource [Key, Description("Name of the SQL Server Reporting Services instance to be configured.")] String InstanceName; [Required, Description("Name of the SQL Server to host the Reporting Service database.")] String RSSQLServer; [Required, Description("Name of the SQL Server instance to host the Reporting Service database.")] String RSSQLInstanceName; - [Required, EmbeddedInstance("MSFT_Credential"), Description("Credential to be used to perform the configuration.")] String SQLAdminCredential; + [Write, Description("Report Server virtual directory name. Optional.")] String ReportServerVirtualDir; + [Write, Description("Report Manager/Report Web App virtual directory name. Optional.")] String ReportsVirtualDir; + [Write, Description("Report Server reserved URLs. Optional.")] String ReportServerReservedUrl[]; + [Write, Description("Report Manager/Report Web App reserved URLs. Optional.")] String ReportsReservedUrl[]; [Read, Description("Is the Reporting Services instance initialized.")] Boolean IsInitialized; }; diff --git a/README.md b/README.md index 960cb8e8f..43b3ddc61 100644 --- a/README.md +++ b/README.md @@ -867,7 +867,7 @@ This resource is used to create a server role, when Ensure is set to 'Present'. ### xSQLServerRSConfig -No description. +Initializes and configures SQL Reporting Services server. #### Requirements @@ -879,7 +879,10 @@ No description. * **[String] InstanceName** _(Key)_: Name of the SQL Server Reporting Services instance to be configured. * **[String] RSSQLServer** _(Required)_: Name of the SQL Server to host the Reporting Service database. * **[String] RSSQLInstanceName** _(Required)_: Name of the SQL Server instance to host the Reporting Service database. -* **[PSCredential] SQLAdminCredential** _(Required)_: Credential to be used to perform the configuration. +* **[String] ReportServerVirtualDir** _(Write)_: Report Server Web Service virtual directory. Optional. +* **[String] ReportsVirtualDir** _(Write)_: Report Manager virtual directory. Optional. +* **[String[]] ReportServerReservedUrl** _(Write)_: Report Server URL reservations. Optional. If not specified, "http://+:80" URL reservation will be used. +* **[String[]] ReportsReservedUrl** _(Write)_: Report Manager URL reservations. Optional. If not specified, "http://+:80" URL reservation will be used. #### Read-Only Properties from Get-TargetResource diff --git a/Tests/Unit/MSFT_xSQLServerRSConfig.Tests.ps1 b/Tests/Unit/MSFT_xSQLServerRSConfig.Tests.ps1 new file mode 100644 index 000000000..6f3b875e0 --- /dev/null +++ b/Tests/Unit/MSFT_xSQLServerRSConfig.Tests.ps1 @@ -0,0 +1,303 @@ +$script:DSCModuleName = 'xSQLServer' +$script:DSCResourceName = 'MSFT_xSQLServerRSConfig' + +#region HEADER + +# Unit Test Template Version: 1.2.0 +$script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) +} + +Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force + +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:DSCModuleName ` + -DSCResourceName $script:DSCResourceName ` + -TestType Unit + +#endregion HEADER + +function Invoke-TestSetup { + #Add-Type -Path (Join-Path -Path (Join-Path -Path (Join-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'Tests') -ChildPath 'Unit') -ChildPath 'Stubs') -ChildPath 'SqlPowerShellSqlExecutionException.cs') + Import-Module -Name (Join-Path -Path (Join-Path -Path (Join-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'Tests') -ChildPath 'Unit') -ChildPath 'Stubs') -ChildPath 'SQLPSStub.psm1') -Global -Force +} + +function Invoke-TestCleanup { + Restore-TestEnvironment -TestEnvironment $TestEnvironment +} + +# Begin Testing +try +{ + Invoke-TestSetup + + InModuleScope $script:DSCResourceName { + $mockNamedInstanceName = 'INSTANCE' + $mockDefaultInstanceName = 'MSSQLSERVER' + $mockReportingServicesDatabaseServerName = 'SERVER' + $mockReportingServicesDatabaseNamedInstanceName = $mockNamedInstanceName + $mockReportingServicesDatabaseDefaultInstanceName = $mockDefaultInstanceName + + $mockGetItemProperty = { + return @{ + InstanceName = $mockInstanceName + Version = $mockDynamic_SqlBuildVersion + } + } + + $mockGetWmiObject_ConfigurationSetting_NamedInstance = { + return New-Object Object | + Add-Member -MemberType NoteProperty -Name 'DatabaseServerName' -Value "$mockReportingServicesDatabaseServerName\$mockReportingServicesDatabaseNamedInstanceName" -PassThru | + Add-Member -MemberType NoteProperty -Name 'IsInitialized' -Value $true -PassThru | + Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportServer' -Value '' -PassThru | + Add-Member -MemberType NoteProperty -Name 'VirtualDirectoryReportManager' -Value '' -PassThru | + Add-Member -MemberType ScriptMethod -Name SetVirtualDirectory { + return $null + } -PassThru | + Add-Member -MemberType ScriptMethod -Name ReserveURL { + return $null + } -PassThru | + Add-Member -MemberType ScriptMethod -Name GenerateDatabaseCreationScript { + return @{ + Script = 'select * from something' + } + } -PassThru | + Add-Member -MemberType ScriptMethod -Name GenerateDatabaseRightsScript { + return @{ + Script = 'select * from something' + } + } -PassThru | + Add-Member -MemberType ScriptMethod -Name SetDatabaseConnection { + return $null + } -PassThru | + Add-Member -MemberType ScriptMethod -Name InitializeReportServer { + return $null + } -PassThru -Force + } + + $mockGetWmiObject_ConfigurationSetting_DefaultInstance = { + return @{ + DatabaseServerName = $mockReportingServicesDatabaseServerName + IsInitialized = $false + } + } + + $mockGetWmiObject_ConfigurationSetting_ParameterFilter = { + $Class -eq 'MSReportServer_ConfigurationSetting' + } + + $mockGetWmiObject_Language = { + return @{ + Language = '1033' + } + } + + $mockGetWmiObject_OperatingSystem_ParameterFilter = { + $Class -eq 'Win32_OperatingSystem' + } + + Describe "xSQLServerRSConfig\Get-TargetResource" -Tag 'Get' { + BeforeAll { + $mockDynamic_SqlBuildVersion = '13.0.4001.0' + + Mock -CommandName Get-ItemProperty -MockWith $mockGetItemProperty -Verifiable + + $testParameters = @{ + InstanceName = $mockNamedInstanceName + RSSQLServer = $mockReportingServicesDatabaseServerName + RSSQLInstanceName = $mockReportingServicesDatabaseNamedInstanceName + } + } + + Context 'When the system is in the desired state' { + BeforeEach { + Mock -CommandName Get-WmiObject ` + -MockWith $mockGetWmiObject_ConfigurationSetting_NamedInstance ` + -ParameterFilter $mockGetWmiObject_ConfigurationSetting_ParameterFilter ` + -Verifiable + } + + It 'Should return the same values as passed as parameters' { + $resultGetTargetResource = Get-TargetResource @testParameters + $resultGetTargetResource.InstanceName | Should Be $mockNamedInstanceName + $resultGetTargetResource.RSSQLServer | Should Be $mockReportingServicesDatabaseServerName + $resultGetTargetResource.RSSQLInstanceName | Should Be $mockReportingServicesDatabaseNamedInstanceName + $resultGetTargetResource | Should BeOfType [System.Collections.Hashtable] + } + + It 'Should return the the state as initialized' { + $resultGetTargetResource = Get-TargetResource @testParameters + $resultGetTargetResource.IsInitialized | Should Be $true + } + } + + Context 'When the system is not in the desired state' { + BeforeEach { + Mock -CommandName Get-WmiObject ` + -MockWith $mockGetWmiObject_ConfigurationSetting_DefaultInstance ` + -ParameterFilter $mockGetWmiObject_ConfigurationSetting_ParameterFilter ` + -Verifiable + } + + It 'Should return the same values as passed as parameters' { + $resultGetTargetResource = Get-TargetResource @testParameters + $resultGetTargetResource.InstanceName | Should Be $mockNamedInstanceName + $resultGetTargetResource.RSSQLServer | Should Be $mockReportingServicesDatabaseServerName + $resultGetTargetResource.RSSQLInstanceName | Should Be 'MSSQLSERVER' + $resultGetTargetResource | Should BeOfType [System.Collections.Hashtable] + } + + It 'Should return the the state as initialized' { + $resultGetTargetResource = Get-TargetResource @testParameters + $resultGetTargetResource.IsInitialized | Should Be $false + } + + Context 'When there is no Reporting Services instance' { + BeforeEach { + Mock -CommandName Get-ItemProperty + } + + It 'Should return the the state as initialized' { + { Get-TargetResource @testParameters } | Should Throw 'SQL Reporting Services instance ''INSTANCE'' does not exist!' + } + } + } + } + + Describe "xSQLServerRSConfig\Set-TargetResource" -Tag 'Set' { + BeforeAll { + Mock -CommandName Import-SQLPSModule + Mock -CommandName Invoke-Sqlcmd + Mock -CommandName Get-ItemProperty -MockWith $mockGetItemProperty -Verifiable + } + + Context 'When the system is not in the desired state' { + Context 'When configuring a named instance' { + BeforeAll { + $mockDynamic_SqlBuildVersion = '13.0.4001.0' + + Mock -CommandName Test-TargetResource -MockWith { + return $true + } + + $testParameters = @{ + InstanceName = $mockNamedInstanceName + RSSQLServer = $mockReportingServicesDatabaseServerName + RSSQLInstanceName = $mockReportingServicesDatabaseNamedInstanceName + } + } + + BeforeEach { + Mock -CommandName Get-WmiObject ` + -MockWith $mockGetWmiObject_ConfigurationSetting_NamedInstance ` + -ParameterFilter $mockGetWmiObject_ConfigurationSetting_ParameterFilter ` + -Verifiable + + Mock -CommandName Get-WmiObject ` + -MockWith $mockGetWmiObject_Language ` + -ParameterFilter $mockGetWmiObject_OperatingSystem_ParameterFilter ` + -Verifiable + } + + It 'Should configure Reporting Service without throwing an error' { + { Set-TargetResource @testParameters } | Should Not Throw + } + + Context 'When there is no Reporting Services instance' { + BeforeEach { + Mock -CommandName Get-ItemProperty + Mock -CommandName Test-TargetResource + } + + It 'Should return the the state as initialized' { + { Set-TargetResource @testParameters } | Should Throw 'Test-TargetResource returned false after calling set.' + } + } + } + + Context 'When configuring a default instance' { + BeforeAll { + $mockDynamic_SqlBuildVersion = '12.0.4100.1' + + Mock -CommandName Test-TargetResource -MockWith { + return $true + } + + $testParameters = @{ + InstanceName = $mockDefaultInstanceName + RSSQLServer = $mockReportingServicesDatabaseServerName + RSSQLInstanceName = $mockReportingServicesDatabaseDefaultInstanceName + } + } + + BeforeEach { + Mock -CommandName Get-WmiObject ` + -MockWith $mockGetWmiObject_ConfigurationSetting_NamedInstance ` + -ParameterFilter $mockGetWmiObject_ConfigurationSetting_ParameterFilter ` + -Verifiable + + Mock -CommandName Get-WmiObject ` + -MockWith $mockGetWmiObject_Language ` + -ParameterFilter $mockGetWmiObject_OperatingSystem_ParameterFilter ` + -Verifiable + } + + It 'Should configure Reporting Service without throwing an error' { + { Set-TargetResource @testParameters } | Should Not Throw + } + } + } + } + + Describe "xSQLServerRSConfig\Test-TargetResource" -Tag 'Test' { + Context 'When the system is not in the desired state' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + IsInitialized = $false + } + } + + $testParameters = @{ + InstanceName = $mockNamedInstanceName + RSSQLServer = $mockReportingServicesDatabaseServerName + RSSQLInstanceName = $mockReportingServicesDatabaseNamedInstanceName + } + } + + It 'Should return state as not in desired state' { + $resultTestTargetResource = Test-TargetResource @testParameters + $resultTestTargetResource | Should Be $false + } + } + + Context 'When the system is in the desired state' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + IsInitialized = $true + } + } + + $testParameters = @{ + InstanceName = $mockNamedInstanceName + RSSQLServer = $mockReportingServicesDatabaseServerName + RSSQLInstanceName = $mockReportingServicesDatabaseNamedInstanceName + } + } + + It 'Should return state as in desired state' { + $resultTestTargetResource = Test-TargetResource @testParameters + $resultTestTargetResource | Should Be $true + } + } + } + } +} +finally +{ + Invoke-TestCleanup +}