Skip to content

PowerShell Setup: Control 2.12 - Supervision and Oversight

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

Prerequisites

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

Automated Scripts

Export Supervision Log

<#
.SYNOPSIS
    Exports supervision review log for compliance audit

.EXAMPLE
    .\Export-SupervisionLog.ps1 -SiteUrl "https://tenant.sharepoint.com/sites/AIGovernance"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl,
    [string]$ListName = "AgentSupervisionLog",
    [string]$OutputPath = ".\SupervisionLog.csv"
)

Write-Host "=== Export Supervision Log ===" -ForegroundColor Cyan

Connect-PnPOnline -Url $SiteUrl -Interactive

$items = Get-PnPListItem -List $ListName -PageSize 1000

$export = @()
foreach ($item in $items) {
    $export += [PSCustomObject]@{
        AgentName = $item["AgentName"]
        ConversationId = $item["ConversationId"]
        ReviewDate = $item["ReviewDate"]
        Reviewer = $item["Reviewer"]
        Decision = $item["Decision"]
        Comments = $item["Comments"]
        RiskLevel = $item["RiskLevel"]
    }
}

$export | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Export saved to: $OutputPath" -ForegroundColor Green
Write-Host "Total records: $($export.Count)"

Disconnect-PnPOnline

Generate Supervision Report

<#
.SYNOPSIS
    Generates supervision statistics report

.EXAMPLE
    .\New-SupervisionReport.ps1 -LogPath ".\SupervisionLog.csv"
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$LogPath,
    [string]$OutputPath = ".\SupervisionReport.xlsx"
)

Write-Host "=== Generate Supervision Report ===" -ForegroundColor Cyan

$log = Import-Csv $LogPath

# Summary statistics
$total = $log.Count
$approved = ($log | Where-Object { $_.Decision -eq "Approved" }).Count
$rejected = ($log | Where-Object { $_.Decision -eq "Rejected" }).Count
$pending = ($log | Where-Object { $_.Decision -eq "Pending" }).Count

$summary = [PSCustomObject]@{
    TotalReviews = $total
    Approved = $approved
    Rejected = $rejected
    Pending = $pending
    ApprovalRate = if ($total -gt 0) { [math]::Round($approved / $total * 100, 1) } else { 0 }
}

# By risk level
$byRisk = $log | Group-Object RiskLevel | ForEach-Object {
    [PSCustomObject]@{
        RiskLevel = $_.Name
        Count = $_.Count
        Percentage = if ($total -gt 0) { [math]::Round($_.Count / $total * 100, 1) } else { 0 }
    }
}

# Export to Excel
$summary | Export-Excel -Path $OutputPath -WorksheetName "Summary" -AutoSize
$byRisk | Export-Excel -Path $OutputPath -WorksheetName "ByRiskLevel" -AutoSize -Append

Write-Host "Report saved to: $OutputPath" -ForegroundColor Green

Validation Script

<#
.SYNOPSIS
    Validates Control 2.12 - Supervision configuration

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

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

# Check 1: WSP documentation
Write-Host "`n[Check 1] WSP Addendum" -ForegroundColor Cyan
Write-Host "[INFO] Verify WSP addendum for AI agents is documented and approved"

# Check 2: HITL configuration
Write-Host "`n[Check 2] HITL Configuration" -ForegroundColor Cyan
Write-Host "[INFO] Verify HITL is enabled in Copilot Studio for Zone 3 agents"

# Check 3: Supervision log
Write-Host "`n[Check 3] Supervision Log" -ForegroundColor Cyan
Write-Host "[INFO] Verify supervision reviews are being logged"

# Check 4: Designated principals
Write-Host "`n[Check 4] Designated Principals" -ForegroundColor Cyan
Write-Host "[INFO] Verify principals with appropriate registrations are assigned"

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

Complete Configuration Script

<#
.SYNOPSIS
    Complete supervision and oversight configuration for Control 2.12

.DESCRIPTION
    Executes end-to-end supervision setup including:
    - Supervision log extraction
    - Statistics generation
    - Compliance report export

.PARAMETER SiteUrl
    SharePoint site URL for supervision log

.PARAMETER ListName
    SharePoint list name for supervision log

.PARAMETER OutputPath
    Path for output reports

.EXAMPLE
    .\Configure-Control-2.12.ps1 -SiteUrl "https://tenant.sharepoint.com/sites/AIGovernance" -OutputPath ".\Supervision"

.NOTES
    Last Updated: January 2026
    Related Control: Control 2.12 - Supervision and Oversight (FINRA Rule 3110)
#>

param(
    [Parameter(Mandatory=$true)]
    [string]$SiteUrl,
    [string]$ListName = "AgentSupervisionLog",
    [string]$OutputPath = ".\Supervision-Report"
)

try {
    Write-Host "=== Control 2.12: Supervision and Oversight Configuration ===" -ForegroundColor Cyan

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

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

    # Check if list exists
    $list = Get-PnPList -Identity $ListName -ErrorAction SilentlyContinue
    if (-not $list) {
        Write-Host "[WARN] Supervision log list '$ListName' not found" -ForegroundColor Yellow
        Write-Host "[INFO] Creating supervision log list..." -ForegroundColor Cyan

        # Create the list
        New-PnPList -Title $ListName -Template GenericList
        Add-PnPField -List $ListName -DisplayName "Agent Name" -InternalName "AgentName" -Type Text
        Add-PnPField -List $ListName -DisplayName "Conversation ID" -InternalName "ConversationId" -Type Text
        Add-PnPField -List $ListName -DisplayName "Review Date" -InternalName "ReviewDate" -Type DateTime
        Add-PnPField -List $ListName -DisplayName "Reviewer" -InternalName "Reviewer" -Type User
        Add-PnPField -List $ListName -DisplayName "Decision" -InternalName "Decision" -Type Choice -Choices @("Approved", "Rejected", "Pending", "Escalated")
        Add-PnPField -List $ListName -DisplayName "Comments" -InternalName "Comments" -Type Note
        Add-PnPField -List $ListName -DisplayName "Risk Level" -InternalName "RiskLevel" -Type Choice -Choices @("Low", "Medium", "High")

        Write-Host "[PASS] Supervision log list created" -ForegroundColor Green
    } else {
        Write-Host "[INFO] Supervision log list found" -ForegroundColor Cyan
    }

    # Get supervision records
    $items = Get-PnPListItem -List $ListName -PageSize 1000 -ErrorAction SilentlyContinue

    if ($items -and $items.Count -gt 0) {
        # Build export
        $export = $items | ForEach-Object {
            [PSCustomObject]@{
                AgentName = $_["AgentName"]
                ConversationId = $_["ConversationId"]
                ReviewDate = $_["ReviewDate"]
                Reviewer = $_["Reviewer"].LookupValue
                Decision = $_["Decision"]
                Comments = $_["Comments"]
                RiskLevel = $_["RiskLevel"]
            }
        }

        # Export to CSV
        $export | Export-Csv -Path "$OutputPath\SupervisionLog-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
        Write-Host "[INFO] Exported $($export.Count) supervision records" -ForegroundColor Cyan

        # Calculate statistics
        $total = $export.Count
        $approved = ($export | Where-Object { $_.Decision -eq "Approved" }).Count
        $rejected = ($export | Where-Object { $_.Decision -eq "Rejected" }).Count
        $pending = ($export | Where-Object { $_.Decision -eq "Pending" }).Count

        Write-Host "`n=== Supervision Statistics ===" -ForegroundColor Cyan
        Write-Host "Total Reviews: $total"
        Write-Host "Approved: $approved"
        Write-Host "Rejected: $rejected"
        Write-Host "Pending: $pending"
        if ($total -gt 0) {
            Write-Host "Approval Rate: $([math]::Round($approved / $total * 100, 1))%"
        }
    } else {
        Write-Host "[INFO] No supervision records found" -ForegroundColor Yellow
    }

    Write-Host "`n[PASS] Control 2.12 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.12 | Portal Walkthrough | Verification Testing | Troubleshooting