Automated Batch Export of SSRS Reports via PowerShell

Modified on Mon, 7 Sep at 7:01 AM

Automated Batch Export of SSRS Reports via PowerShell & SQL Agent

Overview: This solution automates bulk document extraction and rendering from SQL Server Reporting Services (SSRS). It documents the transition between the legacy native subscription injection mechanism and the PowerShell queue-driven export pipeline. The environment utilizes dedicated SQL Server Agent jobs to orchestrate batch student performance graphs, handle parameter XML serialization, and render files to network shares.


Architecture & End-to-End Workflow

[ Crystal Reports / Application UI ]
              │
              ├─► Legacy: Writes to [dbo.uReportServerSubscriptionLog] 
              │            └─► SQL Agent: "Graphinator" executes dbo.uspgReportServerSubscription
              │                 └─► Calls ReportServer.dbo.CreateTask / CreateSubscription
              │
              └─► Modern: Writes to [dbo.uReportServerBatchQueue] (StatusCode = 0)
                           │
                           │ Polled via SQL Agent / Scheduled Script
                           ▼
                  [ Get-BatchReports.ps1 ]
                     │              │
                     │ LoadReport() │ SetExecutionParameters()
                     │ & Render()   │
                     ▼              ▼
           [ SSRS SOAP Web Service ] (http://localhost/ReportServer)
                           │
                           │ Returns binary stream
                           ▼
              [ File System Destination ] (e.g. \\Server\Share\ExportFolder\...)
                           │
                           │ Updates StatusCode = 2 (Success) or 3 (Failure)
                           ▼
              [ dbo.uReportServerBatchQueue ]
                           │
                           ▼
          [ SQL Agent: Rename / Post-Processing Jobs ]
  1. Batch Request Ingestion: An application routine or Crystal Reports batch export identifies the target student cohort and inserts execution metadata into either the modern queue (dbo.uReportServerBatchQueue) or the legacy subscription log (dbo.uReportServerSubscriptionLog).
  2. Queue Polling & Dispatch:
    • Modern Pipeline: A scheduled script or task invokes Get-BatchReports.ps1, retrieving all pending jobs where StatusCode = 0.
    • Legacy Pipeline: The SQL Server Agent job "The Graphinator" polls uReportServerSubscriptionLog for unprocessed records modified within the past 3 days (len(OwnerID) = 0) and processes them via dbo.uspgReportServerSubscription.
  3. Web Service Proxy Initialisation: In the PowerShell pipeline, the script instantiates a SOAP client against the local SSRS execution endpoint using New-WebServiceProxy and Windows Integrated credentials (-UseDefaultCredential).
  4. Session Instantiation & Parameter Binding: The report definition is loaded via LoadReport(), parameters are unpacked from XML, and then explicitly bound to the execution session using SetExecutionParameters().
  5. Stream Rendering & File Creation: The SOAP Render() method exports the document to binary (such as PDF). After validating that the byte stream is non-zero, the array is written to disk via .NET file I/O.
  6. Queue Reconciliation & Renaming: The database record is updated to StatusCode = 2 (Success) or StatusCode = 3 (Failure). Downstream jobs (such as Rename graph reports) standardize file naming conventions.

SQL Server Agent Jobs in Play

SQL Server Agent manages scheduling, triggering, and file handoffs across several specific jobs:

Job NameStep NameTypeRole & Function
The GraphinatorPush out the scheduled graph reportsT-SQLPolls uReportServerSubscriptionLog for items where len(OwnerID) = 0 and ModifiedDate > DATEADD(dd, -3, CURRENT_TIMESTAMP), executing dbo.uspgReportServerSubscription @scheduleid in a loop with a 3-second delay.
Rename graph reportsFile Post-ProcessingCmdExec / PowerShellExecutes post-export file renaming, stripping temporary prefixes, or moving finalized PDFs into student archive directories.
Batch Reports DispatcherExecute Get-BatchReports.ps1CmdExecRuns powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\graphreports\Get-BatchReports.ps1" to process pending records in uReportServerBatchQueue.

Database Objects in Play

DatabaseObject NameObject TypeRole & Description
Application DBdbo.uReportServerBatchQueueTablePrimary modern queue holding pending (StatusCode = 0), successful (2), and failed (3) export records.
Application DBdbo.uReportServerSubscriptionLogTableLegacy queue table storing subscription GUIDs, target UNC paths, and serialized SSRS parameters.
Application DBdbo.uspgReportServerSubscriptionStored ProcedureLegacy stored procedure that dynamically injected temporary subscriptions into the ReportServer catalog tables.
ReportServerdbo.ExecutionLog3System ViewSSRS execution log used to diagnose render formats (RPL, PDF), execution time, byte counts, and engine errors.
ReportServerdbo.CatalogSystem TableSSRS metadata catalog containing report RDL definitions, folder hierarchies, and parameter validation constraints.


Queue Table Schema (dbo.uReportServerBatchQueue)

  • BatchSeq (int, PK): Unique batch row sequence.
  • ReportPath (varchar): SSRS catalog path (e.g. SiteReports/PerformanceGraph).
  • FileName (varchar): Destination file name.
  • ExportFilePath (varchar): Local or UNC target directory path.
  • ReportParameters (xml): Serialized parameters (e.g. <ParameterValues><ParameterValue><Name>ID</Name><Value>12345</Value></ParameterValue></ParameterValues>).
  • StatusCode (int): Execution state (0 = Pending, 1 = In-progress, 2 = Success, 3 = Failure).
  • LastStatusMsg (varchar): Status text or caught exception details.
  • CreatedDate / ModifiedDate (datetime): Record audit timestamps.

Script Configuration Reference

Global execution options are isolated in C:\Scripts\graphreports\config.ps1:

VariableTypeDescriptionGeneric Example
$dbserverStringTarget SQL Server instance hosting the batch queue table."sqlserver.domain.local\INSTANCE"
$databaseStringApplication database containing the queue table."Application_PRD"
$rsserverStringSSRS host name. Always use localhost when running locally to prevent loopback authentication rejections."localhost"
$rsinstanceStringSSRS ReportServer virtual directory name. Typically ReportServer (default), not the database name."ReportServer"
$FileYearIntegerFallback calendar/academic year passed when omitted by queue records.2026
$FileSemesterIntegerFallback semester/term parameter passed when omitted.1
$FileTypeStringDocument category code required by cascading parameter chains.'Academic'

Common Failure Modes & Troubleshooting

1. 0-Byte Destination Files
Root Cause: Writing to disk using [System.IO.FileMode]::Create before verifying that the SOAP render call returned bytes. If SSRS throws a parameter validation error or the session aborts, an empty file is written.
Resolution: Ensure commonCode.ps1 validates $null -ne $RenderOutput -and $RenderOutput.Length -gt 0 before opening the file stream, and wrap execution in a structured try/catch block.

2. HTTP 503: Service Unavailable
Root Cause: Setting $rsinstance to an invalid virtual directory (e.g. using the SQL instance name ReportServer_INSTANCE instead of ReportServer), or pointing $rsserver to an external FQDN blocked by Windows loopback security.
Resolution: Configure $rsserver = "localhost" and $rsinstance = "ReportServer". Verify availability in a local browser at http://localhost/ReportServer/ReportExecution2005.asmx?WSDL.

3. "Value provided for parameter 'X' is not valid" (rsInvalidReportParameter)
Root Cause: Cascading parameter validation failure. SSRS rejects child parameters (such as student ID) if the parent parameters (FileYear, FileSemester) are missing from the execution session, because the child value does not exist in the filtered "Available Values" query.
Resolution: Verify the ReportParameters XML column in dbo.uReportServerBatchQueue contains all required parent filter values.

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article