SHELL/helpers/fabric_settings_helpers.ps1
|
function Get-Root365FabricValue { param( [AllowNull()][object]$Object, [Parameter(Mandatory = $true)][string]$Name ) if ($null -eq $Object) { return $null } if ($Object -is [System.Collections.IDictionary]) { foreach ($Key in $Object.Keys) { if ([string]$Key -ieq $Name) { return $Object[$Key] } } } if ($Object.PSObject -and $Object.PSObject.Properties) { foreach ($Property in $Object.PSObject.Properties) { if ([string]$Property.Name -ieq $Name) { return $Property.Value } } } return $null } function Convert-Root365FabricBool { param([AllowNull()]$Value) if ($null -eq $Value) { return $null } if ($Value -is [bool]) { return [bool]$Value } $Text = ([string]$Value).Trim() if ($Text -match '^(?i:true|1|enabled|yes)$') { return $true } if ($Text -match '^(?i:false|0|disabled|no)$') { return $false } return $null } function Convert-Root365SecureTokenToText { param([AllowNull()]$Token) if ($null -eq $Token) { return $null } if ($Token -is [string]) { return $Token } if ($Token -is [System.Security.SecureString]) { $Ptr = [System.IntPtr]::Zero try { $Ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token) return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($Ptr) } finally { if ($Ptr -ne [System.IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($Ptr) } } } return [string]$Token } function Get-Root365FabricToken { if (-not [string]::IsNullOrWhiteSpace([string]$env:ROOT365_FABRIC_ACCESS_TOKEN)) { return [string]$env:ROOT365_FABRIC_ACCESS_TOKEN } if (Get-Command -Name Get-AzAccessToken -ErrorAction SilentlyContinue) { try { $AccessTokenResult = Get-AzAccessToken -ResourceUrl 'https://api.fabric.microsoft.com' -ErrorAction Stop $TokenValue = Convert-Root365SecureTokenToText -Token (Get-Root365FabricValue -Object $AccessTokenResult -Name 'Token') if (-not [string]::IsNullOrWhiteSpace($TokenValue)) { return $TokenValue } } catch { # Continue to fallback options. } } if (Get-Command -Name Get-PowerBIAccessToken -ErrorAction SilentlyContinue) { try { $PowerBIToken = [string](Get-PowerBIAccessToken -AsString -ErrorAction Stop) if ($PowerBIToken -match '^(?i)Bearer\s+(?<token>.+)$') { return $Matches.token } if (-not [string]::IsNullOrWhiteSpace($PowerBIToken)) { return $PowerBIToken } } catch { # Continue to error below. } } throw "Unable to acquire Fabric API token. Use Connect-AzAccount (Az.Accounts) or Connect-PowerBIServiceAccount, or set ROOT365_FABRIC_ACCESS_TOKEN." } function Get-Root365FabricTenantSettings { if ($global:ROOT365_FabricTenantSettingsCache -and @($global:ROOT365_FabricTenantSettingsCache).Count -gt 0) { return @($global:ROOT365_FabricTenantSettingsCache) } $Token = Get-Root365FabricToken $Headers = @{ Authorization = "Bearer $Token" "Content-Type" = "application/json" } $Response = Invoke-RestMethod -Uri 'https://api.fabric.microsoft.com/v1/admin/tenantsettings' -Method Get -Headers $Headers -ErrorAction Stop $TenantSettings = @($Response.tenantSettings) if ($TenantSettings.Count -eq 0) { throw "Fabric API returned no tenant settings." } $global:ROOT365_FabricTenantSettingsCache = @($TenantSettings) return @($TenantSettings) } function Get-Root365FabricSetting { param( [Parameter(Mandatory = $true)][array]$Settings, [Parameter(Mandatory = $true)][string]$SettingName, [AllowNull()][string]$Title ) $ByName = @($Settings | Where-Object { ([string](Get-Root365FabricValue -Object $_ -Name 'settingName')) -eq $SettingName } | Select-Object -First 1) if ($ByName.Count -gt 0) { return $ByName[0] } if (-not [string]::IsNullOrWhiteSpace($Title)) { $ByTitle = @($Settings | Where-Object { ([string](Get-Root365FabricValue -Object $_ -Name 'title')) -eq $Title } | Select-Object -First 1) if ($ByTitle.Count -gt 0) { return $ByTitle[0] } } return $null } function Get-Root365FabricEnabledGroups { param([AllowNull()]$Setting) $GroupsRaw = @(Get-Root365FabricValue -Object $Setting -Name 'enabledSecurityGroups') $Groups = foreach ($Group in $GroupsRaw) { $Name = [string](Get-Root365FabricValue -Object $Group -Name 'name') if (-not [string]::IsNullOrWhiteSpace($Name)) { $Name continue } $Id = [string](Get-Root365FabricValue -Object $Group -Name 'id') if (-not [string]::IsNullOrWhiteSpace($Id)) { $Id } } return @($Groups | Select-Object -Unique) } function Invoke-Root365FabricControl { param( [Parameter(Mandatory = $true)][string]$CheckId, [Parameter(Mandatory = $true)][string]$Title, [Parameter(Mandatory = $true)][string]$Level, [Parameter(Mandatory = $true)][string]$SettingName, [AllowNull()][string]$SettingTitle, [Parameter(Mandatory = $true)][ValidateSet('Disable', 'RestrictOrDisable', 'Enable')][string]$Mode, [Parameter(Mandatory = $true)][ValidateSet('Pass', 'Fail')][string]$MissingSettingBehavior, [string]$BenchmarkType = 'Automated', [AllowNull()][string[]]$AuditCommands, [AllowNull()][string]$ExpectedStateDescription ) try { $Settings = @(Get-Root365FabricTenantSettings) $Setting = Get-Root365FabricSetting -Settings $Settings -SettingName $SettingName -Title $SettingTitle $Pass = $false $Status = 'FAIL' $ErrorMessage = $null $Enabled = $null $EnabledGroups = @() if ($null -eq $Setting) { $Pass = ($MissingSettingBehavior -eq 'Pass') $Status = if ($Pass) { 'PASS' } else { 'FAIL' } $ErrorMessage = if ($Pass) { $null } else { "Setting '$SettingName' was not found in Fabric tenant settings." } } else { $Enabled = Convert-Root365FabricBool -Value (Get-Root365FabricValue -Object $Setting -Name 'enabled') $EnabledGroups = @(Get-Root365FabricEnabledGroups -Setting $Setting) switch ($Mode) { 'Disable' { $Pass = ($Enabled -eq $false) if (-not $Pass) { $ErrorMessage = "Setting '$SettingName' is enabled; expected disabled." } } 'RestrictOrDisable' { $Pass = ($Enabled -eq $false) -or (($Enabled -eq $true) -and ($EnabledGroups.Count -gt 0)) if (-not $Pass) { $ErrorMessage = "Setting '$SettingName' is enabled for the entire organization and is not restricted to security groups." } } 'Enable' { $Pass = ($Enabled -eq $true) if (-not $Pass) { $ErrorMessage = "Setting '$SettingName' is not enabled." } } } $Status = if ($Pass) { 'PASS' } else { 'FAIL' } } [pscustomobject]@{ CheckId = $CheckId Title = $Title Level = $Level BenchmarkType = $BenchmarkType Status = $Status Pass = $Pass Evidence = [pscustomobject]@{ AuditCommands = $AuditCommands SettingName = $SettingName SettingTitle = $SettingTitle SettingFound = ($null -ne $Setting) Enabled = $Enabled EnabledSecurityGroups = $EnabledGroups Mode = $Mode MissingSettingBehavior = $MissingSettingBehavior ExpectedState = $ExpectedStateDescription RetrievedSettingCount = @($Settings).Count SourceDocument = 'CIS_Microsoft_365_Foundations_Benchmark_v6.0.1' } Error = $ErrorMessage Timestamp = Get-Date } } catch { $ExceptionMessage = [string]$_.Exception.Message $IsAuthOrPermissionIssue = ($ExceptionMessage -match '(?i)Unable to acquire Fabric API token') -or ($ExceptionMessage -match '(?i)forbidden') -or ($ExceptionMessage -match '(?i)unauthorized') -or ($ExceptionMessage -match '(?i)403') [pscustomobject]@{ CheckId = $CheckId Title = $Title Level = $Level BenchmarkType = $BenchmarkType Status = if ($IsAuthOrPermissionIssue) { 'MANUAL_REVIEW' } else { 'ERROR' } Pass = $null Evidence = [pscustomobject]@{ AuditCommands = $AuditCommands SettingName = $SettingName SettingTitle = $SettingTitle SourceDocument = 'CIS_Microsoft_365_Foundations_Benchmark_v6.0.1' } Error = $ExceptionMessage Timestamp = Get-Date } } } |