【问题标题】:RSConfig generates a Dsn Connection String doesn't workRSConfig 生成 Dsn 连接字符串不起作用
【发布时间】:2019-09-23 17:18:29
【问题描述】:

TL;DR

复制步骤,备份您的C:\Program Files\Microsoft SQL Server\MSRS13.SSRS\Reporting Services\ReportServer\RsReportServer.config

运行此命令以更新 SSRS 配置中的连接字符串:

C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn>rsconfig -c -s <ServerName> -i <instanceNameIfNotDefault> -d "reportserver$ssrs" -a SQL -u sa -p "YourSAPassword" -t

现在浏览到 SSRS 网站,它不起作用!要修复它,请恢复您的配置文件或通过 SSRS GUI 工具运行它,它可以工作!

RsConfig 实用程序如何工作?


背景
在 Windows 2016 服务器上安装 SSRS 并恢复 2 个数据库后,我需要更改 SSRS 配置文件中的连接字符串以指向新的 SQL 服务器名称/实例。

问题
当我尝试使用 RSConfig 实用程序更改 C:\Program Files\Microsoft SQL Server\MSRS13.SSRS\Reporting Services\ReportServer\RsReportServer.config 文件中的加密连接字符串时:

C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn>rsconfig -c -s Server0012 -i SSRS -d "reportserver$ssrs" -a SQL -u sa -p "P@ssw0rd!" -t

它会更改 RsReportServer.config 中的 Dsn 连接字符串。

之前: AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAE+tJc/4Vs0a0fdH0tCY8kgQAAAAiAAAAUgBlAHAAbwByAHQAaQBuAGcAIABTAGUAcgB2AGUacgAAABBmAAAAAAQAAIAAAAC2DBxZFsfVB16r0e3...... *

之后: AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAE+tJc/4Vs0a0fdH0tCY8kgQAAAAiAAAAUgBlAHAAbwByAHQAaQBuAGcAIABTAGUAcgB2AGUacgAAABBmAAAAAAQAAIAAAAO2nOjFDJMo........ *

但是在此更改之后,浏览到 SSRS 网站会导致错误:

报表服务器无法连接到其数据库。确保数据库正在运行且可访问。您还可以查看报表服务器跟踪日志以了解详细信息。

如果我运行 SQL Reporting Services 配置工具 (GUI) 并将 Dsn 连接字符串更改为浏览 SSRS 网站就可以了!

显然它改变了 Dsn,但我不知道它在 GUI 工具运行时还能做什么。我使用过 ProcessMonitor,并且我看到 GUI 工具确实使用 RSConfig.exe 实用程序,它使用自己的 RsConfigTool.exe!所以我什至无法捕获实际命令/连接字符串应该是什么的命令行参数。此外,每次我们更改连接字符串时都会生成一个新的随机字符串,因此不确定如何比较实际与预期。

我做了一个注册表键的 WinDiff,除了一些加密的十六进制差异之外,没有什么特别突出的。

我运行 SQLProfiler,并且在我的 PowerShell 脚本中模拟了一堆授权,例如:

$sqls += @"
USE [ReportServer`$SSRSTempDB]
if not exists (select * from sysusers where issqlrole = 1 and name = 'RSExecRole')
BEGIN
 EXEC sp_addrole 'RSExecRole'
END;
GO

我的预感是 SQL 数据库名称中的 $ 符号,当我运行命令时,“虚构/模拟”密码中的 @ 没有被转义,例如:

$MachineName = "server0012"
$instanceName = "SSRS"
$saPassword = "P@ssw0rd!"

$rsConfigPath = "C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn\rsconfig.exe"
$setupArgs = -join('-c -s "', $MachineName,'" -i "', $instanceName,'" -d ','"ReportServer`$SSRS" -t -a SQL -u "sa" -p "', $saPassword,"""")

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process
Write-Host $rsConfigPath $setupArgs
$args = $setupArgs.Split(" ")
& "$rsConfigPath" $args

Restart-Service -Force "SQL Server ($instanceName)"

当我在命令提示符中运行这些普通命令时(无需转义 PowerShell 字符):

rsconfig -c -s Server0012 -i SSRS -d "reportserver$ssrs" -a SQL -u sa -p "P@ssw0rd!"

它改变了 Dsn 连接字符串,但浏览到 SSRS 网站给出了同样的错误(上图)。

如何了解 RsConfigTool.exe 在更改当前报表服务器数据库时还有什么作用?或者任何猜测为什么使用 RSConfig 实用程序生成的连接字符串不正常 - 我尝试了许多不同的组合,似乎只有 RSConfigTool 才能真正做到?

注 1:
我将这一切编写为一个 DevOps 项目,我们正在使用打包程序烘焙这些图像,因此无法手动完成任何操作。

注2:
机器加入域并在安装 SQL 后重命名。所以使用我认为行不通的 Configuration.ini 文件。

【问题讨论】:

  • 哇,这看起来很有趣。 “我怎样才能知道 RsConfigTool.exe 的其他功能[...]”您是否尝试对驱动器进行快照并对其进行比较?也许它让那个魔法更加清晰。
  • 您应该能够使用 VSS 创建快照并区分目录结构和文件内容。两者都适用于 PowerShell。您还应该能够解码 dsn 字符串以区分它们。
  • 制作你的驱动器的快照并进行比较? - 我不需要,因为我知道这是我感兴趣的配置文件(除了 SQL 命令)。 您还应该能够解码 dsn 字符串以区分它们。 - 这在 afaik 中是不可能的,加密的注册表项也是如此(这将是一个巨大的漏洞)。谢谢

标签: sql powershell encryption reporting-services connection-string


【解决方案1】:

诀窍是您需要使用 Powershell Invoke-Expression 命令,服务器名称必须包含不带引号的实例名称 server\instance,并且您需要转义 RsConfig.exe 命令中的 $ 符号:@987654324 @

= ` 转义 $ 符号的 tilda 键,参见下面的脚本。

如果您不使用 Invoke-Expression 并转义 $ 符号,则 DatabaseName 称为 ReportServer 而不是 ReportServer$SSRS

您可以在 SSRS 日志中看到这一点:

library!WindowsService_1!30c!05/17/2019-03:56:29::e 错误:抛出 Microsoft.ReportingServices.Library.ReportServerDatabaseUnavailableException: , Microsoft.ReportingServices.Library.ReportServerDatabaseUnavailableException: 报表服务器无法打开与报表服务器的连接 数据库。所有请求都需要连接到数据库 和处理。 ---> System.Data.SqlClient.SqlException:一个 建立时发生与网络相关或特定于实例的错误 到 SQL Server 的连接。 服务器未找到或未找到 无障碍。验证实例名称是否正确以及 SQL 服务器配置为允许远程连接。(提供者:命名 Pipes Provider,错误:40 - 无法打开与 SQL Server 的连接)

这是我用来修复已重命名的服务器上损坏的 SQL 安装的脚本:

Param(
    [parameter(mandatory=$true,helpmessage="New Machine Name")]
    [string]$MachineName,

    [parameter(mandatory=$false,helpmessage="SQL Instance Name")]
    [string]$instanceName = "SSRS",

    [parameter(mandatory=$false,helpmessage="SQL SA Password")]
    [string]$saPassword = "P@ssword1"  #this is encrypted IRL
)


#1. Start the logging
Start-Transcript -Path "C:\temp\rename-ssrs-computer.txt"

#2. Change the SQL Server's name
Write-Host "Change the SQL Server Instance Name to $MachineName"


$moduleName = "SqlServer"
Import-Module $moduleName -Verbose

$sql = 'select @@SERVERNAME'
$serverNameQry = Invoke-SqlCmd -Serverinstance ".\$instanceName" -Query $sql -username "sa" -password $saPassword  -querytimeout ([int]::MaxValue)
$serverName = $serverNameQry.Column1

$sql = -join('sp_dropserver ''', $serverName,'''
GO
sp_addserver ''', $MachineName, "\", $instanceName,''',''local''
GO
')
Invoke-SqlCmd -Serverinstance ".\$instanceName" -Query $sql -username "sa" -password $saPassword  -querytimeout ([int]::MaxValue)

#3. Change the SSRS database permissions
$sqls = @()
$sqls += @"
USE master

DECLARE @AccountName nvarchar(260)
SET @AccountName = SUSER_SNAME(0x010100000000000514000000)
if not exists (select name from syslogins where name = @AccountName and hasaccess = 1 and isntname = 1)
BEGIN
EXEC sp_grantlogin @AccountName
END;
GO
"@

#..... all the SQL Profile trace outputs...#

Foreach ($sql in $sqls)
{
  Invoke-SqlCmd -Serverinstance ".\$instanceName" -Query $sql -username "sa" -password $saPassword  -querytimeout ([int]::MaxValue)
}

#4. Change all the registry key values with the AMI Original Computer Name
Write-Host "Change the SQL Server Name in the Registry to $MachineName"

$txt = -join('Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\Machines]
"OriginalMachineName"="',$MachineName,'"

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\90\Machines]
"OriginalMachineName"="',$MachineName,'"

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\140\Machines]
"OriginalMachineName"="',$MachineName,'"

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\130\Machines]
"OriginalMachineName"="',$MachineName,'"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\Services\SSIS Server]
"GroupPrefix"="SQLServerDTSUser$',$MachineName,'"
"LName"=""
"Name"="MsDtsServer"
"Type"=dword:00000004

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\Services\SSIS Server]
"GroupPrefix"="SQLServerDTSUser$',$MachineName,'"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\Services\Report Server]
"Name"="ReportServer"
"LName"="ReportServer$"
"Type"=dword:00000006
"GroupPrefix"="SQLServerReportServerUser$',$MachineName,'$"

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\Services\Report Server]
"Name"="ReportServer"
"LName"="ReportServer$"
"Type"=dword:00000006
"GroupPrefix"="SQLServerReportServerUser$',$MachineName,'$"'

)

Add-Content "C:\temp\output.reg" $txt
regedit /s "C:\temp\output.reg"


#5. Set the encrypted connection string DONT CHANGE THIS!!!
$rsConfigPath = "C:\Program Files (x86)\Microsoft SQL Server\130\Tools\Binn\"
$setupArgs = -join('-c -s ', $MachineName, '\' , $instanceName,' -i ', $instanceName,' -d ','"reportserver`$ssrs"', ' -t -a SQL -u sa -p "', $saPassword,'"')
Write-Host "Setup args for RSConfig $rsConfigPath $setupArgs"
Write-Host "Running RSConfig"
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process
Write-Host $rsConfigPath $setupArgs

Set-Location "$rsConfigPath"
Invoke-Expression $("rsconfig.exe " + $setupArgs) 

Write-Host "RSConfig Dsn complete, new Connection string under Dsn saved to rsconfig.config file."


#6. Restart the SQL Service
Write-Host "Restarting $instanceName"
Restart-Service -Force "SQL Server ($instanceName)"
Write-Host "Restarted $instanceName"


#7. Set regional format (date/time etc.) to English (Australia) - this applies to all users 
Import-Module International 
Set-Culture en-AU 
# Check language list for non-US input languages, exit if found 
$currentlist = Get-WinUserLanguageList 
$currentlist | ForEach-Object {if(($.LanguageTag -ne "en-AU") -and ($.LanguageTag -ne "en-US")){exit}} 
# Set the language list for the user, forcing English (Australia) to be the only language 
Set-WinUserLanguageList en-AU -Force 
Set-TimeZone -Name "AUS Eastern Standard Time"


# Lastly Stop the transcript (before the PC gets rebooted by the calling script).
Stop-Transcript

【讨论】:

    【解决方案2】:

    问题不在于 RsConfigTool.exe。它可以正常工作,并且确实可以正确更改连接字符串。

    问题归结为单引号与双引号以及名称中带有 $ 符号。

    来自docs

    当您将字符串括在双引号中时(双引号 字符串),以美元符号 ($) 开头的变量名是 在将字符串传递给之前替换为变量的值 处理命令。

    当我们尝试输出数据库名称时可以看到:

    PS C:\> Write-Output "ReportServer$SSRS"
    ReportServer
    

    如我们所见,它返回“ReportServer”,然后返回$SSRS 变量(为空)的内容

    为了证明这一点,如果我们为 $SSRS 变量创建并设置一个值:

    PS C:\> $SSRS = "SomethingElse"
    PS C:\> Write-Output "ReportServer$SSRS"
    ReportServerSomethingElse
    

    我们得到“SomethingElse”;-)。但是如果我们用单引号括起来,它不会做变量替换:

    PS C:\> Write-Output 'ReportServer$SSRS'
    ReportServer$SSRS
    

    因此,解决方法是在从 PowerShell 调用 RsConfigTool.exe 工具时,只需将双引号替换为单引号即可:

    rsconfig -c -s Server0012 -i SSRS -d 'reportserver$ssrs' -a SQL -u sa -p 'P@ssw0rd!' -t
    

    【讨论】:

    • 当我在命令提示符中运行这些 vanilla 命令时(无需转义 powershell 字符),它仍然不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    • 2018-09-03
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多