Skip to content

PowerShell Setup: Control 2.14 - Training and Awareness Program

Last Updated: January 2026 Modules Required: Microsoft.Graph, ExchangeOnlineManagement

Prerequisites

# Install required modules
Install-Module -Name Microsoft.Graph -Force -Scope CurrentUser
Install-Module -Name ExchangeOnlineManagement -Force -Scope CurrentUser

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "LearningContent.Read.All"

Training Compliance Report Scripts

Get Users by Role for Training Assignment

<#
.SYNOPSIS
    Identifies users who need AI governance training based on role assignments

.DESCRIPTION
    Queries Microsoft Entra ID for users with specific roles that require training

.EXAMPLE
    .\Get-TrainingRequiredUsers.ps1
#>

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "RoleManagement.Read.All"

# Define roles that require AI governance training
$trainingRequiredRoles = @(
    "Power Platform Administrator",
    "Compliance Administrator",
    "SharePoint Administrator",
    "Exchange Administrator"
)

# Get all role assignments
$roleAssignments = Get-MgDirectoryRole | ForEach-Object {
    $role = $_
    $members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id

    foreach ($member in $members) {
        [PSCustomObject]@{
            UserId = $member.Id
            RoleName = $role.DisplayName
            RoleId = $role.Id
        }
    }
}

# Filter to training-required roles
$usersNeedingTraining = $roleAssignments | Where-Object {
    $trainingRequiredRoles -contains $_.RoleName
}

# Get user details
$report = $usersNeedingTraining | ForEach-Object {
    $user = Get-MgUser -UserId $_.UserId
    [PSCustomObject]@{
        DisplayName = $user.DisplayName
        Email = $user.Mail
        Role = $_.RoleName
        Department = $user.Department
        TrainingRequired = "AI Governance Framework"
    }
}

$report | Format-Table
$report | Export-Csv -Path "Training-Required-Users-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

Track Training Completion Status

<#
.SYNOPSIS
    Tracks training completion status from a CSV roster

.DESCRIPTION
    Compares required training list against completion records

.PARAMETER RequiredUsersFile
    CSV file with users who need training

.PARAMETER CompletionRecordsFile
    CSV file with training completion records from LMS

.EXAMPLE
    .\Get-TrainingComplianceStatus.ps1 -RequiredUsersFile "required.csv" -CompletionRecordsFile "completed.csv"
#>

param(
    [string]$RequiredUsersFile = "Training-Required-Users.csv",
    [string]$CompletionRecordsFile = "Training-Completions.csv"
)

# Load data
$requiredUsers = Import-Csv $RequiredUsersFile
$completions = Import-Csv $CompletionRecordsFile

# Build completion lookup
$completionLookup = @{}
foreach ($completion in $completions) {
    $completionLookup[$completion.Email] = $completion.CompletionDate
}

# Generate compliance report
$complianceReport = $requiredUsers | ForEach-Object {
    $completed = $completionLookup.ContainsKey($_.Email)
    $completionDate = if ($completed) { $completionLookup[$_.Email] } else { $null }

    [PSCustomObject]@{
        DisplayName = $_.DisplayName
        Email = $_.Email
        Role = $_.Role
        TrainingCompleted = $completed
        CompletionDate = $completionDate
        Status = if ($completed) { "Compliant" } else { "Non-Compliant" }
    }
}

# Summary statistics
$total = $complianceReport.Count
$compliant = ($complianceReport | Where-Object { $_.Status -eq "Compliant" }).Count
$nonCompliant = $total - $compliant
$complianceRate = [math]::Round(($compliant / $total) * 100, 1)

Write-Host "`n=== Training Compliance Summary ===" -ForegroundColor Cyan
Write-Host "Total Users: $total"
Write-Host "Compliant: $compliant" -ForegroundColor Green
Write-Host "Non-Compliant: $nonCompliant" -ForegroundColor $(if ($nonCompliant -gt 0) { "Yellow" } else { "Green" })
Write-Host "Compliance Rate: $complianceRate%"

# Export detailed report
$complianceReport | Export-Csv -Path "Training-Compliance-Report-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Write-Host "`nReport exported to Training-Compliance-Report-$(Get-Date -Format 'yyyyMMdd').csv"

# Return non-compliant users for follow-up
$nonCompliantUsers = $complianceReport | Where-Object { $_.Status -eq "Non-Compliant" }
if ($nonCompliantUsers) {
    Write-Host "`n=== Non-Compliant Users ===" -ForegroundColor Yellow
    $nonCompliantUsers | Format-Table DisplayName, Email, Role
}

Send Training Reminder Emails

<#
.SYNOPSIS
    Sends training reminder emails to non-compliant users

.DESCRIPTION
    Uses Exchange Online to send reminder emails

.PARAMETER NonCompliantFile
    CSV file with non-compliant users

.EXAMPLE
    .\Send-TrainingReminders.ps1 -NonCompliantFile "non-compliant.csv"
#>

param(
    [string]$NonCompliantFile = "Training-Non-Compliant.csv",
    [string]$SenderEmail = "aigovernance@company.com",  # Replace with your organization's sender email
    [string]$TrainingUrl = "https://learning.company.com/ai-governance"  # Replace with your organization's training URL
)

# Connect to Exchange Online
Connect-ExchangeOnline

# Load non-compliant users
$nonCompliant = Import-Csv $NonCompliantFile

foreach ($user in $nonCompliant) {
    $emailParams = @{
        From = $SenderEmail
        To = $user.Email
        Subject = "Action Required: AI Governance Training"
        Body = @"
Dear $($user.DisplayName),

Our records indicate that you have not yet completed the required AI Governance Training for your role as $($user.Role).

Please complete this training within 14 days by visiting:
$TrainingUrl

This training is required for compliance with our AI governance framework and regulatory obligations.

If you have questions, please contact the AI Governance team.

Best regards,
AI Governance Team
"@
        BodyAsHtml = $false
    }

    # Note: Actual sending would use Send-MgUserMail (Microsoft Graph) or other mail API
    Write-Host "Would send reminder to: $($user.Email)" -ForegroundColor Yellow
}

Write-Host "`nReminder process completed for $($nonCompliant.Count) users"

Validation Script

<#
.SYNOPSIS
    Validates Control 2.14 - Training and Awareness Program

.DESCRIPTION
    Checks training program configuration and compliance rates

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

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

# Check 1: Verify training content exists
Write-Host "`n[Check 1] Training Content Configuration" -ForegroundColor Cyan
# This would integrate with your LMS API
Write-Host "[INFO] Verify training modules exist in LMS" -ForegroundColor Yellow
Write-Host "[INFO] Required modules: AI Governance Framework, Data Handling, Security Awareness"

# Check 2: Verify role-based assignments
Write-Host "`n[Check 2] Role-Based Training Assignments" -ForegroundColor Cyan
# Run the role identification script
Write-Host "[INFO] Run Get-TrainingRequiredUsers.ps1 to identify users needing training"

# Check 3: Compliance rate check
Write-Host "`n[Check 3] Training Compliance Rate" -ForegroundColor Cyan
Write-Host "[INFO] Target: 100% for Zone 3, 95% for Zone 2, 80% for Zone 1"

# Check 4: Evidence retention
Write-Host "`n[Check 4] Evidence Retention" -ForegroundColor Cyan
Write-Host "[INFO] Verify training records are retained per policy (7 years for regulated)"

Write-Host "`n=== Validation Complete ===" -ForegroundColor Cyan
Write-Host "Document findings and remediate any gaps identified"

Complete Configuration Script

<#
.SYNOPSIS
    Complete training and awareness configuration for Control 2.14

.DESCRIPTION
    Executes end-to-end training setup including:
    - User identification by role
    - Training compliance check
    - Non-compliant user reporting

.PARAMETER RequiredUsersFile
    CSV file with users requiring training

.PARAMETER CompletionRecordsFile
    CSV file with training completion records from LMS

.PARAMETER OutputPath
    Path for output reports

.EXAMPLE
    .\Configure-Control-2.14.ps1 -OutputPath ".\Training"

.NOTES
    Last Updated: January 2026
    Related Control: Control 2.14 - Training and Awareness Program
#>

param(
    [string]$RequiredUsersFile,
    [string]$CompletionRecordsFile,
    [string]$OutputPath = ".\Training-Report"
)

try {
    Write-Host "=== Control 2.14: Training and Awareness Configuration ===" -ForegroundColor Cyan

    # Connect to Microsoft Graph
    Connect-MgGraph -Scopes "User.Read.All", "RoleManagement.Read.All"

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

    # Define roles that require AI governance training
    $trainingRequiredRoles = @(
        "Power Platform Administrator",
        "Compliance Administrator",
        "SharePoint Administrator",
        "Exchange Administrator"
    )

    Write-Host "`n[Step 1] Identifying users requiring training..." -ForegroundColor Cyan

    # Get all role assignments
    $roleAssignments = Get-MgDirectoryRole | ForEach-Object {
        $role = $_
        $members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -ErrorAction SilentlyContinue

        foreach ($member in $members) {
            [PSCustomObject]@{
                UserId = $member.Id
                RoleName = $role.DisplayName
                RoleId = $role.Id
            }
        }
    }

    # Filter to training-required roles
    $usersNeedingTraining = $roleAssignments | Where-Object {
        $trainingRequiredRoles -contains $_.RoleName
    }

    # Get user details
    $requiredUsers = $usersNeedingTraining | ForEach-Object {
        $user = Get-MgUser -UserId $_.UserId -ErrorAction SilentlyContinue
        if ($user) {
            [PSCustomObject]@{
                DisplayName = $user.DisplayName
                Email = $user.Mail
                Role = $_.RoleName
                Department = $user.Department
                TrainingRequired = "AI Governance Framework"
            }
        }
    } | Sort-Object Email -Unique

    Write-Host "  [INFO] Found $($requiredUsers.Count) users requiring training" -ForegroundColor Cyan
    $requiredUsers | Export-Csv -Path "$OutputPath\Training-Required-Users.csv" -NoTypeInformation

    # Check completions if file provided
    if ($CompletionRecordsFile -and (Test-Path $CompletionRecordsFile)) {
        Write-Host "`n[Step 2] Checking training completions..." -ForegroundColor Cyan
        $completions = Import-Csv $CompletionRecordsFile

        $completionLookup = @{}
        foreach ($completion in $completions) {
            $completionLookup[$completion.Email] = $completion.CompletionDate
        }

        $complianceReport = $requiredUsers | ForEach-Object {
            $completed = $completionLookup.ContainsKey($_.Email)
            [PSCustomObject]@{
                DisplayName = $_.DisplayName
                Email = $_.Email
                Role = $_.Role
                TrainingCompleted = $completed
                CompletionDate = if ($completed) { $completionLookup[$_.Email] } else { $null }
                Status = if ($completed) { "Compliant" } else { "Non-Compliant" }
            }
        }

        # Calculate statistics
        $total = $complianceReport.Count
        $compliant = ($complianceReport | Where-Object { $_.Status -eq "Compliant" }).Count
        $nonCompliant = $total - $compliant
        $complianceRate = if ($total -gt 0) { [math]::Round(($compliant / $total) * 100, 1) } else { 0 }

        Write-Host "`n=== Training Compliance Summary ===" -ForegroundColor Cyan
        Write-Host "Total Users: $total"
        Write-Host "Compliant: $compliant" -ForegroundColor Green
        Write-Host "Non-Compliant: $nonCompliant" -ForegroundColor $(if ($nonCompliant -gt 0) { "Yellow" } else { "Green" })
        Write-Host "Compliance Rate: $complianceRate%"

        $complianceReport | Export-Csv -Path "$OutputPath\Training-Compliance-Report.csv" -NoTypeInformation

        # Export non-compliant users
        $nonCompliantUsers = $complianceReport | Where-Object { $_.Status -eq "Non-Compliant" }
        if ($nonCompliantUsers) {
            $nonCompliantUsers | Export-Csv -Path "$OutputPath\Training-Non-Compliant.csv" -NoTypeInformation
        }
    } else {
        Write-Host "`n[INFO] No completion records provided - export required users list for LMS comparison" -ForegroundColor Yellow
    }

    Write-Host "`n[PASS] Control 2.14 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-MgGraph -ErrorAction SilentlyContinue
}

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