@@ -1945,95 +1945,75 @@ function Invoke-NinjaOneTenantSync {
19451945
19461946 [System.Collections.Generic.List [PSCustomObject ]]$WidgetData = @ ()
19471947
1948- # ## Fetch BPA Data
1949- $Table = get-cipptable ' cachebpav2'
1950- $BPAData = (Get-CIPPAzDataTableEntity @Table - Filter " PartitionKey eq '$ ( $Customer.customerId ) '" )
1951-
1952- if ($Null -ne $BPAData.Timestamp ) {
1953- # # BPA Data Widgets
1954- # Shared Mailboxes with Enabled Users
1955- # $WidgetData.add([PSCustomObject]@{
1956- # Value = $(
1957- # $SharedSendMailboxCount = ($BpaData.SharedMailboxeswithenabledusers | ConvertFrom-Json | Measure-Object).count
1958- # if ($SharedSendMailboxCount -ne 0) {
1959- # $ResultColour = '#D53948'
1960- # } else {
1961- # $ResultColour = '#26A644'
1962- # }
1963- # $SharedSendMailboxCount
1964- # )
1965- # Description = 'Shared Mailboxes with enabled users'
1966- # Colour = $ResultColour
1967- # Link = "https://$CIPPUrl/tenant/standards/bpa-report?SearchNow=true&Report=CIPP+Best+Practices+v1.0+-+Tenant+view&tenantFilter=$($Customer.customerId)"
1968- # })
1969-
1970- # Unused Licenses
1971- $WidgetData.add ([PSCustomObject ]@ {
1972- Value = $ (
1973- try {
1974- $BPAUnusedLicenses = (($BpaData.Unusedlicenses | ConvertFrom-Json - ErrorAction SilentlyContinue).availableUnits | Measure-Object - Sum).sum
1975- } catch {
1976- $BPAUnusedLicenses = ' Failed to retrieve unused licenses'
1977- }
1978- if ($BPAUnusedLicenses -ne 0 ) {
1979- $ResultColour = ' #D53948'
1980- } else {
1981- $ResultColour = ' #26A644'
1982- }
1983- $BPAUnusedLicenses
1984- )
1985- Description = ' Unused Licenses'
1986- Colour = $ResultColour
1987- Link = " https://$CIPPUrl /tenant/standards/bpa-report?tenantFilter=$ ( $Customer.defaultDomainName ) "
1988- })
1948+ # ## Tenant Posture Widgets (CIPP Reporting DB)
1949+ $PostureTenant = $Customer.defaultDomainName
19891950
1951+ # Reads a reporting DB type and returns the deserialized data objects (count rows excluded).
1952+ $GetDbData = {
1953+ param ($Tenant , $Type )
1954+ try {
1955+ Get-CIPPDbItem - TenantFilter $Tenant - Type $Type | Where-Object { $_.RowKey -notlike ' *-Count' } | ForEach-Object { $_.Data | ConvertFrom-Json - ErrorAction SilentlyContinue }
1956+ } catch {
1957+ Write-Information " NinjaOne: failed to read '$Type ' from reporting DB for $Tenant : $ ( $_.Exception.Message ) "
1958+ }
1959+ }
19901960
1991- # Unified Audit Log
1992- $WidgetData.add ([PSCustomObject ]@ {
1993- Value = $ (if ($BPAData.UnifiedAuditLog -eq $True ) {
1994- $ResultColour = ' #26A644'
1995- ' <i class="fas fa-circle-check"></i>'
1996- } else {
1997- $ResultColour = ' #D53948'
1998- ' <i class="fas fa-circle-xmark"></i>'
1999- }
2000- )
2001- Description = ' Unified Audit Log'
2002- Colour = $ResultColour
2003- Link = " https://security.microsoft.com/auditlogsearch?viewid=Async%20Search&tid=$ ( $Customer.customerId ) "
2004- })
1961+ # OAuth App Consent - user consent restricted (legacy open-consent policy not assigned).
1962+ $AuthPolicy = (& $GetDbData - Tenant $PostureTenant - Type ' AuthorizationPolicy' ) | Select-Object - First 1
1963+ $HasAuthPolicy = $null -ne $AuthPolicy
1964+ $OAuthConsentRestricted = ' ManagePermissionGrantsForSelf.microsoft-user-default-legacy' -notin $AuthPolicy.permissionGrantPolicyIdsAssignedToDefaultUserRole
1965+
1966+ # Unified Audit Log - ingestion enabled
1967+ $AuditConfig = (& $GetDbData - Tenant $PostureTenant - Type ' ExoAdminAuditLogConfig' ) | Select-Object - First 1
1968+ $HasAuditConfig = $null -ne $AuditConfig
1969+ $UnifiedAuditLogEnabled = $AuditConfig.UnifiedAuditLogIngestionEnabled -eq $true
1970+
1971+ # Password Never Expires - any domain with password validity set to never (2147483647)
1972+ $DomainData = & $GetDbData - Tenant $PostureTenant - Type ' Domains'
1973+ $HasDomainData = ($DomainData | Measure-Object ).Count -gt 0
1974+ $PasswordNeverExpires = [bool ]($DomainData | Where-Object { $_.passwordValidityPeriodInDays -eq 2147483647 })
1975+
1976+ # Unused Licenses - sum of available units across SKUs with spare licenses
1977+ $LicenseData = & $GetDbData - Tenant $PostureTenant - Type ' LicenseOverview'
1978+ $HasLicenseData = ($LicenseData | Measure-Object ).Count -gt 0
1979+ $UnusedLicenseCount = (($LicenseData | Where-Object { $_.availableUnits -gt 0 }).availableUnits | Measure-Object - Sum).Sum
1980+ if ($null -eq $UnusedLicenseCount ) { $UnusedLicenseCount = 0 }
1981+
1982+ Write-Information " Tenant posture (reporting DB) - AuthPolicy:$HasAuthPolicy AuditConfig:$HasAuditConfig Domains:$HasDomainData Licenses:$HasLicenseData "
1983+
1984+ # Renders a boolean posture widget, with a neutral state when no cached data is available.
1985+ $NewPostureWidget = {
1986+ param ($Description , $Link , $HasData , $State )
1987+ if (-not $HasData ) {
1988+ [PSCustomObject ]@ { Value = ' <i class="fas fa-circle-question" title="No cached data - run the tenant data cache"></i>' ; Description = $Description ; Colour = ' #CCCCCC' ; Link = $Link }
1989+ } elseif ($State ) {
1990+ [PSCustomObject ]@ { Value = ' <i class="fas fa-circle-check"></i>' ; Description = $Description ; Colour = ' #26A644' ; Link = $Link }
1991+ } else {
1992+ [PSCustomObject ]@ { Value = ' <i class="fas fa-circle-xmark"></i>' ; Description = $Description ; Colour = ' #D53948' ; Link = $Link }
1993+ }
1994+ }
20051995
2006- # Passwords Never Expire
1996+ # Unused Licenses
1997+ $UnusedLicenseLink = " https://$CIPPUrl /tenant/standards/bpa-report?tenantFilter=$ ( $Customer.defaultDomainName ) "
1998+ if (-not $HasLicenseData ) {
1999+ $WidgetData.add ([PSCustomObject ]@ { Value = ' No data' ; Description = ' Unused Licenses' ; Colour = ' #CCCCCC' ; Link = $UnusedLicenseLink })
2000+ } else {
20072001 $WidgetData.add ([PSCustomObject ]@ {
2008- Value = $ (if ($BPAData.PasswordNeverExpires -eq $True ) {
2009- $ResultColour = ' #26A644'
2010- ' <i class="fas fa-circle-check"></i>'
2011- } else {
2012- $ResultColour = ' #D53948'
2013- ' <i class="fas fa-circle-xmark"></i>'
2014- }
2015- )
2016- Description = ' Password Never Expires'
2017- Colour = $ResultColour
2018- Link = " https://$CIPPUrl /tenant/standards/bpa-report?tenantFilter=$ ( $Customer.defaultDomainName ) "
2002+ Value = $UnusedLicenseCount
2003+ Description = ' Unused Licenses'
2004+ Colour = $ (if ($UnusedLicenseCount -ne 0 ) { ' #D53948' } else { ' #26A644' })
2005+ Link = $UnusedLicenseLink
20192006 })
2007+ }
20202008
2021- # oAuth App Consent
2022- $WidgetData.add ([PSCustomObject ]@ {
2023- Value = $ (if ($BPAData.OAuthAppConsent -eq $True ) {
2024- $ResultColour = ' #26A644'
2025- ' <i class="fas fa-circle-check"></i>'
2026- } else {
2027- $ResultColour = ' #D53948'
2028- ' <i class="fas fa-circle-xmark"></i>'
2029- }
2030- )
2031- Description = ' OAuth App Consent'
2032- Colour = $ResultColour
2033- Link = " https://entra.microsoft.com/$ ( $Customer.defaultDomainName ) /#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/UserSettings"
2034- })
2009+ # Unified Audit Log
2010+ $WidgetData.add ((& $NewPostureWidget - Description ' Unified Audit Log' - Link " https://security.microsoft.com/auditlogsearch?viewid=Async%20Search&tid=$ ( $Customer.customerId ) " - HasData $HasAuditConfig - State $UnifiedAuditLogEnabled ))
20352011
2036- }
2012+ # Password Never Expires
2013+ $WidgetData.add ((& $NewPostureWidget - Description ' Password Never Expires' - Link " https://$CIPPUrl /tenant/standards/bpa-report?tenantFilter=$ ( $Customer.defaultDomainName ) " - HasData $HasDomainData - State $PasswordNeverExpires ))
2014+
2015+ # OAuth App Consent
2016+ $WidgetData.add ((& $NewPostureWidget - Description ' OAuth App Consent' - Link " https://entra.microsoft.com/$ ( $Customer.defaultDomainName ) /#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/UserSettings" - HasData $HasAuthPolicy - State $OAuthConsentRestricted ))
20372017
20382018 # Blocked Senders
20392019 $BlockedSenderCount = ($BlockedSenders | Measure-Object ).count
0 commit comments