Search code examples
c#reporting-servicessqlreportingservice

Automate SSRS configuration C#


I am trying to create a program that I can run to automate the configuration of reporting service for MSRS13.

The code correctly copies the cert into the trusted root store. The code correctly copies the URL information into the RSReportingServer.Config, but when I try to launch the URL I get a 404 error. If I open the configuration manager to debug and hit apply the Url works and I no longer get a 404. I have tried running as SYSTEM and the LOCAL SERVICE with no luck. Is there anyway to configure these settings through c#?

I tried using RSConfig to change the service account to run as system but I get an error about .net Framework 3.5 not being installed, and then when I install it I run into invalid namespace errors. I would also prefer to not change the service account away from default, but am willing to change it if I can then change it back.

SSRSConfig(string thumbprint, string instanceName){

X509Certificate2 x509 = GetCertificateByThumbprint(thumbprint);
if (x509 != null)
{
    X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
    try
    {
        store.Open(OpenFlags.ReadWrite);
        store.Add(x509);
    }
    catch (Exception e)
    {
        LoggingManager.ErrorFormat(typeof(CLsiCertUtil), "Failed to add cert to trusted store {0}", e.Message);
        exitCode = CertExitCodes.AddCertError;
    }
    finally
    {
        store.Close();
    }
}
else
{
    LoggingManager.Warn(typeof(CLsiCertUtil), "Cert not found in Personal store. Not porting to Trusted root. Cert may need moved by hand.");
}

string inputPath = "C:\\Program Files\\Microsoft SQL Server\\MSRS13." + instanceName + "\\Reporting Services\\ReportServer\\RSReportServer.config";
FileInfo fi = new FileInfo(inputPath);
if (fi.Exists) fi.IsReadOnly = false;

XDocument xdHttp = XDocument.Load(inputPath);
LoggingManager.InfoFormat(typeof(CLsiCertUtil), "Processing config: \"{0}\"", inputPath);

XElement xeHttpRoot = xdHttp.Root;

if (xeHttpRoot == null)
{
    LoggingManager.ErrorFormat(typeof(CLsiCertUtil), "ERROR: Unable to find root xml element for configuration: \"{0}\"", inputPath);
    return;
}

//Find the sub element that contains the comment
XElement xeSSLCertificateConfiguration = xeHttpRoot.Elements().Where(c => c.Name.ToString().Equals("SSLCertificateConfiguration")).FirstOrDefault();

if (xeSSLCertificateConfiguration == null)
{
    XElement bindings =
        new XElement("Bindings",
            new XElement("Binding",
                new XElement("ApplicationName", "ReportServerWebService"),
                new XElement("CertificateHash", thumbprint),
                new XElement("IPAddress", "0.0.0.0"),
                new XElement("Port", "443")),
            new XElement("Binding",
                new XElement("ApplicationName", "ReportServerWebService"),
                new XElement("CertificateHash", thumbprint),
                new XElement("IPAddress", "::"),
                new XElement("Port", "443")),
            new XElement("Binding",
                new XElement("ApplicationName", "ReportServerWebApp"),
                new XElement("CertificateHash", thumbprint),
                new XElement("IPAddress", "0.0.0.0"),
                new XElement("Port", "443"),
            new XElement("Binding",
                new XElement("ApplicationName", "ReportServerWebApp"),
                new XElement("CertificateHash", thumbprint),
                new XElement("IPAddress", "::"),
                new XElement("Port", "443")
                ))
            );
    xeHttpRoot.Add(new XElement("SSLCertificateConfiguration", bindings));
}

//Find the sub element that contains the comment
XElement xeURLReservations = xeHttpRoot.Elements().Where(c => c.Name.ToString().Equals("URLReservations")).FirstOrDefault();

if(xeURLReservations !=  null)
{
    IEnumerable<XElement> listApp = xeURLReservations.Elements();
    foreach (XElement xeApp in listApp)
    {
        string strAccountSid = "";
        string strAccountName = "";
        XElement xeURLs = xeApp.Elements().Where(c => c.Name.ToString().Equals("URLs")).FirstOrDefault();
        if(xeURLs != null)
        {
            XElement xeURL = xeURLs.Elements().Where(c => c.Name.ToString().Equals("URL")).FirstOrDefault();
            if (xeURL != null)
            {
                XElement xeAccountSid = xeURL.Elements().Where(c => c.Name.ToString().Equals("AccountSid")).FirstOrDefault();
                if (xeAccountSid != null)
                {
                    strAccountSid = xeAccountSid.Value.ToString();
                }
                XElement xeAccountName = xeURL.Elements().Where(c => c.Name.ToString().Equals("AccountName")).FirstOrDefault();
                if (xeAccountName != null)
                {
                    strAccountName = xeAccountName.Value.ToString();
                }
            }

            if(!string.IsNullOrWhiteSpace(strAccountSid) && !string.IsNullOrWhiteSpace(strAccountName))
            {
                string strUrl = "https://" + x509.Subject.Substring(3) + ":443";
                XElement newUrl =
                    new XElement("URL",
                        new XElement("UrlString", strUrl),
                        new XElement("AccountSid",strAccountSid),
                        new XElement("AccountName",strAccountName)
                        );
                xeURLs.Add(newUrl);
            }
        }

    }
}

//save the local xml to the web.config
xdHttp.Save(inputPath);
}

Any help is greatly appreciated I have been looking into this for a few weeks with out progress. Let me know if any more info would be helpful.

This is the Reporting Services log

<Header>
  <Product>Microsoft SQL Server Reporting Services Version 13.0.5026.0</Product>
  <Locale>en-US</Locale>
  <TimeZone>Pacific Standard Time</TimeZone>
  <Path>C:\Program Files\Microsoft SQL Server\MSRS13.SYSMGMT_DB\Reporting Services\LogFiles\Microsoft.ReportingServices.Portal.WebHost_03_12_2021_08_51_28.log</Path>
  <SystemName>TB-84MASTER</SystemName>
  <OSName>Microsoft Windows NT 6.2.9200.0</OSName>
  <OSVersion>6.2.9200.0</OSVersion>
</Header>
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Setting up Debug CRT libraries
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: w WARN: %_NTDRIVE% not defined... Skipping
Microsoft.ReportingServices.Portal.WebHost!library!1!03/12/2021-08:51:28:: i INFO: SQLDump flags: ReferencedMemory, AllThreads, SendToWatson
Microsoft.ReportingServices.Portal.WebHost!library!1!03/12/2021-08:51:28:: i INFO: MiniDump flags: DataSegs, UnloadedModules, ProcessThreadData
Microsoft.ReportingServices.Portal.WebHost!library!1!03/12/2021-08:51:28:: i INFO: Dump on: Microsoft.ReportingServices.Diagnostics.Utilities.InternalCatalogExceptionMicrosoft.ReportingServices.Modeling.InternalModelingExceptionMicrosoft.ReportingServices.ReportProcessing.UnhandledReportRenderingException
Microsoft.ReportingServices.Portal.WebHost!library!1!03/12/2021-08:51:28:: i INFO: Do not dump on: System.Threading.ThreadAbortExceptionSystem.Web.UI.ViewStateExceptionSystem.OutOfMemoryExceptionSystem.Web.HttpExceptionSystem.IO.IOExceptionSystem.IO.FileLoadExceptionMicrosoft.SharePoint.SPExceptionMicrosoft.ReportingServices.WmiProvider.WMIProviderExceptionSystem.AppDomainUnloadedException
Microsoft.ReportingServices.Portal.WebHost!library!1!03/12/2021-08:51:28:: i INFO: Minidump location: C:\Program Files\Microsoft SQL Server\MSRS13.SYSMGMT_DB\Reporting Services\LogFiles
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Starting ReportServerWebApp
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Working directory : C:\Program Files\Microsoft SQL Server\MSRS13.SYSMGMT_DB\Reporting Services\RSWebApp
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Report Server url: http://localhost:80/ReportServer_SYSMGMT_DB
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Report Server Web App virtual root: /Reports_SYSMGMT_DB
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Web app url: http://+:80/Reports_SYSMGMT_DB/
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Web app url: https://TB-84Master.lslab.org:443/Reports_SYSMGMT_DB/
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Web app url: https://TB-84Master.lslab.org:443/Reports_SYSMGMT_DB/
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Authentication scheme(s): Ntlm
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 0    : AuthSchemeConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 5    : RequestLoggingConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 10   : CustomAuthenticationConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 20   : BasicAuthenticationConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 25   : RequestThrottlingConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 30   : CsrfTokenCreationConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 40   : LanguageConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 50   : XFrameOptionsConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 50   : ClassicUrlRedirecterConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 50   : PopulateHeadersConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 53   : LocalRequestMiddlewareConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 55   : ClassicUrlRewriterConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 60   : ResponseCompressionConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 100  : FileSystemConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 190  : ServiceUnavailableConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 200  : DatabaseAvailableConfig
Microsoft.ReportingServices.Portal.WebHost!crypto!1!03/12/2021-08:51:28:: i INFO: Initializing crypto as user: NT Service\ReportServer$SYSMGMT_DB
Microsoft.ReportingServices.Portal.WebHost!crypto!1!03/12/2021-08:51:28:: i INFO: Exporting public key
Microsoft.ReportingServices.Portal.WebHost!crypto!1!03/12/2021-08:51:28:: i INFO: Importing existing encryption key
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 300  : CsrfTokenValidationConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:28:: i INFO: Registering 500  : WebApiOwinConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:29:: i INFO: Registering 600  : ODataWebApiOwinConfig
Microsoft.ReportingServices.Portal.WebHost!reportserverwebapp!1!03/12/2021-08:51:30:: e ERROR: Unhandled exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Net.HttpListenerException: Access is denied
   at System.Net.HttpListener.AddAllPrefixes()
   at System.Net.HttpListener.Start()
   at Microsoft.Owin.Host.HttpListener.OwinHttpListener.Start(HttpListener listener, Func`2 appFunc, IList`1 addresses, IDictionary`2 capabilities, Func`2 loggerFactory)
   at Microsoft.Owin.Host.HttpListener.OwinServerFactory.Create(Func`2 app, IDictionary`2 properties)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Owin.Hosting.ServerFactory.ServerFactoryAdapter.Create(IAppBuilder builder)
   at Microsoft.Owin.Hosting.Engine.HostingEngine.Start(StartContext context)
   at Microsoft.Owin.Hosting.Starter.HostingStarter.Start(StartOptions options)
   at Microsoft.ReportingServices.Portal.WebHost.Services.Impl.WebAppWrapper.Start(StartOptions options)
   at Microsoft.ReportingServices.Portal.WebHost.Services.Impl.WebAppServiceController.Start()
   at Microsoft.ReportingServices.Portal.WebHost.Program.Run()
   at Microsoft.ReportingServices.Portal.WebHost.Program.Main(String[] args).

I have continued testing for a few days and still have come up empty handed. If I change the Network list service and SSRS account to run as user or system my code works. But I need to be able to do that in code.


Solution

  • I ended up not finding a way to do this by directly adjusting the config file. I did find the PowerShell class that could run this for me. I used the following code:

    string script = string.Format(@"$wmiName = (Get-WmiObject –namespace root\Microsoft\SqlServer\ReportServer  –class __Namespace).Name
        $rsConfig = Get-WmiObject –namespace ""root\Microsoft\SqlServer\ReportServer\$wmiName\v13\Admin"" -class MSReportServer_ConfigurationSetting -filter ""InstanceName = '{2}'""
    
        $rsConfig.ReserveURL(""ReportServerWebService"", ""https://{0}:443/"", 1033)
        $rsConfig.CreateSSLCertificateBinding(""ReportServerWebService"", ""{1}"", ""0.0.0.0"", 443, 1033)
        $rsConfig.CreateSSLCertificateBinding(""ReportServerWebService"", ""{1}"", ""::"", 443, 1033)
        $rsConfig.ReserveURL(""ReportServerWebApp"", ""https://{0}:443/"", 1033)
        $rsConfig.CreateSSLCertificateBinding(""ReportServerWebApp"", ""{1}"", ""0.0.0.0"", 443, 1033)
        $rsConfig.CreateSSLCertificateBinding(""ReportServerWebApp"", ""{1}"", ""::"", 443, 1033)
        $rsconfig.SetServiceState($false, $false, $false)
        $rsconfig.SetServiceState($true, $true, $true)", x509.Subject.Substring(3), thumbprint.ToLower(), instanceName );