Skip to content

PowerShell Setup: Control 2.16 - RAG Source Integrity Validation

Last Updated: January 2026 Modules Required: PnP.PowerShell, Microsoft.PowerApps.Administration.PowerShell

Prerequisites

# Install required modules
Install-Module -Name PnP.PowerShell -Force -Scope CurrentUser
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force -Scope CurrentUser

# Connect to SharePoint Online
Connect-PnPOnline -Url "https://contoso.sharepoint.com" -Interactive

# Connect to Power Platform (interactive authentication)
Add-PowerAppsAccount

# For automated/unattended scenarios, use service principal authentication:
# $appId = "<Application-Client-ID>"
# $secret = "<Client-Secret>"
# $tenantId = "<Tenant-ID>"
# Add-PowerAppsAccount -ApplicationId $appId -ClientSecret $secret -TenantID $tenantId

Knowledge Source Inventory Scripts

Audit SharePoint Document Libraries

<#
.SYNOPSIS
    Audits SharePoint document libraries used as knowledge sources

.DESCRIPTION
    Generates a report of documents in a library including:
    - Last modified date (for staleness detection)
    - Version count
    - Approval status

.PARAMETER SiteUrl
    SharePoint site URL

.PARAMETER LibraryName
    Document library name

.EXAMPLE
    .\Audit-KnowledgeSource.ps1 -SiteUrl "https://contoso.sharepoint.com/sites/research" -LibraryName "Research Library"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl,
    [Parameter(Mandatory=$true)]
    [string]$LibraryName
)

# Connect to SharePoint
Connect-PnPOnline -Url $SiteUrl -Interactive

Write-Host "=== Knowledge Source Audit ===" -ForegroundColor Cyan
Write-Host "Site: $SiteUrl"
Write-Host "Library: $LibraryName"

# Get all documents in the library
$items = Get-PnPListItem -List $LibraryName -PageSize 500

$report = $items | Where-Object { $_.FileSystemObjectType -eq "File" } | ForEach-Object {
    $item = $_
    $modified = [DateTime]$item["Modified"]
    $daysSinceModified = (Get-Date) - $modified

    [PSCustomObject]@{
        FileName = $item["FileLeafRef"]
        FilePath = $item["FileRef"]
        LastModified = $modified
        DaysSinceModified = [int]$daysSinceModified.TotalDays
        ModifiedBy = $item["Editor"].LookupValue
        Version = $item["_UIVersionString"]
        ApprovalStatus = $item["_ModerationStatus"]
        IsStale = $daysSinceModified.TotalDays -gt 365
    }
}

# Display summary
Write-Host "`n=== Summary ===" -ForegroundColor Cyan
Write-Host "Total Documents: $($report.Count)"
$staleCount = ($report | Where-Object { $_.IsStale }).Count
Write-Host "Stale Documents (>365 days): $staleCount" -ForegroundColor $(if ($staleCount -gt 0) { "Yellow" } else { "Green" })

# Show stale documents
if ($staleCount -gt 0) {
    Write-Host "`n=== Stale Documents ===" -ForegroundColor Yellow
    $report | Where-Object { $_.IsStale } | Format-Table FileName, LastModified, DaysSinceModified
}

# Export report
$reportPath = "KnowledgeSource-Audit-$(Get-Date -Format 'yyyyMMdd').csv"
$report | Export-Csv -Path $reportPath -NoTypeInformation
Write-Host "`nReport exported to: $reportPath"

Check Document Versioning Configuration

<#
.SYNOPSIS
    Checks versioning configuration for SharePoint document libraries

.PARAMETER SiteUrl
    SharePoint site URL

.EXAMPLE
    .\Check-VersioningConfig.ps1 -SiteUrl "https://contoso.sharepoint.com/sites/research"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl
)

Connect-PnPOnline -Url $SiteUrl -Interactive

Write-Host "=== Versioning Configuration Audit ===" -ForegroundColor Cyan

# Get all document libraries
$libraries = Get-PnPList | Where-Object { $_.BaseTemplate -eq 101 }

$versioningReport = $libraries | ForEach-Object {
    [PSCustomObject]@{
        LibraryName = $_.Title
        VersioningEnabled = $_.EnableVersioning
        MajorVersions = $_.MajorVersionLimit
        MinorVersionsEnabled = $_.EnableMinorVersions
        ContentApproval = $_.EnableModeration
        DraftVisibility = $_.DraftVersionVisibility
    }
}

$versioningReport | Format-Table

# Check compliance
$nonCompliant = $versioningReport | Where-Object {
    -not $_.VersioningEnabled -or -not $_.ContentApproval
}

if ($nonCompliant) {
    Write-Host "`n=== Libraries Needing Configuration ===" -ForegroundColor Yellow
    $nonCompliant | Format-Table LibraryName, VersioningEnabled, ContentApproval
}

# Export
$versioningReport | Export-Csv -Path "Versioning-Config-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

Monitor Content Staleness

<#
.SYNOPSIS
    Generates staleness report for knowledge source content

.DESCRIPTION
    Identifies documents that haven't been updated within threshold

.PARAMETER SiteUrl
    SharePoint site URL

.PARAMETER DaysThreshold
    Number of days to consider content stale (default: 365)

.EXAMPLE
    .\Get-StaleContent.ps1 -SiteUrl "https://contoso.sharepoint.com/sites/research" -DaysThreshold 180
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl,
    [int]$DaysThreshold = 365
)

Connect-PnPOnline -Url $SiteUrl -Interactive

Write-Host "=== Staleness Report (Threshold: $DaysThreshold days) ===" -ForegroundColor Cyan

# Get all document libraries
$libraries = Get-PnPList | Where-Object { $_.BaseTemplate -eq 101 -and $_.Hidden -eq $false }

$allStaleItems = @()

foreach ($library in $libraries) {
    $items = Get-PnPListItem -List $library.Title -PageSize 500

    $staleItems = $items | Where-Object {
        $_.FileSystemObjectType -eq "File" -and
        ((Get-Date) - [DateTime]$_["Modified"]).TotalDays -gt $DaysThreshold
    } | ForEach-Object {
        [PSCustomObject]@{
            Library = $library.Title
            FileName = $_["FileLeafRef"]
            LastModified = $_["Modified"]
            DaysSinceModified = [int]((Get-Date) - [DateTime]$_["Modified"]).TotalDays
            ModifiedBy = $_["Editor"].LookupValue
        }
    }

    $allStaleItems += $staleItems
}

Write-Host "Total Stale Items: $($allStaleItems.Count)" -ForegroundColor $(if ($allStaleItems.Count -gt 0) { "Yellow" } else { "Green" })

if ($allStaleItems.Count -gt 0) {
    $allStaleItems | Sort-Object DaysSinceModified -Descending | Format-Table Library, FileName, DaysSinceModified, ModifiedBy
    $allStaleItems | Export-Csv -Path "Stale-Content-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
}

Validation Script

<#
.SYNOPSIS
    Validates Control 2.16 - RAG Source Integrity

.DESCRIPTION
    Checks knowledge source configuration and compliance

.EXAMPLE
    .\Validate-Control-2.16.ps1 -SiteUrl "https://contoso.sharepoint.com/sites/research"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl
)

Write-Host "=== Control 2.16 Validation ===" -ForegroundColor Cyan

Connect-PnPOnline -Url $SiteUrl -Interactive

# Check 1: Versioning enabled
Write-Host "`n[Check 1] Document Versioning" -ForegroundColor Cyan
$libraries = Get-PnPList | Where-Object { $_.BaseTemplate -eq 101 -and $_.Hidden -eq $false }
$versioningEnabled = $libraries | Where-Object { $_.EnableVersioning }
Write-Host "Libraries with versioning: $($versioningEnabled.Count) / $($libraries.Count)"

# Check 2: Content approval enabled
Write-Host "`n[Check 2] Content Approval" -ForegroundColor Cyan
$approvalEnabled = $libraries | Where-Object { $_.EnableModeration }
Write-Host "Libraries with content approval: $($approvalEnabled.Count) / $($libraries.Count)"

# Check 3: Staleness
Write-Host "`n[Check 3] Content Staleness (>365 days)" -ForegroundColor Cyan
# Would run staleness check here

Write-Host "`n=== Validation Complete ===" -ForegroundColor Cyan

Complete Configuration Script

<#
.SYNOPSIS
    Complete RAG source integrity validation for Control 2.16

.DESCRIPTION
    Executes end-to-end RAG source validation including:
    - Document library audit
    - Versioning configuration check
    - Staleness analysis
    - Compliance report generation

.PARAMETER SiteUrl
    SharePoint site URL containing knowledge sources

.PARAMETER DaysThreshold
    Number of days to consider content stale

.PARAMETER OutputPath
    Path for output reports

.EXAMPLE
    .\Configure-Control-2.16.ps1 -SiteUrl "https://contoso.sharepoint.com/sites/research" -OutputPath ".\RAGIntegrity"

.NOTES
    Last Updated: January 2026
    Related Control: Control 2.16 - RAG Source Integrity Validation
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl,
    [int]$DaysThreshold = 365,
    [string]$OutputPath = ".\RAGIntegrity-Report"
)

try {
    Write-Host "=== Control 2.16: RAG Source Integrity Configuration ===" -ForegroundColor Cyan

    # Connect to SharePoint
    Connect-PnPOnline -Url $SiteUrl -Interactive

    # Ensure output directory exists
    New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null

    # Get all document libraries
    Write-Host "`n[Step 1] Auditing document libraries..." -ForegroundColor Cyan
    $libraries = Get-PnPList | Where-Object { $_.BaseTemplate -eq 101 -and $_.Hidden -eq $false }
    Write-Host "[INFO] Found $($libraries.Count) document libraries" -ForegroundColor Cyan

    # Check versioning configuration
    $versioningReport = $libraries | ForEach-Object {
        [PSCustomObject]@{
            LibraryName = $_.Title
            VersioningEnabled = $_.EnableVersioning
            MajorVersions = $_.MajorVersionLimit
            MinorVersionsEnabled = $_.EnableMinorVersions
            ContentApproval = $_.EnableModeration
            ItemCount = $_.ItemCount
        }
    }
    $versioningReport | Export-Csv -Path "$OutputPath\VersioningConfig.csv" -NoTypeInformation

    # Check compliance
    $nonCompliant = $versioningReport | Where-Object { -not $_.VersioningEnabled -or -not $_.ContentApproval }
    if ($nonCompliant.Count -gt 0) {
        Write-Host "[WARN] Libraries without versioning or content approval: $($nonCompliant.Count)" -ForegroundColor Yellow
        $nonCompliant | Export-Csv -Path "$OutputPath\NonCompliantLibraries.csv" -NoTypeInformation
    } else {
        Write-Host "[PASS] All libraries have versioning and content approval enabled" -ForegroundColor Green
    }

    # Analyze staleness
    Write-Host "`n[Step 2] Analyzing content staleness (threshold: $DaysThreshold days)..." -ForegroundColor Cyan
    $allStaleItems = @()

    foreach ($library in $libraries) {
        $items = Get-PnPListItem -List $library.Title -PageSize 500 -ErrorAction SilentlyContinue

        $staleItems = $items | Where-Object {
            $_.FileSystemObjectType -eq "File" -and
            ((Get-Date) - [DateTime]$_["Modified"]).TotalDays -gt $DaysThreshold
        } | ForEach-Object {
            [PSCustomObject]@{
                Library = $library.Title
                FileName = $_["FileLeafRef"]
                FilePath = $_["FileRef"]
                LastModified = $_["Modified"]
                DaysSinceModified = [int]((Get-Date) - [DateTime]$_["Modified"]).TotalDays
                ModifiedBy = $_["Editor"].LookupValue
            }
        }

        $allStaleItems += $staleItems
    }

    if ($allStaleItems.Count -gt 0) {
        Write-Host "[WARN] Stale content found: $($allStaleItems.Count) items" -ForegroundColor Yellow
        $allStaleItems | Export-Csv -Path "$OutputPath\StaleContent.csv" -NoTypeInformation
    } else {
        Write-Host "[PASS] No stale content found" -ForegroundColor Green
    }

    # Summary
    Write-Host "`n=== Summary ===" -ForegroundColor Cyan
    Write-Host "Site: $SiteUrl"
    Write-Host "Libraries Audited: $($libraries.Count)"
    Write-Host "Non-Compliant Libraries: $($nonCompliant.Count)"
    Write-Host "Stale Items: $($allStaleItems.Count)"
    Write-Host "Report Path: $OutputPath"

    Write-Host "`n[PASS] Control 2.16 configuration completed successfully" -ForegroundColor Green
}
catch {
    Write-Host "[FAIL] Error: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "[INFO] Stack trace: $($_.ScriptStackTrace)" -ForegroundColor Yellow
    exit 1
}
finally {
    # Cleanup connections
    Disconnect-PnPOnline -ErrorAction SilentlyContinue
}

Back to Control 2.16 | Portal Walkthrough | Verification Testing | Troubleshooting