diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e09e54eb..8501c3ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - 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 54f178a84..c970216e9 100644 --- a/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.psm1 +++ b/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.psm1 @@ -20,13 +20,29 @@ function Get-TargetResource [parameter(Mandatory = $true)] [System.String] - $RSSQLInstanceName + $RSSQLInstanceName, + + [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] + $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("\")) @@ -40,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 { @@ -50,6 +87,10 @@ function Get-TargetResource InstanceName = $InstanceName RSSQLServer = $RSSQLServer RSSQLInstanceName = $RSSQLInstanceName + ReportServerVirtualDir = $ReportServerVirtualDir + ReportsVirtualDir = $ReportsVirtualDir + ReportServerReservedUrl = $ReportServerReservedUrl + ReportsReservedUrl = $ReportsReservedUrl IsInitialized = $IsInitialized } @@ -72,28 +113,41 @@ function Set-TargetResource [parameter(Mandatory = $true)] [System.String] - $RSSQLInstanceName + $RSSQLInstanceName, + + [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) { - # 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" - $RSVirtualDirectory = "ReportServer" - $RMVirtualDirectory = "Reports" + if([string]::IsNullOrEmpty($ReportServerVirtualDir)) { $ReportServerVirtualDir = "ReportServer" } + if([string]::IsNullOrEmpty($ReportsVirtualDir)) { $ReportsVirtualDir = "Reports" } $RSDatabase = "ReportServer" } else { $RSServiceName = "ReportServer`$$InstanceName" - $RSVirtualDirectory = "ReportServer_$InstanceName" - $RMVirtualDirectory = "Reports_$InstanceName" + if([string]::IsNullOrEmpty($ReportServerVirtualDir)) { $ReportServerVirtualDir = "ReportServer_$InstanceName" } + if([string]::IsNullOrEmpty($ReportsVirtualDir)) { $ReportsVirtualDir = "Reports_$InstanceName" } $RSDatabase = "ReportServer`$$InstanceName" } if($RSSQLInstanceName -eq "MSSQLSERVER") @@ -106,29 +160,100 @@ function Set-TargetResource } $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) { - $null = $RSConfig.SetVirtualDirectory("ReportServerWebService",$RSVirtualDirectory,$Language) - $null = $RSConfig.ReserveURL("ReportServerWebService","http://+:80",$Language) + 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) + { + 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 $ReportsVirtualDir) + { + 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) + + # Determine RS service account + $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 + + $null = $RSConfig.SetDatabaseConnection($RSConnection,$RSDatabase,2,"","") + $null = $RSConfig.InitializeReportServer($RSConfig.InstallationID) } - if($RSConfig.VirtualDirectoryReportManager -ne $RMVirtualDirectory) + else { - # 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 - $virtualDirectoryName = if ($SQLVersion -ge 13) { 'ReportServerWebApp' } else { 'ReportManager'} - $null = $RSConfig.SetVirtualDirectory($virtualDirectoryName,$RMVirtualDirectory,$Language) - $null = $RSConfig.ReserveURL($virtualDirectoryName,"http://+:80",$Language) - } - $RSCreateScript = $RSConfig.GenerateDatabaseCreationScript($RSDatabase,$Language,$false) + $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." - # Determine RS service account - $RSSvcAccountUsername = (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $RSServiceName}).StartName - $RSRightsScript = $RSConfig.GenerateDatabaseRightsScript($RSSvcAccountUsername,$RSDatabase,$false,$true) + # 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) } + } - Invoke-Sqlcmd -ServerInstance $RSConnection -Query $RSCreateScript.Script - Invoke-Sqlcmd -ServerInstance $RSConnection -Query $RSRightsScript.Script - $null = $RSConfig.SetDatabaseConnection($RSConnection,$RSDatabase,2,"","") - $null = $RSConfig.InitializeReportServer($RSConfig.InstallationID) + 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)) @@ -154,11 +279,59 @@ function Test-TargetResource [parameter(Mandatory = $true)] [System.String] - $RSSQLInstanceName + $RSSQLInstanceName, + + [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 06674454c..c39f79b22 100644 --- a/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.schema.mof +++ b/DSCResources/MSFT_xSQLServerRSConfig/MSFT_xSQLServerRSConfig.schema.mof @@ -4,5 +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; + [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 97d56fc94..33471e840 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,6 +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. +* **[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