<# .SYNOPSIS Script 19 - Service Application Inventory Report .DESCRIPTION READ-ONLY script. Collects SharePoint Service Application configuration: - Service App Name & Type - Application Pool & Service Account - Proxy / Endpoint indicators - Migration risk classification #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$OutputCsv, [switch]$NoPrompt ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" Write-Host "SCRIPT 18 - SERVICE APPLICATION INVENTORY REPORT" -ForegroundColor Cyan Write-Host "READ-ONLY - NO CHANGES WILL BE MADE" -ForegroundColor Green Write-Host "" # Load Snap-in try { if (-not (Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) { Add-PSSnapin Microsoft.SharePoint.PowerShell } } catch { throw "Run in SharePoint Management Shell. Error: $($_.Exception.Message)" } # Output setup $outDir = Split-Path -Path $OutputCsv -Parent if ([string]::IsNullOrWhiteSpace($outDir)) { throw "Provide full OutputCsv path. Example: C:\Temp\ServiceAppInventory.csv" } if (-not (Test-Path $outDir)) { New-Item -Path $outDir -ItemType Directory -Force | Out-Null } $timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss") $baseName = [System.IO.Path]::GetFileNameWithoutExtension($OutputCsv) $summaryPath = Join-Path $outDir "$baseName`_$timestamp`_Summary.csv" $logPath = Join-Path $outDir "$baseName`_$timestamp`_RunLog.txt" $errorPath = Join-Path $outDir "$baseName`_$timestamp`_Errors.csv" # Logging helpers $log = New-Object System.Collections.Generic.List[string] $errors = New-Object System.Collections.Generic.List[object] function Log { param($msg) $line = "[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $msg $log.Add($line) | Out-Null Write-Host $line } function Add-Error { param($scope, $msg) $errors.Add([pscustomobject]@{ Timestamp = Get-Date Scope = $scope Message = $msg }) | Out-Null } # Prompt if (-not $NoPrompt) { Write-Host "This script inventories service applications (read-only)." -ForegroundColor Yellow if ((Read-Host "Type YES to continue") -ne "YES") { return } } # Risk Model function Get-RiskLevel { param($TypeName) if ($TypeName -match "Search|User Profile|Managed Metadata") { return "High" } if ($TypeName -match "Secure Store|Subscription") { return "Medium" } return "Low" } function Get-Score { param($risk) switch ($risk) { "High" { return 30 } "Medium" { return 60 } "Low" { return 90 } default { return 50 } } } function Get-Recommendation { param($risk) switch ($risk) { "High" { return "Validate service app compatibility. Plan rebuild or migration." } "Medium" { return "Review configuration and confirm requirement post-migration." } "Low" { return "Baseline service application. Suitable for migration." } } } # Main execution $results = New-Object System.Collections.Generic.List[object] try { $serviceApps = Get-SPServiceApplication Log "Found $($serviceApps.Count) service application(s)" } catch { Add-Error "ServiceAppDiscovery" $_.Exception.Message throw } foreach ($app in $serviceApps) { try { $name = $app.Name $type = $app.TypeName $appPool = $app.ApplicationPool.Name $appPoolId = $app.ApplicationPool.Id $svcAccount = $app.ApplicationPool.ProcessAccountName # Endpoint presence (not full detail, just indicator) $hasEndpoint = $false try { $endpoints = Get-SPServiceApplicationEndpoint -ServiceApplication $app -ErrorAction SilentlyContinue if ($endpoints) { $hasEndpoint = $true } } catch { } $risk = Get-RiskLevel -TypeName $type $results.Add([pscustomobject]@{ ServiceAppName = $name TypeName = $type ApplicationPool = $appPool IISAppPoolId = $appPoolId ServiceAccount = $svcAccount EndpointPresent = $hasEndpoint RiskLevel = $risk Score = Get-Score $risk Category = "ServiceApplicationInventory" ActionRecommendation = Get-Recommendation $risk }) | Out-Null } catch { Add-Error $app.Name $_.Exception.Message } } # Export detail $results | Export-Csv -Path $OutputCsv -NoTypeInformation -Encoding UTF8 # Export summary $results | Group-Object RiskLevel | ForEach-Object { [pscustomobject]@{ RiskLevel = $_.Name Count = $_.Count } } | Export-Csv -Path $summaryPath -NoTypeInformation -Encoding UTF8 # Logs $log | Set-Content $logPath if ($errors.Count -gt 0) { $errors | Export-Csv -Path $errorPath -NoTypeInformation -Encoding UTF8 Write-Host "ERROR REPORT: $errorPath" -ForegroundColor Yellow } Write-Host "DETAIL REPORT: $OutputCsv" -ForegroundColor Green Write-Host "SUMMARY REPORT: $summaryPath" -ForegroundColor Green Write-Host "RUN LOG: $logPath" -ForegroundColor Green Write-Host "Complete." -ForegroundColor Green