Skip to content

PowerShell Setup: Control 2.13 - Documentation and Record Keeping

Last Updated: January 2026 Modules Required: PnP.PowerShell, ExchangeOnlineManagement

Prerequisites

Install-Module -Name PnP.PowerShell -Force -Scope CurrentUser
Install-Module -Name ExchangeOnlineManagement -Force -Scope CurrentUser

Automated Scripts

Create Site Structure

<#
.SYNOPSIS
    Creates SharePoint site structure for AI governance documentation

.EXAMPLE
    .\New-AIGovernanceSite.ps1 -AdminUrl "https://tenant-admin.sharepoint.com"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$AdminUrl,
    [string]$SiteUrl = "/sites/AI-Governance"
)

Write-Host "=== Create AI Governance Site ===" -ForegroundColor Cyan

Connect-PnPOnline -Url $AdminUrl -Interactive

# Create site
$site = New-PnPSite -Type TeamSite -Title "AI Governance" -Alias "AI-Governance"

Connect-PnPOnline -Url "$AdminUrl$SiteUrl" -Interactive

# Create libraries
$libraries = @(
    "AgentConfigurations",
    "InteractionLogs",
    "ApprovalRecords",
    "IncidentReports",
    "GovernanceDecisions"
)

foreach ($lib in $libraries) {
    New-PnPList -Title $lib -Template DocumentLibrary
    Write-Host "Created library: $lib" -ForegroundColor Green
}

# Create site columns
New-PnPField -DisplayName "Agent ID" -InternalName "AgentID" -Type Text -Group "AI Governance"
New-PnPField -DisplayName "Document Category" -InternalName "DocCategory" -Type Choice -Choices "Configuration","Log","Approval","Incident","Decision" -Group "AI Governance"
New-PnPField -DisplayName "Regulatory Reference" -InternalName "RegReference" -Type Choice -Choices "FINRA 4511","SEC 17a-4","SOX 404","GLBA" -Group "AI Governance"

Write-Host "Site setup complete" -ForegroundColor Green

Disconnect-PnPOnline

Export Retention Label Status

<#
.SYNOPSIS
    Exports retention label application status

.EXAMPLE
    .\Export-RetentionStatus.ps1
#>

Write-Host "=== Retention Label Status ===" -ForegroundColor Cyan

Connect-IPPSSession

# Get retention labels
$labels = Get-RetentionCompliancePolicy | Where-Object { $_.Name -like "*FSI*" -or $_.Name -like "*Agent*" }

Write-Host "Retention policies found: $($labels.Count)"

foreach ($label in $labels) {
    Write-Host "`nPolicy: $($label.Name)" -ForegroundColor Yellow
    Write-Host "  Mode: $($label.Mode)"
    Write-Host "  Enabled: $($label.Enabled)"
    Write-Host "  Locations: $($label.SharePointLocation -join ', ')"
}

Disconnect-ExchangeOnline -Confirm:$false

Audit Document Completeness

<#
.SYNOPSIS
    Audits AI governance documentation completeness

.EXAMPLE
    .\Audit-DocumentationCompleteness.ps1 -SiteUrl "https://tenant.sharepoint.com/sites/AI-Governance"
#>

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

Write-Host "=== Documentation Completeness Audit ===" -ForegroundColor Cyan

Connect-PnPOnline -Url $SiteUrl -Interactive

$requiredDocs = @(
    @{Library="GovernanceDecisions"; Doc="AI-Governance-Policy"},
    @{Library="GovernanceDecisions"; Doc="WSP-Addendum"},
    @{Library="GovernanceDecisions"; Doc="Examination-Response-Procedure"}
)

foreach ($req in $requiredDocs) {
    $items = Get-PnPListItem -List $req.Library -Query "<View><Query><Where><Contains><FieldRef Name='FileLeafRef'/><Value Type='Text'>$($req.Doc)</Value></Contains></Where></Query></View>"

    if ($items) {
        Write-Host "[PASS] Found: $($req.Doc) in $($req.Library)" -ForegroundColor Green
    } else {
        Write-Host "[FAIL] Missing: $($req.Doc) in $($req.Library)" -ForegroundColor Red
    }
}

Disconnect-PnPOnline

Validation Script

<#
.SYNOPSIS
    Validates Control 2.13 - Documentation and record keeping

.EXAMPLE
    .\Validate-Control-2.13.ps1
#>

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

# Check 1: Site structure
Write-Host "`n[Check 1] SharePoint Site Structure" -ForegroundColor Cyan
Write-Host "[INFO] Verify AI Governance site and libraries exist"

# Check 2: Retention labels
Write-Host "`n[Check 2] Retention Labels" -ForegroundColor Cyan
Connect-IPPSSession
$labels = Get-RetentionCompliancePolicy | Where-Object { $_.Name -like "*Agent*" }
if ($labels) {
    Write-Host "[PASS] Retention policies found: $($labels.Count)" -ForegroundColor Green
} else {
    Write-Host "[WARN] No agent retention policies found" -ForegroundColor Yellow
}
Disconnect-ExchangeOnline -Confirm:$false

# Check 3: SEC 17a-4 compliant storage (manual)
Write-Host "`n[Check 3] SEC 17a-4 Compliant Storage" -ForegroundColor Cyan
Write-Host "[INFO] Verify immutable storage for Zone 3 (SEC 17a-4): WORM or audit-trail alternative per October 2022 amendments"

# Check 4: Examination procedures
Write-Host "`n[Check 4] Examination Procedures" -ForegroundColor Cyan
Write-Host "[INFO] Verify examination response procedure is documented"

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

Complete Configuration Script

<#
.SYNOPSIS
    Complete documentation and record keeping configuration for Control 2.13

.DESCRIPTION
    Executes end-to-end documentation setup including:
    - SharePoint site structure verification/creation
    - Retention policy validation
    - Documentation completeness audit

.PARAMETER AdminUrl
    SharePoint admin URL

.PARAMETER SiteAlias
    Site alias for AI Governance site

.PARAMETER OutputPath
    Path for output reports

.EXAMPLE
    .\Configure-Control-2.13.ps1 -AdminUrl "https://tenant-admin.sharepoint.com" -OutputPath ".\Documentation"

.NOTES
    Last Updated: January 2026
    Related Control: Control 2.13 - Documentation and Record Keeping
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$AdminUrl,
    [string]$SiteAlias = "AI-Governance",
    [string]$OutputPath = ".\Documentation-Report"
)

try {
    Write-Host "=== Control 2.13: Documentation and Record Keeping Configuration ===" -ForegroundColor Cyan

    # Connect to SharePoint Admin
    Connect-PnPOnline -Url $AdminUrl -Interactive

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

    # Check if site exists
    $siteUrl = $AdminUrl -replace "-admin", "" -replace "sharepoint.com", "sharepoint.com/sites/$SiteAlias"
    $site = Get-PnPTenantSite -Url $siteUrl -ErrorAction SilentlyContinue

    if (-not $site) {
        Write-Host "[INFO] Creating AI Governance site..." -ForegroundColor Cyan
        New-PnPSite -Type TeamSite -Title "AI Governance" -Alias $SiteAlias
        Write-Host "[PASS] Site created: $siteUrl" -ForegroundColor Green
    } else {
        Write-Host "[INFO] AI Governance site exists: $siteUrl" -ForegroundColor Cyan
    }

    # Connect to the site
    Connect-PnPOnline -Url $siteUrl -Interactive

    # Define required libraries
    $requiredLibraries = @(
        "AgentConfigurations",
        "InteractionLogs",
        "ApprovalRecords",
        "IncidentReports",
        "GovernanceDecisions"
    )

    # Create or verify libraries
    Write-Host "`n[Step 1] Verifying document libraries..." -ForegroundColor Cyan
    $libraryReport = @()
    foreach ($lib in $requiredLibraries) {
        $existing = Get-PnPList -Identity $lib -ErrorAction SilentlyContinue
        if (-not $existing) {
            New-PnPList -Title $lib -Template DocumentLibrary
            Write-Host "  [CREATED] $lib" -ForegroundColor Green
            $libraryReport += [PSCustomObject]@{Library=$lib; Status="Created"; ItemCount=0}
        } else {
            Write-Host "  [EXISTS] $lib - $($existing.ItemCount) items" -ForegroundColor Yellow
            $libraryReport += [PSCustomObject]@{Library=$lib; Status="Existing"; ItemCount=$existing.ItemCount}
        }
    }

    # Export library report
    $libraryReport | Export-Csv -Path "$OutputPath\LibraryInventory.csv" -NoTypeInformation

    # Check retention policies
    Write-Host "`n[Step 2] Checking retention policies..." -ForegroundColor Cyan
    try {
        Connect-IPPSSession -ErrorAction SilentlyContinue
        $retentionPolicies = Get-RetentionCompliancePolicy | Where-Object { $_.Name -like "*Agent*" -or $_.Name -like "*AI*" }
        if ($retentionPolicies) {
            Write-Host "  [PASS] Found $($retentionPolicies.Count) retention policies" -ForegroundColor Green
            $retentionPolicies | Select-Object Name, Mode, Enabled | Export-Csv -Path "$OutputPath\RetentionPolicies.csv" -NoTypeInformation
        } else {
            Write-Host "  [WARN] No AI-specific retention policies found" -ForegroundColor Yellow
        }
        Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
    } catch {
        Write-Host "  [INFO] Could not check retention policies - verify manually in Purview" -ForegroundColor Yellow
    }

    # Summary
    Write-Host "`n=== Summary ===" -ForegroundColor Cyan
    Write-Host "Site URL: $siteUrl"
    Write-Host "Libraries Configured: $($libraryReport.Count)"
    Write-Host "Report Path: $OutputPath"

    Write-Host "`n[PASS] Control 2.13 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
    Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
}

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