From 7c4eba24050442dc4beaedaf00b9b71b6ff71d33 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Thu, 22 Feb 2018 17:52:58 +0200 Subject: [PATCH 1/3] Control admin vs runtime setup --- .../Functions/Admin/Set-RsDatabase.ps1 | 246 +++++++++++++----- 1 file changed, 188 insertions(+), 58 deletions(-) diff --git a/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 b/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 index 29882f9e..9dc02e08 100644 --- a/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 +++ b/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 @@ -7,52 +7,76 @@ function Set-RsDatabase <# .SYNOPSIS This script configures the database settings used by SQL Server Reporting Services. - + .DESCRIPTION This script configures SQL Server Reporting Services to either create and use a new RS database or use an existing RS database. You must be an admin in RS and SQL Server in order to perform this operation successfully. - + There are three phases to setup: + 1. Create the PBIRS database on the database server + 2. Create the run-time user + 3. Grant the run-time user access to the PBIRS database + 4. Configure the PowerBI Report Server to use the database and run-time credentials + Your admin role on SQL Server can be one of: + * The account under which you run this powershell (default) + * A specific set of credentials for the SQL Server which has admin rights, specified via -AdminDatabaseCredential + .PARAMETER ReportServerInstance Specify the name of the SQL Server Reporting Services Instance. Use the "Connect-RsReportServer" function to set/update a default value. - + .PARAMETER ReportServerVersion Specify the version of the SQL Server Reporting Services Instance. Use the "Connect-RsReportServer" function to set/update a default value. - + .PARAMETER ComputerName The Report Server to target. Use the "Connect-RsReportServer" function to set/update a default value. - + .PARAMETER Credential Specify the credentials to use when connecting to the Report Server. Use the "Connect-RsReportServer" function to set/update a default value. - + .PARAMETER DatabaseServerName Specify the database server name. (e.g. localhost, MyMachine\Sql2016, etc.) - + .PARAMETER IsRemoteDatabaseServer Specify this switch if the database server is on a different machine than the machine Reporting Services is running on. - + .PARAMETER Name Specify the name of the RS Database. - + .PARAMETER IsExistingDatabase - Specify this switch if the database to use already exists. - + Specify this switch if the database to use already exists, and prevent creation of the database. + + .PARAMETER IsExistingDatabaseUser + Specify this switch if the runtime database user already exists, and prevent creation of the user. Relevant only if the runtime user is an SQL credential type. + + .PARAMETER HasDatabaseUserRights + Specify this switch if the runtime database user already has access rights to the database, and prevent granting the user rights. + .PARAMETER DatabaseCredentialType - Indicate what type of credentials to use when connecting to the database: Windows, SQL, or Service Account. - + Indicate what type of runtime credentials to use when connecting to the database: Windows, SQL, or Service Account. + .PARAMETER DatabaseCredential - Specify the credentials to use when connecting to the SQL Server. + Specify the runtime credentials to use when connecting to the SQL Server. + This credential is used for *run-time* only. It is not used for initial database setup. Note: This parameter will be ignored whenever DatabaseCredentialType is set to Service Account! - + + .PARAMETER AdminDatabaseCredentialType + Indicate what type of admin setup credentials to use when connecting to the database: Windows (current user running this powershell) or SQL. + Defaults to Windows. + + .PARAMETER AdminDatabaseCredential + Specify the admin setup credentials to use when connecting to the SQL Server. + This credential is used for *setup* only; it is not used for PowerBI Report Server during runtime. + Note: This parameter will be ignored whenever AdminDatabaseCredentialType is set to Service Account! + .EXAMPLE Set-RsDatabase -DatabaseServerName localhost -Name ReportServer -DatabaseCredentialType ServiceAccount Description ----------- This command will create a new RS database (ReportServer) and configure Reporting Services to connect to it using Service Account credentials. - + .EXAMPLE Set-RsDatabase -DatabaseServerName localhost -Name ExistingReportServer -IsExistingDatabase -DatabaseCredentialType Windows -DatabaseCredential $myCredentials Description @@ -68,7 +92,7 @@ function Set-RsDatabase [switch] $IsRemoteDatabaseServer, - + [Parameter(Mandatory = $True)] [Alias('DatabaseName')] [string] @@ -76,34 +100,47 @@ function Set-RsDatabase [switch] $IsExistingDatabase, - + + [switch] + $IsExistingDatabaseUser, + + [switch] + $HasDatabaseUserRights, + [Parameter(Mandatory = $true)] [Alias('Authentication')] [Microsoft.ReportingServicesTools.SqlServerAuthenticationType] $DatabaseCredentialType, - + [System.Management.Automation.PSCredential] $DatabaseCredential, - + + [Parameter] + [Microsoft.ReportingServicesTools.SqlServerAuthenticationType] + $AdminDatabaseCredentialType, + + [System.Management.Automation.PSCredential] + $AdminDatabaseCredential, + [Alias('SqlServerInstance')] [string] $ReportServerInstance, - + [Alias('SqlServerVersion')] [Microsoft.ReportingServicesTools.SqlServerVersion] $ReportServerVersion, - + [string] $ComputerName, - + [System.Management.Automation.PSCredential] $Credential ) - - if ($PSCmdlet.ShouldProcess((Get-ShouldProcessTargetWmi -BoundParameters $PSBoundParameters), "Configure to use $DatabaseServerName as database, using $DatabaseCredentialType authentication")) + + if ($PSCmdlet.ShouldProcess((Get-ShouldProcessTargetWmi -BoundParameters $PSBoundParameters), "Configure to use $DatabaseServerName as database, using $DatabaseCredentialType runtime authentication and $AdminDatabaseCredentialType setup authentication")) { $rsWmiObject = New-RsConfigurationSettingObjectHelper -BoundParameters $PSBoundParameters - + #region Validating authentication and normalizing credentials $username = '' $password = $null @@ -112,7 +149,7 @@ function Set-RsDatabase $username = $rsWmiObject.WindowsServiceIdentityActual $password = '' } - + else { if ($DatabaseCredential -eq $null) @@ -123,11 +160,37 @@ function Set-RsDatabase $password = $DatabaseCredential.GetNetworkCredential().Password } #endregion Validating authentication and normalizing credentials - + + #region Validating admin authentication and normalizing credentials + $adminUsername = '' + $adminPassword = $null + + # default is Windows + $isSQLAdminAccount = ($AdminDatabaseCredentialType -like "SQL") + + # we do not allow service account - only Windows and SQL + if ($AdminDatabaseCredentialType -like 'serviceaccount') + { + throw "Can only use Admin Database Credentials Type of 'Windows' or 'SQL'" + } + + # must have credentials passed + if ($AdminDatabaseCredentialType -like 'sql') + { + if ($AdminDatabaseCredential -eq $null) + { + throw "No Admin Database Credential specified! Admin Database credential must be specified when configuring $AdminDatabaseCredentialType authentication." + } + $adminUsername = $AdminDatabaseCredential.UserName + $adminPassword = $AdminDatabaseCredential.GetNetworkCredential().Password + } + #endregion Validating admin authentication and normalizing credentials + + #region Create Database if necessary if (-not $IsExistingDatabase) { - # Step 1 - Generate Database Script + # Step 1 - Generate Database Script Write-Verbose "Generating database creation script..." $EnglishLocaleId = 1033 $IsSharePointMode = $false @@ -142,12 +205,19 @@ function Set-RsDatabase $SQLScript = $result.Script Write-Verbose "Generating database creation script... Complete!" } - + # Step 2 - Run Database creation script Write-Verbose "Executing database creation script..." try { - Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop + if ($isSQLAdminAccount) + { + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop -Username $adminUsername -Password $adminPassword + } + else + { + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop + } } catch { @@ -157,39 +227,99 @@ function Set-RsDatabase Write-Verbose "Executing database creation script... Complete!" } #endregion Create Database if necessary - - #region Configuring Database rights - # Step 3 - Generate database rights script - Write-Verbose "Generating database rights script..." - $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") - $result = $rsWmiObject.GenerateDatabaseRightsScript($username, $Name, $IsRemoteDatabaseServer, $isWindowsAccount) - if ($result.HRESULT -ne 0) - { - Write-Verbose "Generating database rights script... Failed!" - throw "Failed to generate the database rights script from the report server using WMI. Errorcode: $($result.HRESULT)" - } - else - { - $SQLscript = $result.Script - Write-Verbose "Generating database rights script... Complete!" - } - - # Step 4 - Run Database rights script - Write-Verbose "Executing database rights script..." - try + + #region Create Runtime Database User + if (-not $IsExistingDatabaseUser) { - Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLscript -ErrorAction Stop + # nothing to do if it is a windows user + $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") + if (-not $isWindowsAccount) + { + # Step 3 - Generate database user script + Write-Verbose "Generating database user creation script..." + $SQLscript = " + -- create the login if it does not exist + if not exists(select * from sys.server_principals where name = '$username') + CREATE LOGIN $username WITH PASSWORD = '$password'; + GO + + -- Creates a database user for the login created above, if it does not exist + if not exists(select * from sys.database_principals where name = '$username') + CREATE USER $username FOR LOGIN $username; + GO + " + + Write-Verbose "Generating database user creation script... Complete!" + + # Step 4 - Run Database rights script + Write-Verbose "Executing database user creation script..." + try + { + if ($isSQLAdminAccount) + { + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop -Username $adminUsername -Password $adminPassword + } + else + { + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop + } + } + catch + { + Write-Verbose "Executing database user creation script... Failed!" + throw + } + Write-Verbose "Executing database user creation script... Complete!" + + } else { + Write-Verbose "Not generating database user, since using Windows account." + } } - catch + #endregion Create Runtime Database User + + + #region Configuring Database rights + if (-not $HasDatabaseUserRights) { - Write-Verbose "Executing database rights script... Failed!" - throw + # Step 5 - Generate database rights script + Write-Verbose "Generating database rights script..." + $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") + $result = $rsWmiObject.GenerateDatabaseRightsScript($username, $Name, $IsRemoteDatabaseServer, $isWindowsAccount) + if ($result.HRESULT -ne 0) + { + Write-Verbose "Generating database rights script... Failed!" + throw "Failed to generate the database rights script from the report server using WMI. Errorcode: $($result.HRESULT)" + } + else + { + $SQLscript = $result.Script + Write-Verbose "Generating database rights script... Complete!" + } + + # Step 6 - Run Database rights script + Write-Verbose "Executing database rights script..." + try + { + if ($isSQLAdminAccount) + { + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop -Username $adminUsername -Password $adminPassword + } + else + { + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop + } + } + catch + { + Write-Verbose "Executing database rights script... Failed!" + throw + } + Write-Verbose "Executing database rights script... Complete!" } - Write-Verbose "Executing database rights script... Complete!" #endregion Configuring Database rights - + #region Update Reporting Services database configuration - # Step 5 - Update Reporting Services to connect to new database now + # Step 7 - Update Reporting Services to connect to new database now Write-Verbose "Updating Reporting Services to connect to new database..." $result = $rsWmiObject.SetDatabaseConnection($DatabaseServerName, $Name, $DatabaseCredentialType.Value__, $username, $password) if ($result.HRESULT -ne 0) From 67d23409f04b7a2abc23fe36d674268c22415f57 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Thu, 22 Feb 2018 20:27:50 +0200 Subject: [PATCH 2/3] Remove user creation --- .../Functions/Admin/Set-RsDatabase.ps1 | 67 ++----------------- 1 file changed, 5 insertions(+), 62 deletions(-) diff --git a/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 b/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 index 9dc02e08..993cbc0a 100644 --- a/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 +++ b/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 @@ -13,9 +13,8 @@ function Set-RsDatabase You must be an admin in RS and SQL Server in order to perform this operation successfully. There are three phases to setup: 1. Create the PBIRS database on the database server - 2. Create the run-time user - 3. Grant the run-time user access to the PBIRS database - 4. Configure the PowerBI Report Server to use the database and run-time credentials + 2. Grant the run-time user access to the PBIRS database - this user must exist before running this + 3. Configure the PowerBI Report Server to use the database and run-time credentials Your admin role on SQL Server can be one of: * The account under which you run this powershell (default) * A specific set of credentials for the SQL Server which has admin rights, specified via -AdminDatabaseCredential @@ -48,9 +47,6 @@ function Set-RsDatabase .PARAMETER IsExistingDatabase Specify this switch if the database to use already exists, and prevent creation of the database. - .PARAMETER IsExistingDatabaseUser - Specify this switch if the runtime database user already exists, and prevent creation of the user. Relevant only if the runtime user is an SQL credential type. - .PARAMETER HasDatabaseUserRights Specify this switch if the runtime database user already has access rights to the database, and prevent granting the user rights. @@ -101,9 +97,6 @@ function Set-RsDatabase [switch] $IsExistingDatabase, - [switch] - $IsExistingDatabaseUser, - [switch] $HasDatabaseUserRights, @@ -228,60 +221,10 @@ function Set-RsDatabase } #endregion Create Database if necessary - #region Create Runtime Database User - if (-not $IsExistingDatabaseUser) - { - # nothing to do if it is a windows user - $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") - if (-not $isWindowsAccount) - { - # Step 3 - Generate database user script - Write-Verbose "Generating database user creation script..." - $SQLscript = " - -- create the login if it does not exist - if not exists(select * from sys.server_principals where name = '$username') - CREATE LOGIN $username WITH PASSWORD = '$password'; - GO - - -- Creates a database user for the login created above, if it does not exist - if not exists(select * from sys.database_principals where name = '$username') - CREATE USER $username FOR LOGIN $username; - GO - " - - Write-Verbose "Generating database user creation script... Complete!" - - # Step 4 - Run Database rights script - Write-Verbose "Executing database user creation script..." - try - { - if ($isSQLAdminAccount) - { - Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop -Username $adminUsername -Password $adminPassword - } - else - { - Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop - } - } - catch - { - Write-Verbose "Executing database user creation script... Failed!" - throw - } - Write-Verbose "Executing database user creation script... Complete!" - - } else { - Write-Verbose "Not generating database user, since using Windows account." - } - } - #endregion Create Runtime Database User - - #region Configuring Database rights if (-not $HasDatabaseUserRights) { - # Step 5 - Generate database rights script + # Step 3 - Generate database rights script Write-Verbose "Generating database rights script..." $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") $result = $rsWmiObject.GenerateDatabaseRightsScript($username, $Name, $IsRemoteDatabaseServer, $isWindowsAccount) @@ -296,7 +239,7 @@ function Set-RsDatabase Write-Verbose "Generating database rights script... Complete!" } - # Step 6 - Run Database rights script + # Step 4 - Run Database rights script Write-Verbose "Executing database rights script..." try { @@ -319,7 +262,7 @@ function Set-RsDatabase #endregion Configuring Database rights #region Update Reporting Services database configuration - # Step 7 - Update Reporting Services to connect to new database now + # Step 5 - Update Reporting Services to connect to new database now Write-Verbose "Updating Reporting Services to connect to new database..." $result = $rsWmiObject.SetDatabaseConnection($DatabaseServerName, $Name, $DatabaseCredentialType.Value__, $username, $password) if ($result.HRESULT -ne 0) From 99a55765159d7b6026425541624e84c601060e69 Mon Sep 17 00:00:00 2001 From: Avi Deitcher Date: Thu, 22 Feb 2018 20:57:42 +0200 Subject: [PATCH 3/3] Granting db rights idempotent, so always run --- .../Functions/Admin/Set-RsDatabase.ps1 | 65 ++++++++----------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 b/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 index 993cbc0a..691a651c 100644 --- a/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 +++ b/ReportingServicesTools/Functions/Admin/Set-RsDatabase.ps1 @@ -47,9 +47,6 @@ function Set-RsDatabase .PARAMETER IsExistingDatabase Specify this switch if the database to use already exists, and prevent creation of the database. - .PARAMETER HasDatabaseUserRights - Specify this switch if the runtime database user already has access rights to the database, and prevent granting the user rights. - .PARAMETER DatabaseCredentialType Indicate what type of runtime credentials to use when connecting to the database: Windows, SQL, or Service Account. @@ -97,9 +94,6 @@ function Set-RsDatabase [switch] $IsExistingDatabase, - [switch] - $HasDatabaseUserRights, - [Parameter(Mandatory = $true)] [Alias('Authentication')] [Microsoft.ReportingServicesTools.SqlServerAuthenticationType] @@ -168,7 +162,7 @@ function Set-RsDatabase } # must have credentials passed - if ($AdminDatabaseCredentialType -like 'sql') + if ($isSQLAdminAccount) { if ($AdminDatabaseCredential -eq $null) { @@ -222,43 +216,40 @@ function Set-RsDatabase #endregion Create Database if necessary #region Configuring Database rights - if (-not $HasDatabaseUserRights) + # Step 3 - Generate database rights script + Write-Verbose "Generating database rights script..." + $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") + $result = $rsWmiObject.GenerateDatabaseRightsScript($username, $Name, $IsRemoteDatabaseServer, $isWindowsAccount) + if ($result.HRESULT -ne 0) { - # Step 3 - Generate database rights script - Write-Verbose "Generating database rights script..." - $isWindowsAccount = ($DatabaseCredentialType -like "Windows") -or ($DatabaseCredentialType -like "ServiceAccount") - $result = $rsWmiObject.GenerateDatabaseRightsScript($username, $Name, $IsRemoteDatabaseServer, $isWindowsAccount) - if ($result.HRESULT -ne 0) - { - Write-Verbose "Generating database rights script... Failed!" - throw "Failed to generate the database rights script from the report server using WMI. Errorcode: $($result.HRESULT)" - } - else - { - $SQLscript = $result.Script - Write-Verbose "Generating database rights script... Complete!" - } + Write-Verbose "Generating database rights script... Failed!" + throw "Failed to generate the database rights script from the report server using WMI. Errorcode: $($result.HRESULT)" + } + else + { + $SQLscript = $result.Script + Write-Verbose "Generating database rights script... Complete!" + } - # Step 4 - Run Database rights script - Write-Verbose "Executing database rights script..." - try + # Step 4 - Run Database rights script + Write-Verbose "Executing database rights script..." + try + { + if ($isSQLAdminAccount) { - if ($isSQLAdminAccount) - { - Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop -Username $adminUsername -Password $adminPassword - } - else - { - Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop - } + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop -Username $adminUsername -Password $adminPassword } - catch + else { - Write-Verbose "Executing database rights script... Failed!" - throw + Invoke-Sqlcmd -ServerInstance $DatabaseServerName -Query $SQLScript -ErrorAction Stop } - Write-Verbose "Executing database rights script... Complete!" } + catch + { + Write-Verbose "Executing database rights script... Failed!" + throw + } + Write-Verbose "Executing database rights script... Complete!" #endregion Configuring Database rights #region Update Reporting Services database configuration