Private/Get-SqlRsInstance.ps1
|
# ============================================================================= # Script : Private/Get-SqlRsInstance.ps1 # Author : Keith Ramsey # Created : 2026-06-08 # ============================================================================= # Change Log # ----------------------------------------------------------------------------- # 2026-06-08 Keith Ramsey Initial: enumerate WMI child namespaces under # root\Microsoft\SqlServer\ReportServer, match by # instance name, resolve the version sub-namespace, # and return the MSReportServer_ConfigurationSetting # CIM instance. DR-013 (WMI mechanism) + DR-014 # (enumerate/auto-detect strategy). # ============================================================================= # Decision Contract: # - Never throws. All errors caught; $null returned on any failure. # - No hostnames, IPs, or service accounts in source (air-gap discipline). # - Instance name matching: prefer exact 'RS_<InstanceName>'; fall back to # any namespace whose Name contains the InstanceName (case-insensitive). # - Version sub-namespace is enumerated, not hard-coded (DR-014 Option A). # - Remote access uses -ComputerName on Get-CimInstance, or a CimSession # when -Credential is supplied. # ============================================================================= function Get-SqlRsInstance { param( [string] $InstanceName = 'MSSQLSERVER', [string] $ComputerName = $env:COMPUTERNAME, [PSCredential]$Credential ) # ------------------------------------------------------------------ # Helper: build a consistent CIM parameter hashtable for every query. # A CimSession is created once when -Credential is supplied; otherwise # -ComputerName is passed directly (no session overhead for local use). # ------------------------------------------------------------------ $session = $null $cimParams = @{} $isLocal = ( $ComputerName -eq $env:COMPUTERNAME -or $ComputerName -eq 'localhost' -or $ComputerName -eq '127.0.0.1' ) try { if (-not $isLocal) { if ($Credential) { $sessionOpt = New-CimSessionOption -Protocol Wsman $session = New-CimSession -ComputerName $ComputerName ` -Credential $Credential ` -SessionOption $sessionOpt ` -ErrorAction Stop $cimParams['CimSession'] = $session } else { $cimParams['ComputerName'] = $ComputerName } } # ------------------------------------------------------------------ # Step 1 — Enumerate child namespaces under the RS root namespace. # Each child namespace name follows the pattern RS_<EncodedInstanceName>. # ------------------------------------------------------------------ $rsRoot = 'root\Microsoft\SqlServer\ReportServer' $childNs = Get-CimInstance @cimParams ` -Namespace $rsRoot ` -ClassName '__Namespace' ` -ErrorAction Stop if (-not $childNs) { return $null } # ------------------------------------------------------------------ # Step 2 — Match the child namespace to the requested instance name. # Preference order: # 1. Exact match on 'RS_<InstanceName>' (case-insensitive). # 2. Any namespace whose Name contains the InstanceName. # ------------------------------------------------------------------ $exactTarget = "RS_$InstanceName" $matched = $childNs | Where-Object { $_.Name -ieq $exactTarget } if (-not $matched) { $matched = $childNs | Where-Object { $_.Name -ilike "*$InstanceName*" } | Select-Object -First 1 } if (-not $matched) { return $null } # ------------------------------------------------------------------ # Step 3 — Enumerate version sub-namespaces under the matched namespace # to find the vN layer (e.g. v13, v14, v15). Pick the first one that # also contains an 'Admin' sub-namespace — that is the Admin namespace # referenced by DR-013. # ------------------------------------------------------------------ $nsBase = "$rsRoot\$($matched.Name)" $versionNs = Get-CimInstance @cimParams ` -Namespace $nsBase ` -ClassName '__Namespace' ` -ErrorAction Stop if (-not $versionNs) { return $null } $adminNs = $null foreach ($ver in ($versionNs | Where-Object { $_.Name -imatch '^v\d+$' })) { $candidate = "$nsBase\$($ver.Name)" $adminChild = Get-CimInstance @cimParams ` -Namespace $candidate ` -ClassName '__Namespace' ` -ErrorAction SilentlyContinue | Where-Object { $_.Name -ieq 'Admin' } if ($adminChild) { $adminNs = "$candidate\Admin" break } } if (-not $adminNs) { return $null } # ------------------------------------------------------------------ # Step 4 — Return the MSReportServer_ConfigurationSetting CIM instance # from the resolved Admin namespace. # ------------------------------------------------------------------ $configInstance = Get-CimInstance @cimParams ` -Namespace $adminNs ` -ClassName 'MSReportServer_ConfigurationSetting' ` -ErrorAction Stop return $configInstance } catch { return $null } finally { if ($session) { Remove-CimSession -CimSession $session -ErrorAction SilentlyContinue } } } |