Skip to content

Commit df469f1

Browse files
Merge pull request #47 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents fe7bcb0 + cf2536d commit df469f1

202 files changed

Lines changed: 4183 additions & 753 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ConversionTable.csv

Lines changed: 122 additions & 1 deletion
Large diffs are not rendered by default.

Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ function Add-CIPPDelegatedPermission {
114114
$OldScope = ($CurrentDelegatedScopes | Where-Object -Property Resourceid -EQ $svcPrincipalId.id)
115115

116116
if (!$OldScope) {
117+
if ([string]::IsNullOrEmpty($NewScope) -or $NewScope -eq ' ') {
118+
$Results.add("No delegated permissions to add for $($svcPrincipalId.displayName)")
119+
continue
120+
}
117121
try {
118122
$Createbody = @{
119123
clientId = $ourSVCPrincipal.id
@@ -147,6 +151,13 @@ function Add-CIPPDelegatedPermission {
147151
$Results.add("All delegated permissions exist for $($svcPrincipalId.displayName)")
148152
continue
149153
}
154+
155+
if ([string]::IsNullOrEmpty($NewScope) -or $NewScope -eq ' ') {
156+
# No permissions to update
157+
$Results.add("No delegated permissions to update for $($svcPrincipalId.displayName)")
158+
continue
159+
}
160+
150161
$Patchbody = @{
151162
scope = "$NewScope"
152163
} | ConvertTo-Json -Compress

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertHuntressRogueApps.ps1

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@ function Get-CIPPAlertHuntressRogueApps {
1313
Param (
1414
[Parameter(Mandatory = $false)]
1515
[Alias('input')]
16-
$InputValue,
16+
[bool]$InputValue = $false,
1717
$TenantFilter
1818
)
1919

2020
try {
2121
$RogueApps = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/huntresslabs/rogueapps/main/public/rogueapps.json'
2222
$RogueAppFilter = $RogueApps.appId -join "','"
2323
$ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$filter=appId in ('$RogueAppFilter')" -tenantid $TenantFilter
24+
# If IgnoreDisabledApps is true, filter out disabled service principals
25+
if ($InputValue) {
26+
$ServicePrincipals = $ServicePrincipals | Where-Object { $_.accountEnabled -eq $true }
27+
}
2428

2529
if (($ServicePrincipals | Measure-Object).Count -gt 0) {
2630
$AlertData = foreach ($ServicePrincipal in $ServicePrincipals) {

Modules/CIPPCore/Public/Alerts/Get-CIPPAlertInactiveLicensedUsers.ps1

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,60 @@ function Get-CIPPAlertInactiveLicensedUsers {
88
[Parameter(Mandatory = $false)]
99
[Alias('input')]
1010
$InputValue,
11+
[Parameter(Mandatory = $false)]
12+
[switch]$IncludeNeverSignedIn, # Include users who have never signed in (default is to skip them), future use would allow this to be set in an alert configuration
1113
$TenantFilter
1214
)
1315

1416
try {
1517
try {
18+
$Lookup = (Get-Date).AddDays(-90).ToUniversalTime()
19+
20+
# Build base filter - cannot filter assignedLicenses server-side
21+
$BaseFilter = if ($InputValue -eq $true) { "accountEnabled eq true" } else { "" }
1622

17-
$Lookup = (Get-Date).AddDays(-90).ToUniversalTime().ToString('o')
18-
$GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=(signInActivity/lastNonInteractiveSignInDateTime le $Lookup)&`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled,assignedLicenses" -scope 'https://graph.microsoft.com/.default' -tenantid $TenantFilter |
19-
Where-Object { $null -ne $_.assignedLicenses.skuId }
23+
$Uri = if ($BaseFilter) {
24+
"https://graph.microsoft.com/beta/users?`$filter=$BaseFilter&`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled,assignedLicenses"
25+
} else {
26+
"https://graph.microsoft.com/beta/users?`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled,assignedLicenses"
27+
}
28+
29+
$GraphRequest = New-GraphGetRequest -uri $Uri -scope 'https://graph.microsoft.com/.default' -tenantid $TenantFilter |
30+
Where-Object { $null -ne $_.assignedLicenses -and $_.assignedLicenses.Count -gt 0 }
2031

21-
# true = only active users
22-
if ($InputValue -eq $true) { $GraphRequest = $GraphRequest | Where-Object { $_.accountEnabled -eq $true } }
2332
$AlertData = foreach ($user in $GraphRequest) {
24-
$Message = 'User {0} has been inactive for 90 days, but still has a license assigned.' -f $user.UserPrincipalName
25-
$user | Select-Object -Property UserPrincipalName, signInActivity, @{Name = 'Message'; Expression = { $Message } }
33+
$lastInteractive = $user.signInActivity.lastSignInDateTime
34+
$lastNonInteractive = $user.signInActivity.lastNonInteractiveSignInDateTime
2635

27-
}
28-
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData
36+
# Find most recent sign-in
37+
$lastSignIn = $null
38+
if ($lastInteractive -and $lastNonInteractive) {
39+
$lastSignIn = if ([DateTime]$lastInteractive -gt [DateTime]$lastNonInteractive) { $lastInteractive } else { $lastNonInteractive }
40+
} elseif ($lastInteractive) {
41+
$lastSignIn = $lastInteractive
42+
} elseif ($lastNonInteractive) {
43+
$lastSignIn = $lastNonInteractive
44+
}
2945

30-
} catch {}
46+
# Check if inactive
47+
$isInactive = (-not $lastSignIn) -or ([DateTime]$lastSignIn -le $Lookup)
48+
# Skip users who have never signed in by default (unless IncludeNeverSignedIn is specified)
49+
if (-not $IncludeNeverSignedIn -and -not $lastSignIn) { continue }
50+
# Only process inactive users
51+
if ($isInactive) {
52+
if (-not $lastSignIn) {
53+
$Message = 'User {0} has never signed in but still has a license assigned.' -f $user.UserPrincipalName
54+
} else {
55+
$daysSinceSignIn = [Math]::Round(((Get-Date) - [DateTime]$lastSignIn).TotalDays)
56+
$Message = 'User {0} has been inactive for {1} days but still has a license assigned. Last sign-in: {2}' -f $user.UserPrincipalName, $daysSinceSignIn, $lastSignIn
57+
}
3158

59+
$user | Select-Object -Property UserPrincipalName, signInActivity, @{Name = 'Message'; Expression = { $Message } }
60+
}
61+
}
3262

63+
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData
64+
} catch {}
3365
} catch {
3466
Write-AlertMessage -tenant $($TenantFilter) -message "Failed to check inactive users with licenses for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)"
3567
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
function Get-CIPPAlertOneDriveQuota {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
#>
6+
[CmdletBinding()]
7+
Param (
8+
[Parameter(Mandatory)]
9+
$TenantFilter,
10+
[Alias('input')]
11+
[ValidateRange(0,100)]
12+
[int]$InputValue = 90
13+
)
14+
15+
try {
16+
$Usage = New-GraphGetRequest -tenantid $TenantFilter -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')?`$format=application/json&`$top=999" -AsApp $true
17+
if (!$Usage) {
18+
Write-AlertMessage -tenant $($TenantFilter) -message "OneDrive quota Alert: Unable to get OneDrive usage: Error occurred: No data returned from API."
19+
return
20+
}
21+
}
22+
catch {
23+
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
24+
Write-AlertMessage -tenant $($TenantFilter) -message "OneDrive quota Alert: Unable to get OneDrive usage: Error occurred: $ErrorMessage"
25+
return
26+
}
27+
28+
#Check if the OneDrive quota is over the threshold
29+
$OverQuota = $Usage | ForEach-Object {
30+
if ($_.StorageUsedInBytes -eq 0 -or $_.storageAllocatedInBytes -eq 0) { return }
31+
try {
32+
$UsagePercent = [math]::Round(($_.storageUsedInBytes / $_.storageAllocatedInBytes) * 100)
33+
} catch { $UsagePercent = 100 }
34+
35+
if ($UsagePercent -gt $InputValue) {
36+
$GBLeft = [math]::Round(($_.storageAllocatedInBytes - $_.storageUsedInBytes) / 1GB)
37+
"$($_.ownerPrincipalName): OneDrive is $UsagePercent% full. OneDrive has $($GBLeft)GB storage left"
38+
}
39+
40+
}
41+
42+
#If the quota is over the threshold, send an alert
43+
if ($OverQuota) {
44+
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $OverQuota
45+
}
46+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function Get-CIPPAlertTERRL {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
#>
6+
[CmdletBinding()]
7+
Param (
8+
[Parameter(Mandatory = $false)]
9+
[Alias('input')]
10+
$InputValue,
11+
$TenantFilter
12+
)
13+
14+
try {
15+
# Set threshold with fallback to 80%
16+
$Threshold = if ([string]::IsNullOrWhiteSpace($InputValue)) { 80 } else { [int]$InputValue }
17+
18+
# Get TERRL status
19+
$TerrlStatus = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-LimitsEnforcementStatus'
20+
21+
if ($TerrlStatus) {
22+
$UsagePercentage = [math]::Round(($TerrlStatus.ObservedValue / $TerrlStatus.Threshold) * 100, 2)
23+
24+
if ($UsagePercentage -gt $Threshold) {
25+
$AlertData = [PSCustomObject]@{
26+
UsagePercentage = $UsagePercentage
27+
CurrentVolume = $TerrlStatus.ObservedValue
28+
ThresholdLimit = $TerrlStatus.Threshold
29+
EnforcementEnabled = $TerrlStatus.EnforcementEnabled
30+
Verdict = $TerrlStatus.Verdict
31+
Message = 'Tenant is at {0}% of their TERRL limit (using {1} of {2} messages). Tenant Enforcement Status: {3}' -f $UsagePercentage, $TerrlStatus.ObservedValue, $TerrlStatus.Threshold, $TerrlStatus.Verdict
32+
}
33+
Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData
34+
}
35+
}
36+
} catch {
37+
Write-AlertMessage -tenant $($TenantFilter) -message "Could not get TERRL status for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)"
38+
}
39+
}

Modules/CIPPCore/Public/Authentication/Get-CIPPAccessRole.ps1

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,34 @@ function Get-CIPPAccessRole {
1616
Internal
1717
#>
1818
[CmdletBinding()]
19-
param($Request)
19+
param($Request, $Headers)
2020

21-
$CacheAccessUserRoleTable = Get-CIPPTable -tablename 'cacheAccessUserRole'
22-
$CachedRoles = Get-CIPPAzDataTableEntity @CacheAccessUserRoleTable -Filter "PartitionKey eq 'AccessUser' and RowKey eq '$($Request.Headers.'x-ms-client-principal-name')'" | Select-Object -ExpandProperty Role | ConvertFrom-Json
21+
$Headers = $Request.Headers ?? $Headers
2322

24-
$SwaCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json)
23+
$CacheAccessUserRoleTable = Get-CIPPTable -tablename 'cacheAccessUserRoles'
24+
25+
$SwaCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Headers.'x-ms-client-principal')) | ConvertFrom-Json)
2526
$SwaRoles = $SwaCreds.userRoles
27+
$Username = $SwaCreds.userDetails
28+
29+
$CachedRoles = Get-CIPPAzDataTableEntity @CacheAccessUserRoleTable -Filter "PartitionKey eq 'AccessUser' and RowKey eq '$Username'" | Select-Object -ExpandProperty Role | ConvertFrom-Json
30+
31+
Write-Information "SWA Roles: $($SwaRoles -join ', ')"
32+
Write-Information "Cached Roles: $($CachedRoles -join ', ')"
2633

2734
# Combine SWA roles and cached roles into a single deduplicated list
2835
$AllRoles = [System.Collections.Generic.List[string]]::new()
29-
if ($null -ne $SwaRoles) {
30-
$AllRoles.AddRange($SwaRoles)
36+
37+
foreach ($Role in $SwaRoles) {
38+
if (-not $AllRoles.Contains($Role)) {
39+
$AllRoles.Add($Role)
40+
}
3141
}
32-
if ($null -ne $CachedRoles) {
33-
$AllRoles.AddRange($CachedRoles)
42+
foreach ($Role in $CachedRoles) {
43+
if (-not $AllRoles.Contains($Role)) {
44+
$AllRoles.Add($Role)
45+
}
3446
}
35-
36-
# Remove duplicates and ensure we have a clean array
3747
$CombinedRoles = $AllRoles | Select-Object -Unique
3848

3949
# For debugging

0 commit comments

Comments
 (0)