scripts/local/power-platform.ps1
|
<# Raidiness — Power Platform & Copilot Studio (local, read-only) Why local: the inventory API only becomes reachable app-only after a service principal has been registered with New-PowerAppManagementApp. That is a write action in the customer's tenant, and Raidiness never performs it itself (CLAUDE.md #1). If you prefer not to, run this script once yourself: it reads the same data with the rights the administrator already has. Role: Power Platform Administrator (or Global Reader with AI Reader). Writes: nothing. Only Get-* cmdlets and a JSON file on your own disk. Output: JSON you upload in Raidiness under the "Power Platform" module. Usage: .\power-platform.ps1 -TenantId <tenant> -RunId <run> -OutputPath .\pp.json .\power-platform.ps1 -TenantId <tenant> -RunId <run> -HashUpns #> # psrunner-lint allow: Add-PowerAppsAccount — interactive sign-in of the administrator, not a write action [CmdletBinding()] param( [Parameter(Mandatory = $true)][string] $TenantId, [Parameter(Mandatory = $true)][string] $RunId, [string] $OutputPath = ".\raidiness-power-platform.json", # Replaces e-mail addresses with a hash: the report counts owners, it does # not need to know them by name. [switch] $HashUpns ) $ErrorActionPreference = "Stop" function Protect-Upn { param([string] $Value) if (-not $HashUpns -or [string]::IsNullOrWhiteSpace($Value)) { return $Value } $bytes = [System.Text.Encoding]::UTF8.GetBytes($Value.ToLowerInvariant()) $sha = [System.Security.Cryptography.SHA256]::Create() return ($sha.ComputeHash($bytes) | ForEach-Object { $_.ToString("x2") }) -join "" | ForEach-Object { $_.Substring(0, 16) } } Write-Host "Raidiness — Power Platform, read-only. Role: Power Platform Administrator." -ForegroundColor Cyan Write-Host "Nothing will be changed in the tenant." -ForegroundColor Cyan if (-not (Get-Module -ListAvailable -Name Microsoft.PowerApps.Administration.PowerShell)) { throw "The Microsoft.PowerApps.Administration.PowerShell module is missing. Install it first: Install-Module Microsoft.PowerApps.Administration.PowerShell -Scope CurrentUser" } Import-Module Microsoft.PowerApps.Administration.PowerShell Add-PowerAppsAccount -TenantID $TenantId | Out-Null $environments = Get-AdminPowerAppEnvironment | Select-Object ` EnvironmentName, DisplayName, Location, EnvironmentType, IsDefault, CreatedTime $dlp = Get-DlpPolicy | Select-Object ` PolicyName, DisplayName, Environments, DefaultConnectorsClassification, ConnectorGroups $agents = @() foreach ($environment in $environments) { $apps = Get-AdminPowerApp -EnvironmentName $environment.EnvironmentName | Where-Object { $_.AppType -eq "CopilotStudio" -or $_.Internal.properties.appType -eq "Copilot" } foreach ($app in $apps) { $agents += [ordered]@{ environmentName = $environment.EnvironmentName displayName = $app.DisplayName appName = $app.AppName owner = Protect-Upn ($app.Owner.email) createdTime = $app.CreatedTime lastModified = $app.LastModifiedTime sharedWithAll = [bool]($app.Internal.properties.sharedGroupsCount -gt 0) authentication = $app.Internal.properties.authenticationType } } } $payload = [ordered]@{ raidiness = [ordered]@{ version = "1.0" module = "power-platform" tenantId = $TenantId runId = $RunId generatedAt = (Get-Date).ToUniversalTime().ToString("o") upnsHashed = [bool] $HashUpns } results = [ordered]@{ "powerplatform.environments" = $environments "powerplatform.dlpPolicies" = $dlp "powerplatform.inventory.agents" = $agents } } $payload | ConvertTo-Json -Depth 8 | Out-File -FilePath $OutputPath -Encoding utf8 Write-Host "Done. Upload $OutputPath in Raidiness under the Power Platform module." -ForegroundColor Green |