@@ -814,10 +814,12 @@ All UPNs: {{join(Result[*].UserPrincipalName, ", ")}}`,
814814 </ Typography >
815815 </ Stack >
816816 < Typography variant = "caption" color = "text.secondary" >
817- AST allowlist — approved cmdlets only. < code > +=</ code > is blocked. Data access
818- is automatically tenant-locked — do not pass{ ' ' }
819- < code > -TenantFilter</ code > . Type < code > %</ code > in the editor for replacement
820- variables.
817+ Runs in PowerShell < strong > ConstrainedLanguage</ strong > — approved cmdlets
818+ only. < code > New-Object</ code > , < code > { '[pscustomobject]@{}' } </ code > casts, and
819+ .NET/reflection are blocked. Build rows with{ ' ' }
820+ < code > { 'Select-Object @{Name;Expression}' } </ code > and return a plain{ ' ' }
821+ < code > { '@{}' } </ code > hashtable. Data access is tenant-locked — do not pass{ ' ' }
822+ < code > -TenantFilter</ code > . Type < code > %</ code > for replacement variables.
821823 </ Typography >
822824 </ Box >
823825 </ Grid >
@@ -907,20 +909,11 @@ $Licenses | ForEach-Object {
907909# Build results - users with their resolved license names
908910$results = $Users | Where-Object {
909911 $_.assignedLicenses.Count -gt 0
910- } | ForEach-Object {
911- $user = $_
912- $licenseNames = @($user.assignedLicenses | ForEach-Object {
913- $name = $SkuLookup[$_.skuId]
914- if ($name) { $name } else { $_.skuId }
915- })
916- [PSCustomObject]@{
917- UserPrincipalName = $user.userPrincipalName
918- DisplayName = $user.displayName
919- AccountEnabled = $user.accountEnabled
920- LicenseCount = $licenseNames.Count
921- Licenses = $licenseNames -join ', '
922- }
923- }
912+ } | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }},
913+ @{Name='DisplayName'; Expression={ $_.displayName }},
914+ @{Name='AccountEnabled'; Expression={ $_.accountEnabled }},
915+ @{Name='LicenseCount'; Expression={ @($_.assignedLicenses).Count }},
916+ @{Name='Licenses'; Expression={ (@($_.assignedLicenses | ForEach-Object { $n = $SkuLookup[$_.skuId]; if ($n) { $n } else { $_.skuId } }) -join ', ') }}
924917
925918# Build markdown table
926919$header = "### Licensed Users: $($results.Count)\\n\\n| User | Display Name | Enabled | Licenses |\\n|---|---|---|---|"
@@ -968,14 +961,10 @@ $Users = Get-CIPPTestData -Type 'Users'
968961$Users | Where-Object {
969962 $_.accountEnabled -eq $false -and
970963 $_.assignedLicenses.Count -gt 0
971- } | ForEach-Object {
972- [PSCustomObject]@{
973- UserPrincipalName = $_.userPrincipalName
974- DisplayName = $_.displayName
975- LicenseCount = $_.assignedLicenses.Count
976- Message = 'Disabled account with active license(s)'
977- }
978- }` }
964+ } | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }},
965+ @{Name='DisplayName'; Expression={ $_.displayName }},
966+ @{Name='LicenseCount'; Expression={ @($_.assignedLicenses).Count }},
967+ @{Name='Message'; Expression={ 'Disabled account with active license(s)' }}` }
979968 language = "powershell"
980969 showLineNumbers = { true }
981970 />
@@ -1008,14 +997,10 @@ $RegDetails = Get-CIPPTestData -Type 'UserRegistrationDetails'
1008997$noMfa = $RegDetails | Where-Object {
1009998 $_.methodsRegistered.Count -eq 0 -and
1010999 $_.userType -ne 'guest'
1011- } | ForEach-Object {
1012- [PSCustomObject]@{
1013- UserPrincipalName = $_.userPrincipalName
1014- UserDisplayName = $_.userDisplayName
1015- IsAdmin = $_.isAdmin
1016- Message = 'No MFA methods registered'
1017- }
1018- }
1000+ } | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }},
1001+ @{Name='UserDisplayName'; Expression={ $_.userDisplayName }},
1002+ @{Name='IsAdmin'; Expression={ $_.isAdmin }},
1003+ @{Name='Message'; Expression={ 'No MFA methods registered' }}
10191004
10201005$count = @($noMfa).Count
10211006if ($count -gt 0) {
@@ -1068,18 +1053,11 @@ $cutoff = (Get-Date).AddDays(-$DaysThreshold)
10681053$Guests | Where-Object {
10691054 -not $_.signInActivity.lastSignInDateTime -or
10701055 [datetime]$_.signInActivity.lastSignInDateTime -lt $cutoff
1071- } | ForEach-Object {
1072- $lastSign = if ($_.signInActivity.lastSignInDateTime) {
1073- $_.signInActivity.lastSignInDateTime
1074- } else { 'Never' }
1075- [PSCustomObject]@{
1076- UserPrincipalName = $_.userPrincipalName
1077- DisplayName = $_.displayName
1078- CreatedDateTime = $_.createdDateTime
1079- LastSignIn = $lastSign
1080- Message = "No sign-in within $DaysThreshold days"
1081- }
1082- }` }
1056+ } | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }},
1057+ @{Name='DisplayName'; Expression={ $_.displayName }},
1058+ @{Name='CreatedDateTime'; Expression={ $_.createdDateTime }},
1059+ @{Name='LastSignIn'; Expression={ if ($_.signInActivity.lastSignInDateTime) { $_.signInActivity.lastSignInDateTime } else { 'Never' } }},
1060+ @{Name='Message'; Expression={ "No sign-in within $DaysThreshold days" }}` }
10831061 language = "powershell"
10841062 showLineNumbers = { true }
10851063 />
@@ -1111,12 +1089,8 @@ $Guests | Where-Object {
11111089$Policies = Get-CIPPTestData -Type 'ConditionalAccessPolicies'
11121090$grouped = $Policies | Group-Object -Property state
11131091
1114- $counts = $grouped | ForEach-Object {
1115- [PSCustomObject]@{
1116- State = $_.Name
1117- Count = $_.Count
1118- }
1119- }
1092+ $counts = $grouped | Select-Object @{Name='State'; Expression={ $_.Name }},
1093+ @{Name='Count'; Expression={ $_.Count }}
11201094
11211095# Build markdown summary — %tenantname% is replaced at runtime
11221096$header = "### %tenantname% — CA Policies: $(@($Policies).Count) total\n\n| State | Count |\n|---|---|"
@@ -1428,6 +1402,13 @@ $md = $summaryTable + "\n\n---\n\n" + $policyTable
14281402 Type < code > %</ code > to insert replacement variables (e.g.{ ' ' }
14291403 < code > %tenantid%</ code > , < code > %defaultdomain%</ code > , or custom variables).
14301404 </ Typography >
1405+ < Alert severity = "info" sx = { { mt : 1 } } >
1406+ Scripts run in < strong > ConstrainedLanguage</ strong > . Build output rows with{ ' ' }
1407+ < code > { 'Select-Object @{Name;Expression}' } </ code > (not{ ' ' }
1408+ < code > { '[pscustomobject]@{}' } </ code > ) and return a{ ' ' }
1409+ < code > { '@{ CIPPStatus = ... }' } </ code > hashtable. < code > New-Object</ code > and
1410+ .NET reflection are blocked.
1411+ </ Alert >
14311412 { hasTenantFilterParam && (
14321413 < Alert severity = "warning" sx = { { mt : 1 } } >
14331414 < code > -TenantFilter</ code > is not needed — data access functions are
0 commit comments