PowerShell Setup: Control 2.22 - Inactivity Timeout Enforcement
Parent Control: 2.22 - Inactivity Timeout Enforcement
Last Updated: February 2026 Module Requirements: Az.Accounts, PowerShell 7.0+ Estimated Time: 30 minutes for setup; 5 minutes per remediation run
Prerequisites
- PowerShell 7.x or later installed
- Az.Accounts module installed (
Install-Module Az.Accounts) - Authenticated session via
Connect-AzAccount(service principal or interactive) - Service principal with Power Platform Admin role or delegated environment admin
- App registration with
https://api.bap.microsoft.com/.defaultscope granted (for service principal auth) - Environment names (EnvironmentName, not display name) identified for remediation
Script: Set-InactivityTimeout.ps1
Script Location
The script is located at scripts/governance/Set-InactivityTimeout.ps1 in the FSI-AgentGov repository. Navigate to the scripts/governance/ directory or adjust paths in the commands below accordingly.
Synopsis
Configures the inactivity timeout duration for a Power Platform environment via the BAP Admin API privacy settings endpoint. Uses a GET-PATCH-GET pattern to read current state, apply changes, and verify. Supports -WhatIf for preview mode, optional Dataverse audit record writing, and evidence packaging with SHA-256 integrity hashing.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
-EnvironmentName |
String | Yes | — | Power Platform Environment Name (canonical GUID, not display name) |
-TimeoutDuration |
Int32 | No | 120 | Inactivity timeout duration in minutes (valid range: 5-120) |
-WarningDuration |
Int32 | No | 5 | Warning notification duration in minutes before timeout (valid range: 1-30; must be less than -TimeoutDuration) |
-DataverseUrl |
String | No | — | Dataverse environment URL for writing remediation audit records (e.g., https://org12345.crm.dynamics.com/) |
-OutputFormat |
String | No | Object | Output format: Table, JSON, or Object |
-OutputPath |
String | No | — | File path to export JSON results |
-IncludeEvidence |
Switch | No | — | Computes SHA-256 integrity hash over results for evidence packaging |
-WhatIf |
Switch | No | — | Preview mode — displays current vs. target configuration without making changes |
-Verbose |
Switch | No | — | Detailed output including API request/response details |
Authentication
The script requires an authenticated Azure session via Connect-AzAccount before execution. It obtains BAP API tokens automatically using Get-AzAccessToken. No -ClientId, -TenantId, or -ClientSecret parameters are needed — authentication is handled by the pre-existing session.
Example Commands
Preview changes (WhatIf mode)
# Authenticate first (one-time per session)
Connect-AzAccount -ServicePrincipal `
-ApplicationId $clientId `
-CertificateThumbprint $thumbprint `
-TenantId $tenantId
# Preview what would change
.\Set-InactivityTimeout.ps1 `
-EnvironmentName "d1234567-abcd-ef01-2345-6789abcdef01" `
-TimeoutDuration 60 `
-WhatIf
Expected output:
What if: Performing the operation "Set inactivity timeout to 60 min with 5 min warning" on target "d1234567-abcd-ef01-2345-6789abcdef01".
Apply remediation to a single environment (Zone 3)
.\Set-InactivityTimeout.ps1 `
-EnvironmentName "d1234567-abcd-ef01-2345-6789abcdef01" `
-TimeoutDuration 60 `
-WarningDuration 10 `
-Verbose
Apply remediation with Dataverse audit record
.\Set-InactivityTimeout.ps1 `
-EnvironmentName "d1234567-abcd-ef01-2345-6789abcdef01" `
-TimeoutDuration 60 `
-DataverseUrl "https://org12345.crm.dynamics.com/" `
-IncludeEvidence `
-OutputFormat JSON `
-OutputPath .\evidence\timeout-remediation.json
Bulk remediation from CSV
# CSV file must include a header row.
# Required columns: EnvironmentName, TimeoutDuration
# Optional column: WarningDuration (defaults to 5 if omitted)
#
# Example CSV (non-compliant-environments.csv):
# EnvironmentName,TimeoutDuration,WarningDuration
# d1234567-abcd-ef01-2345-6789abcdef01,60,10
# e2345678-bcde-f012-3456-789abcdef012,120,15
Import-Csv ".\non-compliant-environments.csv" | ForEach-Object {
$params = @{
EnvironmentName = $_.EnvironmentName
TimeoutDuration = [int]$_.TimeoutDuration
}
if ($_.WarningDuration) {
$params['WarningDuration'] = [int]$_.WarningDuration
}
.\Set-InactivityTimeout.ps1 @params
}
Bulk remediation with WhatIf preview
Import-Csv ".\non-compliant-environments.csv" | ForEach-Object {
$params = @{
EnvironmentName = $_.EnvironmentName
TimeoutDuration = [int]$_.TimeoutDuration
WhatIf = $true
}
if ($_.WarningDuration) {
$params['WarningDuration'] = [int]$_.WarningDuration
}
.\Set-InactivityTimeout.ps1 @params
}
API Reference
GET — Retrieve Current Privacy Settings
GET https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments/{EnvironmentName}/settings/privacy?api-version=2021-04-01
Authorization: Bearer {access_token}
Response (example):
{
"properties": {
"InactivityTimeoutEnabled": true,
"InactivityTimeoutInMinutes": 120,
"InactivityWarningInMinutes": 10
}
}
Session Expiration via BAP Admin API
The BAP Admin API privacy settings endpoint also returns session expiration properties alongside inactivity timeout settings. When querying an environment's privacy settings using the GET endpoint above, the response may include session expiration fields. Organizations can use this endpoint to programmatically verify both inactivity timeout and session expiration configuration in a single API call. Refer to the existing patterns in the GET and PATCH examples above for authentication and request format.
PATCH — Update Privacy Settings
PATCH https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments/{EnvironmentName}/settings/privacy?api-version=2021-04-01
Authorization: Bearer {access_token}
Content-Type: application/json
{
"properties": {
"InactivityTimeoutEnabled": true,
"InactivityTimeoutInMinutes": 60,
"InactivityWarningInMinutes": 5
}
}
Authentication Setup
Service Principal Configuration
- Register an application in Microsoft Entra ID
- Grant the application the Power Platform Admin role, or assign Environment Admin per environment
- Add the API permission scope:
https://api.bap.microsoft.com/.default - Grant admin consent for the API permission
- Create a client secret or upload a certificate for authentication
Authenticating Before Running the Script
The script uses Get-AzAccessToken internally to obtain BAP API tokens. You must authenticate via Connect-AzAccount before running the script:
# Option 1: Service principal with certificate (recommended for automation)
Connect-AzAccount -ServicePrincipal `
-ApplicationId $clientId `
-CertificateThumbprint $thumbprint `
-TenantId $tenantId
# Option 2: Service principal with client secret
$secureSecret = ConvertTo-SecureString $clientSecret -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($clientId, $secureSecret)
Connect-AzAccount -ServicePrincipal -Credential $credential -TenantId $tenantId
# Option 3: Interactive (for manual remediation)
Connect-AzAccount -TenantId $tenantId
Token Lifecycle
The script obtains tokens automatically via Get-AzAccessToken. If your session expires during a long bulk run, re-run Connect-AzAccount and retry.
Obtaining a Token for Diagnostic Commands
For standalone API calls outside the script (e.g., troubleshooting diagnostics):
$tokenResult = Get-AzAccessToken -ResourceUrl "https://api.bap.microsoft.com"
$token = if ($tokenResult.Token -is [securestring]) { $tokenResult.Token | ConvertFrom-SecureString -AsPlainText } else { $tokenResult.Token }
Error Handling
| Error | Cause | Resolution |
|---|---|---|
401 Unauthorized |
Token expired or invalid scope | Re-authenticate; verify https://api.bap.microsoft.com/.default scope |
403 Forbidden |
Insufficient permissions | Verify service principal has Power Platform Admin or Environment Admin role |
404 Not Found |
Invalid EnvironmentName | Use the canonical EnvironmentName (GUID format), not the display name |
429 Too Many Requests |
API rate limiting | Implement retry with exponential backoff; reduce concurrency for bulk runs |
| Other HTTP errors | Various API issues | Check the error message for details; verify API endpoint availability and request format |
Evidence Hash Verification
When -IncludeEvidence is used, the script computes a SHA-256 integrity hash over the result object. The hash is computed on compressed JSON (no whitespace). To verify a previously exported evidence file:
# 1. Read the exported evidence JSON
$evidence = Get-Content .\evidence\timeout-remediation.json -Raw | ConvertFrom-Json
# 2. Capture the recorded hash, then null it out for recomputation
$recordedHash = $evidence.Metadata.IntegrityHash
$evidence.Metadata.IntegrityHash = $null
# 3. Recompute the hash using compressed JSON (must match original format)
$json = $evidence | ConvertTo-Json -Depth 10 -Compress
$hashBytes = [System.Security.Cryptography.SHA256]::Create().ComputeHash(
[System.Text.Encoding]::UTF8.GetBytes($json)
)
$computedHash = [BitConverter]::ToString($hashBytes) -replace '-'
# 4. Compare
if ($computedHash -eq $recordedHash) {
Write-Host "Evidence integrity verified" -ForegroundColor Green
} else {
Write-Warning "Hash mismatch — evidence may have been modified"
}
Compression Required
The hash is computed on compressed JSON (ConvertTo-Json -Compress). Using pretty-printed JSON for verification will produce a different hash. If hash verification fails on an unmodified file, ensure you are using the same PowerShell version that generated the evidence — JSON property ordering may vary between PowerShell versions.
Next Steps
- Portal Walkthrough — Manual PPAC configuration
- Verification & Testing — Validate remediation results
- Troubleshooting — Advanced diagnostics
Updated: February 2026 | Version: v1.3