PowerShell Setup: Control 1.22 — Information Barriers for AI Agents
Read the FSI PowerShell baseline first
Before running any command in this playbook, read the PowerShell Authoring Baseline for FSI Implementations. It is the canonical source for module version pinning, sovereign-cloud (GCC / GCC High / DoD) endpoints, mutation safety (-WhatIf / SupportsShouldProcess), Dataverse compatibility, and SHA-256 evidence emission. Snippets below show abbreviated patterns; the baseline is authoritative.
Last Updated: April 2026
Modules Required: ExchangeOnlineManagement (Compliance PowerShell — Connect-IPPSSession), Microsoft.Graph (for HR-of-record attribute reads and segment-coverage reporting), optional PnP.PowerShell v2+ (for SharePoint site-segment validation)
Prerequisites
# Pin module versions in regulated tenants. Substitute CAB-approved versions.
Install-Module -Name ExchangeOnlineManagement -RequiredVersion '<approved-version>' `
-Repository PSGallery -Scope CurrentUser -AllowClobber -AcceptLicense
Install-Module -Name Microsoft.Graph -RequiredVersion '<approved-version>' `
-Repository PSGallery -Scope CurrentUser -AllowClobber -AcceptLicense
# Optional, for SharePoint site-segment validation:
Install-Module -Name PnP.PowerShell -RequiredVersion '<approved-version>' `
-Repository PSGallery -Scope CurrentUser -AllowClobber -AcceptLicense
Compliance PowerShell (
Connect-IPPSSession) is Windows PowerShell 5.1 Desktop edition for some IB cmdlets and PowerShell 7+ for others depending on theExchangeOnlineManagementbuild. Verify the cmdlet's edition requirement before automating.All snippets assume an interactive admin session. For unattended automation, use a certificate-based service principal with the Compliance Administrator role or the Information Barriers Manager role assignment.
Script 1 — Pre-Change Baseline Capture
Always capture state before modifying IB. This output is the rollback reference and the evidence baseline for change control (FINRA 3110, SOX 404).
<#
.SYNOPSIS
Captures Information Barriers baseline state for Control 1.22 evidence.
.DESCRIPTION
Records IB mode, segments, policies, and last application status.
Writes timestamped CSV/JSON outputs and emits SHA-256 hashes for
chain-of-custody (SEC 17a-4 / FINRA 4511 alignment).
.EXAMPLE
.\Get-IBBaseline.ps1 -OutputPath '.\evidence\1.22\baseline'
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$OutputPath
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path $OutputPath)) { New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null }
$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
Connect-IPPSSession -ShowBanner:$false
$mode = Get-InformationBarrierMode
$segments = Get-OrganizationSegment
$policies = Get-InformationBarrierPolicy
$status = Get-InformationBarrierPoliciesApplicationStatus
$mode | ConvertTo-Json -Depth 5 | Out-File "$OutputPath\IB-Mode-$timestamp.json" -Encoding utf8
$segments| Select-Object Name, UserGroupFilter, Type, ExoSegmentId, CreatedBy, WhenCreated, WhenChanged |
Export-Csv "$OutputPath\IB-Segments-$timestamp.csv" -NoTypeInformation -Encoding utf8
$policies| Select-Object Name, AssignedSegment, SegmentsAllowed, SegmentsBlocked, State, ModerationAllowed, WhenChanged |
Export-Csv "$OutputPath\IB-Policies-$timestamp.csv" -NoTypeInformation -Encoding utf8
$status | ConvertTo-Json -Depth 5 | Out-File "$OutputPath\IB-AppStatus-$timestamp.json" -Encoding utf8
# SHA-256 chain-of-custody hashes
Get-ChildItem $OutputPath -Filter "*$timestamp*" | ForEach-Object {
$hash = Get-FileHash -Path $_.FullName -Algorithm SHA256
[PSCustomObject]@{ File = $_.Name; SHA256 = $hash.Hash; CapturedAtUtc = (Get-Date).ToUniversalTime() }
} | Export-Csv "$OutputPath\Evidence-Manifest-$timestamp.csv" -NoTypeInformation -Encoding utf8
Disconnect-ExchangeOnline -Confirm:$false
Write-Host "Baseline captured to $OutputPath" -ForegroundColor Green
Script 2 — Create Organization Segments
<#
.SYNOPSIS
Creates IB organization segments for FSI ethical walls.
.PARAMETER WhatIf
Standard ShouldProcess support — preview without mutation.
.EXAMPLE
.\New-IBSegments.ps1 -WhatIf
.\New-IBSegments.ps1
#>
[CmdletBinding(SupportsShouldProcess)]
param()
$ErrorActionPreference = 'Stop'
Connect-IPPSSession -ShowBanner:$false
$segments = @(
@{ Name = 'IB-Research'; Filter = "Department -eq 'Equity Research'" }
@{ Name = 'IB-Trading'; Filter = "Department -eq 'Sales and Trading'" }
@{ Name = 'IB-IB-Public'; Filter = "Department -eq 'Investment Banking' -and CompanyName -eq 'Capital Markets'" }
@{ Name = 'IB-IB-Private'; Filter = "Department -eq 'Investment Banking' -and CompanyName -eq 'M&A'" }
@{ Name = 'IB-Muni-Underwriting'; Filter = "Department -eq 'Municipal Underwriting'" }
@{ Name = 'IB-Muni-Advisory'; Filter = "Department -eq 'Municipal Advisory'" }
@{ Name = 'IB-Compliance'; Filter = "Department -eq 'Compliance'" }
)
foreach ($s in $segments) {
$existing = Get-OrganizationSegment -Identity $s.Name -ErrorAction SilentlyContinue
if ($existing) {
Write-Host "[EXISTS] $($s.Name)" -ForegroundColor Yellow
continue
}
if ($PSCmdlet.ShouldProcess($s.Name, "New-OrganizationSegment")) {
New-OrganizationSegment -Name $s.Name -UserGroupFilter $s.Filter | Out-Null
Write-Host "[CREATED] $($s.Name)" -ForegroundColor Green
}
}
Disconnect-ExchangeOnline -Confirm:$false
Script 3 — Create IB Policies (Multi-Segment Allow-List Pattern)
Multi-Segment mode policies are allow-lists. The
-SegmentsAllowedarray names every segment the assigned segment may communicate with. Misconfiguration here is the most common cause of unintended barrier failures.
<#
.SYNOPSIS
Creates IB policies in MultiSegment mode for FSI ethical walls.
.NOTES
Verifies Get-InformationBarrierMode returns 'MultiSegment' before creating
allow-list policies. Falls back with an error in other modes.
#>
[CmdletBinding(SupportsShouldProcess)]
param()
$ErrorActionPreference = 'Stop'
Connect-IPPSSession -ShowBanner:$false
$mode = (Get-InformationBarrierMode).Identity
if ($mode -ne 'MultiSegment') {
throw "IB mode is '$mode'. This script targets MultiSegment. Migrate first or use the SingleSegment block-list variant."
}
$policies = @(
@{ Name = 'Policy-IB-Research'; Assigned = 'IB-Research'; Allowed = @('IB-Research','IB-Compliance') }
@{ Name = 'Policy-IB-Trading'; Assigned = 'IB-Trading'; Allowed = @('IB-Trading','IB-Compliance') }
@{ Name = 'Policy-IB-IB-Public'; Assigned = 'IB-IB-Public'; Allowed = @('IB-IB-Public','IB-Compliance') }
@{ Name = 'Policy-IB-IB-Private'; Assigned = 'IB-IB-Private'; Allowed = @('IB-IB-Private','IB-Compliance') }
@{ Name = 'Policy-IB-Muni-Underwriting'; Assigned = 'IB-Muni-Underwriting'; Allowed = @('IB-Muni-Underwriting','IB-Compliance') }
@{ Name = 'Policy-IB-Muni-Advisory'; Assigned = 'IB-Muni-Advisory'; Allowed = @('IB-Muni-Advisory','IB-Compliance') }
@{ Name = 'Policy-IB-Compliance'; Assigned = 'IB-Compliance'; Allowed = @('IB-Research','IB-Trading','IB-IB-Public','IB-IB-Private','IB-Muni-Underwriting','IB-Muni-Advisory','IB-Compliance') }
)
foreach ($p in $policies) {
$existing = Get-InformationBarrierPolicy -Identity $p.Name -ErrorAction SilentlyContinue
if ($existing) {
Write-Host "[EXISTS] $($p.Name) — review before re-creating" -ForegroundColor Yellow
continue
}
if ($PSCmdlet.ShouldProcess($p.Name, "New-InformationBarrierPolicy (MultiSegment allow-list)")) {
New-InformationBarrierPolicy -Name $p.Name `
-AssignedSegment $p.Assigned `
-SegmentsAllowed $p.Allowed `
-State Active | Out-Null
Write-Host "[CREATED] $($p.Name)" -ForegroundColor Green
}
}
Write-Host "`nReview policies before applying." -ForegroundColor Cyan
Get-InformationBarrierPolicy | Select-Object Name, AssignedSegment, SegmentsAllowed, State | Format-Table -AutoSize
Disconnect-ExchangeOnline -Confirm:$false
Script 4 — Apply IB Policies and Track Status
<#
.SYNOPSIS
Applies IB policies and waits up to N hours for completion.
.PARAMETER MaxWaitHours
Maximum hours to poll Get-InformationBarrierPoliciesApplicationStatus.
Default 6; production tenants frequently take 24–72 hours.
.EXAMPLE
.\Start-IBApplication.ps1 -MaxWaitHours 24
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[int]$MaxWaitHours = 6,
[int]$PollSeconds = 300
)
$ErrorActionPreference = 'Stop'
Connect-IPPSSession -ShowBanner:$false
if ($PSCmdlet.ShouldProcess('Tenant', 'Start-InformationBarrierPoliciesApplication')) {
Start-InformationBarrierPoliciesApplication
Write-Host "Application started at $(Get-Date -Format 'u')" -ForegroundColor Cyan
}
$deadline = (Get-Date).AddHours($MaxWaitHours)
do {
Start-Sleep -Seconds $PollSeconds
$status = Get-InformationBarrierPoliciesApplicationStatus | Sort-Object StartTime -Descending | Select-Object -First 1
Write-Host "[$(Get-Date -Format 'u')] Status: $($status.Status) Identity: $($status.Identity)" -ForegroundColor DarkCyan
} while ($status.Status -in @('NotStarted','InProgress') -and (Get-Date) -lt $deadline)
if ($status.Status -ne 'Completed') {
Write-Warning "Did not reach Completed within $MaxWaitHours hours. Current status: $($status.Status)"
exit 2
}
Write-Host "[PASS] Application Completed at $($status.EndTime)" -ForegroundColor Green
Disconnect-ExchangeOnline -Confirm:$false
Script 5 — Segment Coverage Report (Identify Segment-less Users)
Users without a segment bypass IB enforcement and are the highest-impact residual risk. This report identifies them so they can be remediated before policy application.
<#
.SYNOPSIS
Identifies users not covered by any IB segment.
.DESCRIPTION
Cross-references all enabled member users in Entra ID against current
IB segment filters and emits a CSV of segment-less users for remediation.
.EXAMPLE
.\Export-IBSegmentCoverage.ps1 -OutputPath '.\evidence\1.22\coverage'
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$OutputPath
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path $OutputPath)) { New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null }
$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
Connect-MgGraph -Scopes 'User.Read.All' -NoWelcome | Out-Null
$users = Get-MgUser -All -Filter "accountEnabled eq true and userType eq 'Member'" `
-Property Id,UserPrincipalName,DisplayName,Department,CompanyName,JobTitle
# Heuristic: an HR-of-record-driven segmentation requires Department to be populated.
$uncovered = $users | Where-Object { [string]::IsNullOrWhiteSpace($_.Department) }
$uncovered | Select-Object UserPrincipalName, DisplayName, Department, CompanyName, JobTitle |
Export-Csv "$OutputPath\IB-UncoveredUsers-$timestamp.csv" -NoTypeInformation -Encoding utf8
$summary = [PSCustomObject]@{
TotalEnabledMembers = $users.Count
Uncovered = $uncovered.Count
CoveragePercent = if ($users.Count -gt 0) { [math]::Round((($users.Count - $uncovered.Count) / $users.Count) * 100, 2) } else { 0 }
GeneratedAtUtc = (Get-Date).ToUniversalTime()
}
$summary | ConvertTo-Json | Out-File "$OutputPath\IB-CoverageSummary-$timestamp.json" -Encoding utf8
Write-Host "Coverage: $($summary.CoveragePercent)% — $($summary.Uncovered) uncovered users" -ForegroundColor Cyan
Disconnect-MgGraph | Out-Null
Script 6 — Validate Configuration End-to-End
<#
.SYNOPSIS
Validates Control 1.22 configuration is in the intended state.
.DESCRIPTION
Returns 0 on PASS; non-zero on FAIL with reason logged.
Designed for unattended scheduled runs feeding compliance dashboards.
#>
[CmdletBinding()]
param(
[string]$ExpectedMode = 'MultiSegment',
[string[]]$RequiredSegments = @('IB-Research','IB-Trading','IB-IB-Public','IB-IB-Private','IB-Muni-Underwriting','IB-Muni-Advisory','IB-Compliance'),
[decimal]$MinimumCoveragePercent = 99.5
)
$ErrorActionPreference = 'Stop'
$failures = @()
Connect-IPPSSession -ShowBanner:$false
$mode = (Get-InformationBarrierMode).Identity
if ($mode -ne $ExpectedMode) { $failures += "IB mode is '$mode'; expected '$ExpectedMode'." }
$segments = (Get-OrganizationSegment).Name
$missing = $RequiredSegments | Where-Object { $_ -notin $segments }
if ($missing) { $failures += "Missing segments: $($missing -join ', ')." }
$active = Get-InformationBarrierPolicy | Where-Object State -eq 'Active'
if ($active.Count -lt $RequiredSegments.Count) {
$failures += "Active policy count ($($active.Count)) less than required segment count ($($RequiredSegments.Count))."
}
$last = Get-InformationBarrierPoliciesApplicationStatus | Sort-Object StartTime -Descending | Select-Object -First 1
if ($last.Status -ne 'Completed') { $failures += "Last application status: $($last.Status)." }
Disconnect-ExchangeOnline -Confirm:$false
if ($failures) {
$failures | ForEach-Object { Write-Host "[FAIL] $_" -ForegroundColor Red }
exit 1
}
Write-Host "[PASS] Control 1.22 validation succeeded" -ForegroundColor Green
exit 0
Sovereign-Cloud Connection Notes
For GCC High and DoD tenants, Connect-IPPSSession requires explicit endpoints:
# GCC High
Connect-IPPSSession `
-ConnectionUri 'https://ps.compliance.protection.office365.us/powershell-liveid/' `
-AzureADAuthorizationEndpointUri 'https://login.microsoftonline.us/common'
# DoD
Connect-IPPSSession `
-ConnectionUri 'https://l5.ps.compliance.protection.office365.us/powershell-liveid/' `
-AzureADAuthorizationEndpointUri 'https://login.microsoftonline.us/common'
Refer to the PowerShell Authoring Baseline §6 for current sovereign-cloud endpoint tables.
Rollback
If a misapplied policy must be rolled back:
Set-InformationBarrierPolicy -Identity <name> -State Inactiveto deactivate without deletion (preserves audit history).Start-InformationBarrierPoliciesApplicationto push the deactivation.- Confirm
Get-InformationBarrierPoliciesApplicationStatusreachesCompleted. - Only delete a policy after Compliance sign-off; deletion is permanent.
Back to Control 1.22 | Portal Walkthrough | Verification Testing | Troubleshooting