diff --git a/.github/workflows/dev_clouduptest.yml b/.github/workflows/dev_clouduptest.yml
new file mode 100644
index 000000000000..2754bc9b6e7b
--- /dev/null
+++ b/.github/workflows/dev_clouduptest.yml
@@ -0,0 +1,32 @@
+# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
+# More GitHub Actions for Azure: https://github.com/Azure/actions
+
+name: Build and deploy Powershell project to Azure Function App - clouduptest
+
+on:
+ push:
+ branches:
+ - dev
+ workflow_dispatch:
+
+env:
+ AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: 'Checkout GitHub Action'
+ uses: actions/checkout@v4
+
+ - name: 'Run Azure Functions Action'
+ uses: Azure/functions-action@v1
+ id: fa
+ with:
+ app-name: 'clouduptest'
+ slot-name: 'Production'
+ package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
+ publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_9B9E8B9A9BBE446188BCA9F126A1B646 }}
+ sku: 'flexconsumption'
+
\ No newline at end of file
diff --git a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1
index ad3a24553976..d2838016027c 100644
--- a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1
+++ b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1
@@ -19,6 +19,9 @@ function Add-CIPPScheduledTask {
[Parameter(Mandatory = $true, ParameterSetName = 'RunNow')]
[string]$RowKey,
+ [Parameter(Mandatory = $false, ParameterSetName = 'Default')]
+ [string]$DesiredStartTime = $null,
+
[Parameter(Mandatory = $false, ParameterSetName = 'Default')]
[Parameter(Mandatory = $false, ParameterSetName = 'RunNow')]
$Headers
@@ -119,8 +122,24 @@ function Add-CIPPScheduledTask {
$task.Recurrence.value
}
- if ([int64]$task.ScheduledTime -eq 0 -or [string]::IsNullOrEmpty($task.ScheduledTime)) {
- $task.ScheduledTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds
+ if ($DesiredStartTime) {
+ try {
+ # Parse the epoch time
+ $epochSeconds = [int64]$DesiredStartTime
+ # Set ScheduledTime to the desired time
+ $task.ScheduledTime = $epochSeconds
+ } catch {
+ Write-Warning "Failed to parse DesiredStartTime: $DesiredStartTime. Using provided ScheduledTime."
+ # Fall back to default
+ if ([int64]$task.ScheduledTime -eq 0 -or [string]::IsNullOrEmpty($task.ScheduledTime)) {
+ $task.ScheduledTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds
+ }
+ }
+ } else {
+ # No DesiredStartTime - use current behavior (immediate execution)
+ if ([int64]$task.ScheduledTime -eq 0 -or [string]::IsNullOrEmpty($task.ScheduledTime)) {
+ $task.ScheduledTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds
+ }
}
$excludedTenants = if ($task.excludedTenants.value) {
$task.excludedTenants.value -join ','
@@ -166,6 +185,10 @@ function Add-CIPPScheduledTask {
Hidden = [bool]$Hidden
Results = 'Planned'
}
+ # Always store DesiredStartTime if provided
+ if ($DesiredStartTime) {
+ $entity['DesiredStartTime'] = [string]$DesiredStartTime
+ }
# Store the original tenant filter for group expansion during execution
if ($originalTenantFilter -is [PSCustomObject] -and $originalTenantFilter.type -eq 'Group') {
@@ -190,6 +213,7 @@ function Add-CIPPScheduledTask {
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
return "Could not add task: $ErrorMessage"
}
+ Write-LogMessage -headers $Headers -API 'ScheduledTask' -message "Added task $($entity.Name) with ID $($entity.RowKey)" -Sev 'Info' -Tenant $tenantFilter
return "Successfully added task: $($entity.Name)"
}
} catch {
diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1
index ec55c10bb283..23004aa5c307 100644
--- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1
+++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1
@@ -4,7 +4,7 @@ function Get-CIPPAlertDepTokenExpiry {
Entrypoint
#>
[CmdletBinding()]
- Param (
+ param (
[Parameter(Mandatory = $false)]
[Alias('input')]
$InputValue,
@@ -13,7 +13,7 @@ function Get-CIPPAlertDepTokenExpiry {
try {
try {
- $DepTokens = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings' -tenantid $TenantFilter).value
+ $DepTokens = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings' -tenantid $TenantFilter
$AlertData = foreach ($Dep in $DepTokens) {
if ($Dep.tokenExpirationDateTime -lt (Get-Date).AddDays(30) -and $Dep.tokenExpirationDateTime -gt (Get-Date).AddDays(-7)) {
$Message = 'Apple Device Enrollment Program token expiring on {0}' -f $Dep.tokenExpirationDateTime
diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1
index 54f34db7ee17..3c731d4d84c6 100644
--- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1
+++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1
@@ -12,8 +12,13 @@ function Get-CIPPAlertNoCAConfig {
)
try {
- $CAAvailable = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $TenantFilter -ErrorAction Stop).serviceplans
- if ('AAD_PREMIUM' -in $CAAvailable.servicePlanName) {
+ # Only consider CA available when a SKU that grants it has enabled seats (> 0)
+ $SubscribedSkus = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/subscribedSkus?`$select=prepaidUnits,servicePlans" -tenantid $TenantFilter -ErrorAction Stop
+ $CAAvailable = foreach ($sku in $SubscribedSkus) {
+ if ([int]$sku.prepaidUnits.enabled -gt 0) { $sku.servicePlans }
+ }
+
+ if (('AAD_PREMIUM' -in $CAAvailable.servicePlanName) -or ('AAD_PREMIUM_P2' -in $CAAvailable.servicePlanName)) {
$CAPolicies = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies' -tenantid $TenantFilter)
if (!$CAPolicies.id) {
$AlertData = 'Conditional Access is available, but no policies could be found.'
diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1
index 9767e24fd5c4..2dab259a662a 100644
--- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1
+++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1
@@ -4,7 +4,7 @@ function Get-CIPPAlertVppTokenExpiry {
Entrypoint
#>
[CmdletBinding()]
- Param (
+ param (
[Parameter(Mandatory = $false)]
[Alias('input')]
$InputValue,
@@ -12,13 +12,12 @@ function Get-CIPPAlertVppTokenExpiry {
)
try {
try {
- $VppTokens = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceAppManagement/vppTokens' -tenantid $TenantFilter).value
+ $VppTokens = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceAppManagement/vppTokens' -tenantid $TenantFilter
$AlertData = foreach ($Vpp in $VppTokens) {
if ($Vpp.state -ne 'valid') {
$Message = 'Apple Volume Purchase Program Token is not valid, new token required'
$Vpp | Select-Object -Property organizationName, appleId, vppTokenAccountType, @{Name = 'Message'; Expression = { $Message } }
- }
- if ($Vpp.expirationDateTime -lt (Get-Date).AddDays(30) -and $Vpp.expirationDateTime -gt (Get-Date).AddDays(-7)) {
+ } elseif ($Vpp.expirationDateTime -lt (Get-Date).AddDays(30).ToUniversalTime() -and $Vpp.expirationDateTime -gt (Get-Date).AddDays(-7).ToUniversalTime()) {
$Message = 'Apple Volume Purchase Program token expiring on {0}' -f $Vpp.expirationDateTime
$Vpp | Select-Object -Property organizationName, appleId, vppTokenAccountType, @{Name = 'Message'; Expression = { $Message } }
}
diff --git a/Modules/CIPPCore/Public/Authentication/Get-CippAllowedPermissions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CippAllowedPermissions.ps1
index 0f11f47d8684..a48bf575c136 100644
--- a/Modules/CIPPCore/Public/Authentication/Get-CippAllowedPermissions.ps1
+++ b/Modules/CIPPCore/Public/Authentication/Get-CippAllowedPermissions.ps1
@@ -70,7 +70,6 @@ function Get-CippAllowedPermissions {
# For admin and superadmin: Compute permissions from base role include/exclude rules
if ($PrimaryRole -in @('admin', 'superadmin')) {
- Write-Information "Computing permissions for $PrimaryRole using base role rules"
if ($BaseRole) {
# Start with all permissions and apply include/exclude rules
@@ -143,7 +142,19 @@ function Get-CippAllowedPermissions {
}
# Restrict base permissions to only those allowed by custom roles
- $RestrictedPermissions = $BasePermissions | Where-Object { $CustomRolePermissions -contains $_ }
+ # Include Read permissions when ReadWrite permissions are present
+ $RestrictedPermissions = $BasePermissions | Where-Object {
+ $Permission = $_
+ if ($CustomRolePermissions -contains $Permission) {
+ $true
+ } elseif ($Permission -match 'Read$') {
+ # Check if there's a corresponding ReadWrite permission
+ $ReadWritePermission = $Permission -replace 'Read', 'ReadWrite'
+ $CustomRolePermissions -contains $ReadWritePermission
+ } else {
+ $false
+ }
+ }
foreach ($Permission in $RestrictedPermissions) {
if ($null -ne $Permission -and $Permission -is [string]) {
$AllowedPermissions.Add($Permission)
@@ -161,8 +172,6 @@ function Get-CippAllowedPermissions {
}
# Handle users with only custom roles (no base role)
elseif ($CustomRoles.Count -gt 0) {
- Write-Information 'Computing permissions for custom roles only'
-
foreach ($CustomRole in $CustomRoles) {
try {
$RolePermissions = Get-CIPPRolePermissions -RoleName $CustomRole
diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1
index f4f80f4cb5dc..e9c33daf0ebf 100644
--- a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1
+++ b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1
@@ -15,10 +15,10 @@ function Invoke-ListCippQueue {
$CippQueue = Get-CippTable -TableName 'CippQueue'
$CippQueueTasks = Get-CippTable -TableName 'CippQueueTasks'
$3HoursAgo = (Get-Date).ToUniversalTime().AddHours(-3).ToString('yyyy-MM-ddTHH:mm:ssZ')
- $CippQueueData = Get-CIPPAzDataTableEntity @CippQueue -Filter "Timestamp ge datetime'$3HoursAgo'" | Sort-Object -Property Timestamp -Descending
+ $CippQueueData = Get-CIPPAzDataTableEntity @CippQueue -Filter "PartitionKey eq 'CippQueue' and Timestamp ge datetime'$3HoursAgo'" | Sort-Object -Property Timestamp -Descending
$QueueData = foreach ($Queue in $CippQueueData) {
- $Tasks = Get-CIPPAzDataTableEntity @CippQueueTasks -Filter "QueueId eq '$($Queue.RowKey)'" | Where-Object { $_.Name } | Select-Object @{n = 'Timestamp'; exp = { $_.Timestamp.DateTime.ToUniversalTime() } }, Name, Status
+ $Tasks = Get-CIPPAzDataTableEntity @CippQueueTasks -Filter "PartitionKey eq 'Task' and QueueId eq '$($Queue.RowKey)'" | Where-Object { $_.Name } | Select-Object @{n = 'Timestamp'; exp = { $_.Timestamp.DateTime.ToUniversalTime() } }, Name, Status
$TaskStatus = @{}
$Tasks | Group-Object -Property Status | ForEach-Object {
$TaskStatus.$($_.Name) = $_.Count
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1
index 1ad77fdc3ac7..54ad46f0d529 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1
@@ -33,6 +33,10 @@ function Invoke-ListGraphRequest {
$Parameters.'$expand' = $Request.Query.'$expand'
}
+ if ($Request.Query.expand) {
+ $Parameters.'expand' = $Request.Query.expand
+ }
+
if ($Request.Query.'$top') {
$Parameters.'$top' = $Request.Query.'$top'
}
@@ -120,13 +124,13 @@ function Invoke-ListGraphRequest {
try {
$Results = Get-GraphRequestList @GraphRequestParams
- if ($Results.nextLink) {
- Write-Host "NextLink: $($Results.nextLink | Select-Object -Last 1)"
- if ($Request.Query.TenantFilter -ne 'AllTenants') {
- $Metadata['nextLink'] = $Results.nextLink | Select-Object -Last 1
+ if ($Results | Where-Object { $_.PSObject.Properties.Name -contains 'nextLink' }) {
+ if (![string]::IsNullOrEmpty($Results.nextLink) -and $Request.Query.TenantFilter -ne 'AllTenants') {
+ Write-Host "NextLink: $($Results.nextLink | Where-Object { $_ } | Select-Object -Last 1)"
+ $Metadata['nextLink'] = $Results.nextLink | Where-Object { $_ } | Select-Object -Last 1
}
- #Results is an array of objects, so we need to remove the last object before returning
- $Results = $Results | Select-Object -First ($Results.Count - 1)
+ # Remove nextLink trailing object only if it’s the last item
+ $Results = $Results | Where-Object { $_.PSObject.Properties.Name -notcontains 'nextLink' }
}
if ($Request.Query.ListProperties) {
$Columns = ($Results | Select-Object -First 1).PSObject.Properties.Name
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1
index 1ec5a2d2c70d..89f5a6c586af 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1
@@ -31,7 +31,7 @@ function Invoke-AddScheduledItem {
$Result = "Error scheduling task: $($_.Exception.Message)"
}
} else {
- $Result = Add-CIPPScheduledTask -Task $Request.Body -Headers $Request.Headers -hidden $hidden -DisallowDuplicateName $Request.Query.DisallowDuplicateName
+ $Result = Add-CIPPScheduledTask -Task $Request.Body -Headers $Request.Headers -hidden $hidden -DisallowDuplicateName $Request.Query.DisallowDuplicateName -DesiredStartTime $Request.Body.DesiredStartTime
Write-LogMessage -headers $Request.Headers -API $APINAME -message $Result -Sev 'Info'
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1
index 25fbf73dc0ed..2f6136b4f7c6 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1
@@ -17,7 +17,7 @@ function Invoke-ExecRestoreBackup {
if ($Request.Body.BackupName -like 'CippBackup_*') {
$Table = Get-CippTable -tablename 'CIPPBackup'
- $Backup = Get-CippAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.BackupName)'"
+ $Backup = Get-CippAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.BackupName)' or OriginalEntityId eq '$($Request.Body.BackupName)'"
if ($Backup) {
$BackupData = $Backup.Backup | ConvertFrom-Json -ErrorAction SilentlyContinue | Select-Object * -ExcludeProperty ETag, Timestamp
$BackupData | ForEach-Object {
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecTenantGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecTenantGroup.ps1
index 5ab6cf634b28..eb47c838becc 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecTenantGroup.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecTenantGroup.ps1
@@ -43,7 +43,7 @@ function Invoke-ExecTenantGroup {
Add-CIPPAzDataTableEntity @Table -Entity $GroupEntity -Force
}
- $CurrentMembers = Get-CIPPAzDataTableEntity @MembersTable -Filter "GroupId eq '$groupId'"
+ $CurrentMembers = Get-CIPPAzDataTableEntity @MembersTable -Filter "PartitionKey eq 'Member' and GroupId eq '$groupId'"
$Adds = [System.Collections.Generic.List[string]]::new()
$Removes = [System.Collections.Generic.List[string]]::new()
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1
index 985b60203f3d..e1accc58772c 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1
@@ -1,6 +1,6 @@
using namespace System.Net
-Function Invoke-AddPolicy {
+function Invoke-AddPolicy {
<#
.FUNCTIONALITY
Entrypoint
@@ -14,8 +14,8 @@ Function Invoke-AddPolicy {
$Headers = $Request.Headers
Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug'
- $Tenants = ($Request.Body.tenantFilter.value)
- if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants).defaultDomainName }
+ $Tenants = $Request.Body.tenantFilter.value ? $Request.Body.tenantFilter.value : $Request.Body.tenantFilter
+ if ('AllTenants' -in $Tenants) { $Tetnants = (Get-Tenants).defaultDomainName }
$displayname = $Request.Body.displayName
$description = $Request.Body.Description
$AssignTo = if ($Request.Body.AssignTo -ne 'on') { $Request.Body.AssignTo }
@@ -25,7 +25,7 @@ Function Invoke-AddPolicy {
$results = foreach ($Tenant in $tenants) {
if ($Request.Body.replacemap.$tenant) {
- ([pscustomobject]$Request.Body.replacemap.$tenant).psobject.properties | ForEach-Object { $RawJson = $RawJson -replace $_.name, $_.value }
+ ([pscustomobject]$Request.Body.replacemap.$tenant).psobject.properties | ForEach-Object { $RawJson = $RawJson -replace $_.name, $_.value }
}
try {
Write-Host 'Calling Adding policy'
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1
index c0256ffdd24a..db016aa2e7df 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1
@@ -19,7 +19,14 @@ function Invoke-ListGroups {
$GroupType = $Request.Query.groupType
$Members = $Request.Query.members
$Owners = $Request.Query.owners
- $SelectString = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&$expand=members($select=userPrincipalName)'
+
+ $ExpandMembers = $Request.Query.expandMembers ?? $false
+
+ $SelectString = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName'
+ if ($ExpandMembers -ne $false) {
+ $SelectString = '{0}&$expand=members($select=userPrincipalName)' -f $SelectString
+ }
+
$BulkRequestArrayList = [System.Collections.Generic.List[object]]::new()
@@ -86,7 +93,7 @@ function Invoke-ListGroups {
$RawGraphRequest = New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($BulkRequestArrayList) -asapp $true
$GraphRequest = [PSCustomObject]@{
groupInfo = ($RawGraphRequest | Where-Object { $_.id -eq 1 }).body | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } },
- @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true } else { $false } } },
+ @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -like '*Team*') { $true } else { $false } } },
@{Name = 'calculatedGroupType'; Expression = {
if ($_.mailEnabled -and $_.securityEnabled) { 'Mail-Enabled Security' }
if (!$_.mailEnabled -and $_.securityEnabled) { 'Security' }
@@ -129,4 +136,4 @@ function Invoke-ListGroups {
Body = $GraphRequest
})
-}
\ No newline at end of file
+}
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1
index ae45ad066f45..2b06bf09a7c7 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1
@@ -134,19 +134,21 @@ function Invoke-ExecJITAdmin {
if ($Request.Body.useraction -eq 'Create') {
Write-LogMessage -Headers $User -API $APIName -tenant $TenantFilter -message "Creating JIT Admin user $($Request.Body.Username)" -Sev 'Info'
Write-Information "Creating JIT Admin user $($Request.Body.username)"
+ $Domain = $Request.Body.Domain.value ? $Request.Body.Domain.value : $Request.Body.Domain
+
$JITAdmin = @{
User = @{
'FirstName' = $Request.Body.FirstName
'LastName' = $Request.Body.LastName
- 'UserPrincipalName' = "$($Request.Body.Username)@$($Request.Body.Domain.value)"
+ 'UserPrincipalName' = "$($Request.Body.Username)@$($Domain)"
}
Expiration = $Expiration
Action = 'Create'
TenantFilter = $TenantFilter
}
$CreateResult = Set-CIPPUserJITAdmin @JITAdmin
- $Username = "$($Request.Body.Username)@$($Request.Body.Domain.value)"
- $Results.Add("Created User: $($Request.Body.Username)@$($Request.Body.Domain.value)")
+ $Username = "$($Request.Body.Username)@$($Domain)"
+ $Results.Add("Created User: $Username")
if (!$Request.Body.UseTAP) {
$Results.Add("Password: $($CreateResult.password)")
}
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1
index 0ac9be97d022..99bc8bc0c144 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1
@@ -20,7 +20,12 @@ function Invoke-ExecSetSharePointMember {
try {
if ($Request.Body.SharePointType -eq 'Group') {
- $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)' or proxyAddresses/any(x:endsWith(x,'$($Request.Body.GroupID)'))&`$count=true" -ComplexFilter -tenantid $TenantFilter).id
+ if ($Request.Body.GroupID -match '^[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$') {
+ $GroupId = $Request.Body.GroupID
+ } else {
+ $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)' or proxyAddresses/any(x:endsWith(x,'$($Request.Body.GroupID)')) or mailNickname eq '$($Request.Body.GroupID)'" -ComplexFilter -tenantid $TenantFilter).id
+ }
+
if ($Request.Body.Add -eq $true) {
$Results = Add-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $Request.Body.user.value -TenantFilter $TenantFilter -Headers $Headers
} else {
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1
index fdf1b97e79ba..a336637f08a8 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1
@@ -3,7 +3,7 @@ using namespace System.Net
function Invoke-ExecOnboardTenant {
<#
.FUNCTIONALITY
- Entrypoint
+ Entrypoint,AnyTenant
.ROLE
Tenant.Administration.ReadWrite
#>
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1
index 04a61795e46b..54fe9aa99036 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1
@@ -47,7 +47,17 @@ function Invoke-CIPPStandardsRun {
return
} else {
Write-Information 'Classic Standards Run'
- $AllTasks = Get-CIPPStandards
+
+ $GetStandardParams = @{
+ TenantFilter = $TenantFilter
+ runManually = $runManually
+ }
+
+ if ($TemplateID) {
+ $GetStandardParams['TemplateId'] = $TemplateID
+ }
+
+ $AllTasks = Get-CIPPStandards @GetStandardParams
if ($Force.IsPresent) {
Write-Information 'Clearing Rerun Cache'
diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tools/GitHub/Invoke-ExecGitHubAction.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tools/GitHub/Invoke-ExecGitHubAction.ps1
index a367c35b9cfb..b7c593da6604 100644
--- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tools/GitHub/Invoke-ExecGitHubAction.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tools/GitHub/Invoke-ExecGitHubAction.ps1
@@ -23,7 +23,7 @@ function Invoke-ExecGitHubAction {
$SplatParams = $Parameters | Select-Object -ExcludeProperty Action, TenantFilter | ConvertTo-Json | ConvertFrom-Json -AsHashtable
$Table = Get-CIPPTable -TableName Extensionsconfig
- $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).GitHub
+ $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -ErrorAction SilentlyContinue).GitHub
if (!$Configuration.Enabled) {
$Response = Invoke-RestMethod -Uri 'https://cippy.azurewebsites.net/api/ExecGitHubAction' -Method POST -Body ($Parameters | ConvertTo-Json -Depth 10) -ContentType 'application/json'
diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1
index 52cc699df175..3659f27154dc 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1
@@ -14,67 +14,36 @@ Function Invoke-ListExternalTenantInfo {
$Headers = $Request.Headers
Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug'
-
-
- # Interact with query parameters or the body of the request.
- $Tenant = $Request.Query.tenant
- $TenantFilter = $Request.Query.tenantFilter
-
- # Normalize to tenantid and determine if tenant exists
- $TenantId = (Invoke-RestMethod -Method GET "https://login.windows.net/$Tenant/.well-known/openid-configuration").token_endpoint.Split('/')[3]
-
- if ($TenantId) {
- $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$TenantId')" -NoAuthCheck $true -tenantid $TenantFilter
- $StatusCode = [HttpStatusCode]::OK
+ $HttpResponse = [HttpResponseContext]@{
+ StatusCode = [HttpStatusCode]::OK
+ Body = "Default response, you should never see this"
}
- if ($GraphRequest) {
-
- $TenantDefaultDomain = $GraphRequest.defaultDomainName
-
- $body = @"
-
-
-
- http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation
- https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc
-
- http://www.w3.org/2005/08/addressing/anonymous
-
-
-
-
-
- $TenantDefaultDomain
-
-
-
-
-"@
-
- # Create the headers
- $AutoDiscoverHeaders = @{
- 'Content-Type' = 'text/xml; charset=utf-8'
- 'SOAPAction' = '"http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation"'
- 'User-Agent' = 'AutodiscoverClient'
+ try {
+ if ($Request.Query.tenant) {
+ $Tenant = $Request.Query.tenant
+
+ # Normalize to tenantid and determine if tenant exists
+ $TenantId = (Invoke-RestMethod -Method GET "https://login.windows.net/$Tenant/.well-known/openid-configuration").token_endpoint.Split('/')[3]
+
+ if ($TenantId) {
+ $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$TenantId')" -NoAuthCheck $true -tenantid $env:TenantID
+ $StatusCode = [HttpStatusCode]::OK
+ $HttpResponse.Body = [PSCustomObject]@{
+ GraphRequest = $GraphRequest
+ }
+ } else {
+ $HttpResponse.StatusCode = [HttpStatusCode]::BadRequest
+ $HttpResponse.Body = "Tenant $($Tenant) not found"
+ }
+ } else {
+ $HttpResponse.StatusCode = [HttpStatusCode]::BadRequest
+ $HttpResponse.Body = "Tenant parameter is required"
}
-
- # Invoke
- $Response = Invoke-RestMethod -UseBasicParsing -Method Post -Uri 'https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc' -Body $body -Headers $AutoDiscoverHeaders
-
- # Return
- $TenantDomains = $Response.Envelope.body.GetFederationInformationResponseMessage.response.Domains.Domain | Sort-Object
+ } catch {
+ $HttpResponse.StatusCode = [HttpStatusCode]::InternalServerError
+ $HttpResponse.Body = "Something went wrong while trying to get tenant info for tenant $($Tenant): $($_.Exception.Message)"
}
- $results = [PSCustomObject]@{
- GraphRequest = $GraphRequest
- Domains = @($TenantDomains)
- }
-
- # Associate values to output bindings by calling 'Push-OutputBinding'.
- Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
- StatusCode = $StatusCode
- Body = $results
- })
-
+ Push-OutputBinding -Name Response -Value $HttpResponse
}
diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1
index a4f0f64a00b1..58976b122f30 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1
@@ -1,6 +1,6 @@
using namespace System.Net
-Function Invoke-PublicPhishingCheck {
+function Invoke-PublicPhishingCheck {
<#
.FUNCTIONALITY
Entrypoint
@@ -11,7 +11,10 @@ Function Invoke-PublicPhishingCheck {
#this has been switched to the external free service by cyberdrain at clone.cipp.app due to extreme numbers of executions if selfhosted.
param($Request, $TriggerMetadata)
- if ($Request.body.Cloned) {
+
+ $Tenant = Get-Tenants -TenantFilter $Request.body.TenantId
+
+ if ($Request.body.Cloned -and $Tenant.customerId -eq $Request.body.TenantId) {
Write-AlertMessage -message $Request.body.AlertMessage -sev 'Alert' -tenant $Request.body.TenantId
}
diff --git a/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1 b/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1
index 5fdabf756b71..8d68ef26e5f3 100644
--- a/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1
+++ b/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1
@@ -34,7 +34,7 @@ function Get-CIPPTenantAlignment {
$JSON = $_.JSON -replace '"Action":', '"action":'
try {
$RowKey = $_.RowKey
- $Data = $JSON | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue
+ $Data = $JSON | ConvertFrom-Json -Depth 100 -ErrorAction Stop
} catch {
Write-Warning "$($RowKey) standard could not be loaded: $($_.Exception.Message)"
return
@@ -52,7 +52,7 @@ function Get-CIPPTenantAlignment {
# Get standards comparison data
$StandardsTable = Get-CIPPTable -TableName 'CippStandardsReports'
- $AllStandards = Get-CIPPAzDataTableEntity @StandardsTable -Filter "PartitionKey ne 'StandardReport'"
+ $AllStandards = Get-CIPPAzDataTableEntity @StandardsTable -Filter "PartitionKey ne 'StandardReport' and PartitionKey ne ''"
# Filter by tenant if specified
$Standards = if ($TenantFilter) {
@@ -71,8 +71,16 @@ function Get-CIPPTenantAlignment {
# Process field value
if ($FieldValue -is [System.Boolean]) {
$FieldValue = [bool]$FieldValue
- } elseif ($FieldValue -like '*{*') {
- $FieldValue = ConvertFrom-Json -Depth 100 -InputObject $FieldValue -ErrorAction SilentlyContinue
+ } elseif (Test-Json -Json $FieldValue -ErrorAction SilentlyContinue) {
+ try {
+ $FieldValue = ConvertFrom-Json -Depth 100 -InputObject $FieldValue -ErrorAction Stop
+ } catch {
+ Write-Warning "$($FieldName) standard report could not be loaded: $($_.Exception.Message)"
+ $FieldValue = [PSCustomObject]@{
+ Error = "Invalid JSON format: $($_.Exception.Message)"
+ OriginalValue = $FieldValue
+ }
+ }
} else {
$FieldValue = [string]$FieldValue
}
diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1
index 9408d9e5dca0..abe5236b8295 100644
--- a/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1
+++ b/Modules/CIPPCore/Public/GraphHelper/Write-AlertTrace.ps1
@@ -3,7 +3,7 @@ function Write-AlertTrace {
.FUNCTIONALITY
Internal function. Pleases most of Write-AlertTrace for alerting purposes
#>
- Param(
+ param(
$cmdletName,
$data,
$tenantFilter
@@ -20,6 +20,8 @@ function Write-AlertTrace {
$TableRow = @{
'PartitionKey' = $PartitionKey
'RowKey' = "$($tenantFilter)-$($cmdletName)"
+ 'CmdletName' = "$cmdletName"
+ 'Tenant' = "$tenantFilter"
'LogData' = [string]$LogData
}
$Table.Entity = $TableRow
@@ -31,6 +33,8 @@ function Write-AlertTrace {
$TableRow = @{
'PartitionKey' = $PartitionKey
'RowKey' = "$($tenantFilter)-$($cmdletName)"
+ 'CmdletName' = "$cmdletName"
+ 'Tenant' = "$tenantFilter"
'LogData' = [string]$LogData
}
$Table.Entity = $TableRow
diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1
index e14bf71d6999..88feab4169e2 100644
--- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1
+++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1
@@ -153,7 +153,7 @@ function New-CIPPCAPolicy {
}
foreach ($location in $JSONObj.conditions.locations.includeLocations) {
- Write-Information "Replacing $location"
+ Write-Information "Replacing named location - $location"
$lookup = $LocationLookupTable | Where-Object -Property name -EQ $location
Write-Information "Found $lookup"
if (!$lookup) { continue }
@@ -198,6 +198,11 @@ function New-CIPPCAPolicy {
}
}
+ if ($JSONObj.conditions.users.includeUsers.Count -eq 0) {
+ Write-Information 'No users matched in this policy, setting to none'
+ $JSONObj.conditions.users.includeUsers = 'none'
+ }
+
} catch {
$ErrorMessage = Get-CippException -Exception $_
Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to replace displayNames for conditional access rule $($JSONObj.displayName). Error: $($ErrorMessage.NormalizedError)" -sev 'Error' -LogData $ErrorMessage
@@ -229,14 +234,19 @@ function New-CIPPCAPolicy {
if ($DisableSD -eq $true) {
#Send request to disable security defaults.
$body = '{ "isEnabled": false }'
- $null = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -Type patch -Body $body -ContentType 'application/json'
- Write-LogMessage -Headers $User -API 'Create CA Policy' -tenant $($Tenant) -message "Disabled Security Defaults for tenant $($TenantFilter)" -Sev 'Info'
- Start-Sleep 3
+ try {
+ $null = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -Type patch -Body $body -asApp $true -ContentType 'application/json'
+ Write-LogMessage -Headers $User -API 'Create CA Policy' -tenant $($Tenant) -message "Disabled Security Defaults for tenant $($TenantFilter)" -Sev 'Info'
+ Start-Sleep 3
+ } catch {
+ $ErrorMessage = Get-CippException -Exception $_
+ Write-Information "Failed to disable security defaults for tenant $($TenantFilter): $($ErrorMessage.NormalizedError)"
+ }
}
$RawJSON = ConvertTo-Json -InputObject $JSONObj -Depth 10 -Compress
Write-Information $RawJSON
try {
- Write-Information 'Checking'
+ Write-Information 'Checking for existing policies'
$CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $TenantFilter -asApp $true | Where-Object -Property displayName -EQ $displayname
if ($CheckExististing) {
if ($Overwrite -ne $true) {
@@ -249,7 +259,7 @@ function New-CIPPCAPolicy {
return "Updated policy $displayname for $tenantfilter"
}
} else {
- Write-Information 'Creating'
+ Write-Information 'Creating new policy'
if ($JSONobj.GrantControls.authenticationStrength.policyType -or $JSONObj.$jsonobj.LocationInfo) {
Start-Sleep 3
}
@@ -260,6 +270,10 @@ function New-CIPPCAPolicy {
} catch {
$ErrorMessage = Get-CippException -Exception $_
Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName): $($ErrorMessage.NormalizedError) " -sev 'Error' -LogData $ErrorMessage
+
+ Write-Warning "Failed to create or update conditional access rule $($JSONObj.displayName): $($ErrorMessage.NormalizedError)"
+ Write-Information $_.InvocationInfo.PositionMessage
+ Write-Information ($JSONObj | ConvertTo-Json -Depth 10)
throw "Failed to create or update conditional access rule $($JSONObj.displayName): $($ErrorMessage.NormalizedError)"
}
}
diff --git a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1
index e18f016429a6..c733ad7df034 100644
--- a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1
+++ b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1
@@ -30,9 +30,9 @@ function New-CIPPUserTask {
value = 'Set-CIPPUserLicense'
}
Parameters = [pscustomobject]@{
- UserId = $UserObj.id
+ UserId = $CreationResults.Username
APIName = 'Sherweb License Assignment'
- AddLicenses = $licenses
+ AddLicenses = $UserObj.licenses.value
}
ScheduledTime = 0 #right now, which is in the next 15 minutes and should cover most cases.
PostExecution = @{
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1
index b570a9206e41..e786db8130b2 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardAtpPolicyForO365 {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'AtpPolicyForO365' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'AtpPolicyForO365' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'AtpPolicyForO365'
if ($TestResult -eq $false) {
@@ -40,7 +40,7 @@ function Invoke-CIPPStandardAtpPolicyForO365 {
} #we're done.
try {
$CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AtpPolicyForO365' |
- Select-Object EnableATPForSPOTeamsODB, EnableSafeDocs, AllowSafeDocsOpen
+ Select-Object EnableATPForSPOTeamsODB, EnableSafeDocs, AllowSafeDocsOpen
} catch {
$CurrentState = @{
License = 'This tenant might not be licensed for this feature'
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1
index 406f02485f1a..8ff864589e35 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1
@@ -32,6 +32,7 @@ function Invoke-CIPPStandardConditionalAccessTemplate {
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'ConditionalAccess'
$Table = Get-CippTable -tablename 'templates'
$TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2')
+ $TestP2 = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_p2' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM_P2')
if ($TestResult -eq $false) {
#writing to each item that the license is not present.
$settings.TemplateList | ForEach-Object {
@@ -42,9 +43,8 @@ function Invoke-CIPPStandardConditionalAccessTemplate {
} #we're done.
try {
- $AllCAPolicies = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies?$top=999' -tenantid $Tenant
- }
- catch {
+ $AllCAPolicies = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies?$top=999' -tenantid $Tenant -asApp $true
+ } catch {
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the ConditionalAccessTemplate state for $Tenant. Error: $ErrorMessage" -Sev Error
return
@@ -55,6 +55,13 @@ function Invoke-CIPPStandardConditionalAccessTemplate {
try {
$Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$($Setting.TemplateList.value)'"
$JSONObj = (Get-CippAzDataTableEntity @Table -Filter $Filter).JSON
+ $Policy = $JSONObj | ConvertFrom-Json
+ if ($Policy.conditions.userRiskLevels.count -gt 0 -or $Policy.conditions.signInRiskLevels.count -gt 0) {
+ if (!$TestP2) {
+ Write-Information "Skipping policy $($Policy.displayName) as it requires AAD Premium P2 license."
+ continue
+ }
+ }
$null = New-CIPPCAPolicy -replacePattern 'displayName' -TenantFilter $tenant -state $Setting.state -RawJSON $JSONObj -Overwrite $true -APIName $APIName -Headers $Request.Headers -DisableSD $Setting.DisableSD
} catch {
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
@@ -70,7 +77,15 @@ function Invoke-CIPPStandardConditionalAccessTemplate {
$policy = $Policies | Where-Object { $_.displayName -eq $Setting.label }
$CheckExististing = $AllCAPolicies | Where-Object -Property displayName -EQ $Setting.label
if (!$CheckExististing) {
- Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Setting.value)" -FieldValue "Policy $($Setting.label) is missing from this tenant." -Tenant $Tenant
+ if ($Setting.conditions.userRiskLevels.Count -gt 0 -or $Setting.conditions.signInRiskLevels.Count -gt 0) {
+ if (!$TestP2) {
+ Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Setting.value)" -FieldValue "Policy $($Setting.label) requires AAD Premium P2 license." -Tenant $Tenant
+ } else {
+ Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Setting.value)" -FieldValue "Policy $($Setting.label) is missing from this tenant." -Tenant $Tenant
+ }
+ } else {
+ Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Setting.value)" -FieldValue "Policy $($Setting.label) is missing from this tenant." -Tenant $Tenant
+ }
} else {
$CompareObj = ConvertFrom-Json -ErrorAction SilentlyContinue -InputObject (New-CIPPCATemplate -TenantFilter $tenant -JSON $CheckExististing)
$Compare = Compare-CIPPIntuneObject -ReferenceObject $policy -DifferenceObject $CompareObj
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1
index ae4c238ce051..309027904a55 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1
@@ -30,7 +30,7 @@ function Invoke-CIPPStandardDefaultSharingLink {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DefaultSharingLink' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DefaultSharingLink' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
# Determine the desired sharing link type (default to Internal if not specified)
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1
index aca77117f96b..8bb7c18f8ac1 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1
@@ -29,7 +29,7 @@ function Invoke-CIPPStandardDeletedUserRentention {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DeletedUserRentention' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DeletedUserRentention' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DeletedUserRetention'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1
index d926b5a69270..a8b5229912e5 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1
@@ -29,7 +29,7 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DisableAddShortcutsToOneDrive' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DisableAddShortcutsToOneDrive' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableAddShortcutsToOneDrive'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1
index ad06e06ce457..a57c5a7ffbf7 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1
@@ -28,7 +28,7 @@ function Invoke-CIPPStandardDisableM365GroupUsers {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DisableM365GroupUsers' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DisableM365GroupUsers' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableM365GroupUsers'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1
index ffb0dba555dc..e9d8e63be8d0 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardDisableReshare {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DisableReshare' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DisableReshare' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableReshare'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1
index eda6a2a4014f..14a106926ba5 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1
@@ -32,7 +32,7 @@ function Invoke-CIPPStandardDisableSharePointLegacyAuth {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DisableSharePointLegacyAuth' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DisableSharePointLegacyAuth' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableSharePointLegacyAuth'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1
index 74e2628e219e..20eaf6719e11 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1
@@ -28,7 +28,7 @@ function Invoke-CIPPStandardDisableUserSiteCreate {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'DisableUserSiteCreate' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'DisableUserSiteCreate' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableUserSiteCreate'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExConnector.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExchangeConnectorTemplate.ps1
similarity index 100%
rename from Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExConnector.ps1
rename to Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExchangeConnectorTemplate.ps1
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1
index fac3406a91f8..63ae676c4509 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1
@@ -29,7 +29,7 @@ function Invoke-CIPPStandardExcludedfileExt {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'ExcludedfileExt' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'ExcludedfileExt' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'ExcludedfileExt'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1
index 1cd033c26a67..c3177bd9fb2c 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1
@@ -37,8 +37,7 @@ function Invoke-CIPPStandardMailContacts {
try {
$TenantID = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/organization' -tenantid $tenant)
$CurrentInfo = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/organization/$($TenantID.id)" -tenantid $Tenant
- }
- catch {
+ } catch {
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the MailContacts state for $Tenant. Error: $ErrorMessage" -Sev Error
return
@@ -46,11 +45,12 @@ function Invoke-CIPPStandardMailContacts {
$contacts = $settings
$TechAndSecurityContacts = @($Contacts.SecurityContact, $Contacts.TechContact)
+ $state = $CurrentInfo.marketingNotificationEmails -eq $Contacts.MarketingContact -and `
+ ($CurrentInfo.securityComplianceNotificationMails -in $TechAndSecurityContacts -or
+ $CurrentInfo.technicalNotificationMails -in $TechAndSecurityContacts) -and `
+ $CurrentInfo.privacyProfile.contactEmail -eq $Contacts.GeneralContact
+
if ($Settings.remediate -eq $true) {
- $state = $CurrentInfo.marketingNotificationEmails -eq $Contacts.MarketingContact -and `
- ($CurrentInfo.securityComplianceNotificationMails -in $TechAndSecurityContacts -or
- $CurrentInfo.technicalNotificationMails -in $TechAndSecurityContacts) -and `
- $CurrentInfo.privacyProfile.contactEmail -eq $Contacts.GeneralContact
if ($state) {
Write-LogMessage -API 'Standards' -tenant $tenant -message 'Contact emails are already set.' -sev Info
} else {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1
index 2b446afcfe9c..a13214d3306f 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardRestrictThirdPartyStorageServices {
param ($Tenant, $Settings)
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'RestrictThirdPartyStorageServices'
- $TestResult = Test-CIPPStandardLicense -StandardName 'ThirdPartyStorageServicesRestricted' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'ThirdPartyStorageServicesRestricted' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1
index 7112e90148c1..736a16f25480 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1
@@ -30,7 +30,7 @@ function Invoke-CIPPStandardSPAzureB2B {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPAzureB2B' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPAzureB2B' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1
index b30e945af564..b3acea0aaf26 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardSPDirectSharing {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPDirectSharing' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPDirectSharing' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1
index 59d08d079528..2d932a3facd3 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1
@@ -27,7 +27,7 @@ function Invoke-CIPPStandardSPDisableLegacyWorkflows {
https://docs.cipp.app/user-documentation/tenant/standards/list-standards
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableLegacyWorkflows' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableLegacyWorkflows' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1
index f1883357e1c3..c1d42395b43d 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardSPDisallowInfectedFiles {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisallowInfectedFiles' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisallowInfectedFiles' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1
index b76fb5939521..6baa5015cdde 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1
@@ -32,7 +32,7 @@ function Invoke-CIPPStandardSPEmailAttestation {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPEmailAttestation' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPEmailAttestation' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1
index 99f563cab686..d8860e81a57d 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardSPExternalUserExpiration {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPExternalUserExpiration' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPExternalUserExpiration' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1
index 6290bc0ed0f3..68fbff1f4898 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardSPFileRequests {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPFileRequests' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPFileRequests' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-LogMessage -API 'Standards' -tenant $tenant -message 'The tenant is not licenced for this standard SPFileRequests' -sev Error
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1
index 279deaac3ba5..eee6e26dec70 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1
@@ -29,7 +29,7 @@ function Invoke-CIPPStandardSPSyncButtonState {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'SPSyncButtonState' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'SPSyncButtonState' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1
index aefe21354eb0..67e2223ef016 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1
@@ -29,7 +29,7 @@ function Invoke-CIPPStandardTenantDefaultTimezone {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'TenantDefaultTimezone' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'TenantDefaultTimezone' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TenantDefaultTimezone'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1
index baeaed8e7d18..3ec4b1544145 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1
@@ -28,7 +28,7 @@ function Invoke-CIPPStandarddisableMacSync {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'disableMacSync' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'disableMacSync' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'disableMacSync'
if ($TestResult -eq $false) {
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1
index 37b1e7653ffd..0b119ef8c0cf 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1
@@ -32,7 +32,7 @@ function Invoke-CIPPStandardsharingCapability {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'sharingCapability' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'sharingCapability' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1
index 033d49556c15..646c6be19311 100644
--- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1
+++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1
@@ -31,7 +31,7 @@ function Invoke-CIPPStandardsharingDomainRestriction {
#>
param($Tenant, $Settings)
- $TestResult = Test-CIPPStandardLicense -StandardName 'sharingDomainRestriction' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
+ $TestResult = Test-CIPPStandardLicense -StandardName 'sharingDomainRestriction' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE')
if ($TestResult -eq $false) {
Write-Host "We're exiting as the correct license is not present for this standard."
diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1
index b9b16bbc0db6..18748ca7e5f4 100644
--- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1
+++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1
@@ -30,7 +30,7 @@ function Test-CIPPGDAPRelationships {
Issue = 'The relationship has global administrator access. Auto-Extend is not available.'
Tenant = [string]$Group.customer.displayName
Relationship = [string]$Group.displayName
- Link = 'https://docs.cipp.app/setup/gdap/troubleshooting#autoextend'
+ Link = 'https://docs.cipp.app/setup/installation/recommended-roles'
}) | Out-Null
}
diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1
index 3456ae75bd08..1e13a1d5f25c 100644
--- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1
+++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1
@@ -7,427 +7,431 @@ function Test-CIPPAuditLogRules {
$Rows
)
- # Helper function to map GUIDs and partner UPNs to user objects
- function Add-CIPPGuidMappings {
- param(
- [Parameter(Mandatory = $true)]
- $DataObject,
- [Parameter(Mandatory = $true)]
- $Users,
- [Parameter(Mandatory = $true)]
- $Groups,
- [Parameter(Mandatory = $true)]
- $Devices,
- [Parameter(Mandatory = $true)]
- $ServicePrincipals,
- [Parameter(Mandatory = $true)]
- $PartnerUsers,
- [Parameter(Mandatory = $false)]
- [string]$PropertyPrefix = ''
- )
+ try {
+ # Helper function to map GUIDs and partner UPNs to user objects
+ function Add-CIPPGuidMappings {
+ param(
+ [Parameter(Mandatory = $true)]
+ $DataObject,
+ [Parameter(Mandatory = $true)]
+ $Users,
+ [Parameter(Mandatory = $true)]
+ $Groups,
+ [Parameter(Mandatory = $true)]
+ $Devices,
+ [Parameter(Mandatory = $true)]
+ $ServicePrincipals,
+ [Parameter(Mandatory = $true)]
+ $PartnerUsers,
+ [Parameter(Mandatory = $false)]
+ [string]$PropertyPrefix = ''
+ )
+
+ $DataObject.PSObject.Properties | ForEach-Object {
+ # Check for standard GUID format OR partner UPN formats
+ if ($_.Value -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' -or
+ $_.Value -match 'user_[0-9a-f]{32}@[^@]+\.onmicrosoft\.com' -or
+ $_.Value -match '[^\\]+\.onmicrosoft\.com\\tenant:\s*[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12},\s*object:\s*[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}') {
+
+ # Use regex from guid-resolver hook to match various partner user formats
+ # Format 1: user_@.onmicrosoft.com
+ if ($_.Value -match 'user_([0-9a-f]{32})@([^@]+\.onmicrosoft\.com)') {
+ $hexId = $matches[1]
+ $tenantDomain = $matches[2]
+ if ($hexId.Length -eq 32) {
+ # Convert the 32-character hex string to GUID format
+ $guid = "$($hexId.Substring(0,8))-$($hexId.Substring(8,4))-$($hexId.Substring(12,4))-$($hexId.Substring(16,4))-$($hexId.Substring(20,12))"
+ Write-Information "Found partner UPN format: $($_.Value) with GUID: $guid and tenant: $tenantDomain"
+
+ # Check partner users for this GUID
+ foreach ($PartnerUser in $PartnerUsers) {
+ if ($PartnerUser.id -eq $guid) {
+ $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $PartnerUser.userPrincipalName -Force -ErrorAction SilentlyContinue
+ Write-Information "Mapped Partner User UPN: $($PartnerUser.userPrincipalName) to $PropertyPrefix$($_.Name)"
+ return
+ }
+ }
+ }
+ }
+
+ # Format 2: TenantName.onmicrosoft.com\tenant: , object:
+ if ($_.Value -match '([^\\]+\.onmicrosoft\.com)\\tenant:\s*([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}),\s*object:\s*([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})') {
+ $customerTenantDomain = $matches[1]
+ $partnerTenantGuid = $matches[2]
+ $objectGuid = $matches[3]
+ Write-Information "Found partner exchange format: customer tenant $customerTenantDomain, partner tenant $partnerTenantGuid, object $objectGuid"
- $DataObject.PSObject.Properties | ForEach-Object {
- # Check for standard GUID format OR partner UPN formats
- if ($_.Value -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' -or
- $_.Value -match 'user_[0-9a-f]{32}@[^@]+\.onmicrosoft\.com' -or
- $_.Value -match '[^\\]+\.onmicrosoft\.com\\tenant:\s*[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12},\s*object:\s*[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}') {
-
- # Use regex from guid-resolver hook to match various partner user formats
- # Format 1: user_@.onmicrosoft.com
- if ($_.Value -match 'user_([0-9a-f]{32})@([^@]+\.onmicrosoft\.com)') {
- $hexId = $matches[1]
- $tenantDomain = $matches[2]
- if ($hexId.Length -eq 32) {
- # Convert the 32-character hex string to GUID format
- $guid = "$($hexId.Substring(0,8))-$($hexId.Substring(8,4))-$($hexId.Substring(12,4))-$($hexId.Substring(16,4))-$($hexId.Substring(20,12))"
- Write-Information "Found partner UPN format: $($_.Value) with GUID: $guid and tenant: $tenantDomain"
-
- # Check partner users for this GUID
+ # Check partner users for this object GUID
foreach ($PartnerUser in $PartnerUsers) {
- if ($PartnerUser.id -eq $guid) {
+ if ($PartnerUser.id -eq $objectGuid) {
$DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $PartnerUser.userPrincipalName -Force -ErrorAction SilentlyContinue
Write-Information "Mapped Partner User UPN: $($PartnerUser.userPrincipalName) to $PropertyPrefix$($_.Name)"
return
}
}
}
- }
- # Format 2: TenantName.onmicrosoft.com\tenant: , object:
- if ($_.Value -match '([^\\]+\.onmicrosoft\.com)\\tenant:\s*([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}),\s*object:\s*([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})') {
- $customerTenantDomain = $matches[1]
- $partnerTenantGuid = $matches[2]
- $objectGuid = $matches[3]
- Write-Information "Found partner exchange format: customer tenant $customerTenantDomain, partner tenant $partnerTenantGuid, object $objectGuid"
-
- # Check partner users for this object GUID
- foreach ($PartnerUser in $PartnerUsers) {
- if ($PartnerUser.id -eq $objectGuid) {
- $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $PartnerUser.userPrincipalName -Force -ErrorAction SilentlyContinue
- Write-Information "Mapped Partner User UPN: $($PartnerUser.userPrincipalName) to $PropertyPrefix$($_.Name)"
+ # Check standard directory objects (users, groups, devices, service principals)
+ foreach ($User in $Users) {
+ if ($User.id -eq $_.Value) {
+ $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $User.userPrincipalName -Force -ErrorAction SilentlyContinue
+ Write-Information "Mapped User: $($User.userPrincipalName) to $PropertyPrefix$($_.Name)"
return
}
}
- }
-
- # Check standard directory objects (users, groups, devices, service principals)
- foreach ($User in $Users) {
- if ($User.id -eq $_.Value) {
- $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $User.userPrincipalName -Force -ErrorAction SilentlyContinue
- Write-Information "Mapped User: $($User.userPrincipalName) to $PropertyPrefix$($_.Name)"
- return
- }
- }
- foreach ($Group in $Groups) {
- if ($Group.id -eq $_.Value) {
- $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $Group -Force -ErrorAction SilentlyContinue
- Write-Information "Mapped Group: $($Group.displayName) to $PropertyPrefix$($_.Name)"
- return
+ foreach ($Group in $Groups) {
+ if ($Group.id -eq $_.Value) {
+ $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $Group -Force -ErrorAction SilentlyContinue
+ Write-Information "Mapped Group: $($Group.displayName) to $PropertyPrefix$($_.Name)"
+ return
+ }
}
- }
- foreach ($Device in $Devices) {
- if ($Device.id -eq $_.Value) {
- $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $Device -Force -ErrorAction SilentlyContinue
- Write-Information "Mapped Device: $($Device.displayName) to $PropertyPrefix$($_.Name)"
- return
+ foreach ($Device in $Devices) {
+ if ($Device.id -eq $_.Value) {
+ $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $Device -Force -ErrorAction SilentlyContinue
+ Write-Information "Mapped Device: $($Device.displayName) to $PropertyPrefix$($_.Name)"
+ return
+ }
}
- }
- foreach ($ServicePrincipal in $ServicePrincipals) {
- if ($ServicePrincipal.id -eq $_.Value -or $ServicePrincipal.appId -eq $_.Value) {
- $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $ServicePrincipal -Force -ErrorAction SilentlyContinue
- Write-Information "Mapped Service Principal: $($ServicePrincipal.displayName) to $PropertyPrefix$($_.Name)"
- return
+ foreach ($ServicePrincipal in $ServicePrincipals) {
+ if ($ServicePrincipal.id -eq $_.Value -or $ServicePrincipal.appId -eq $_.Value) {
+ $DataObject | Add-Member -NotePropertyName "$PropertyPrefix$($_.Name)" -NotePropertyValue $ServicePrincipal -Force -ErrorAction SilentlyContinue
+ Write-Information "Mapped Service Principal: $($ServicePrincipal.displayName) to $PropertyPrefix$($_.Name)"
+ return
+ }
}
}
}
}
- }
-
- #$FunctionStartTime = Get-Date
- $Results = [PSCustomObject]@{
- TotalLogs = 0
- MatchedLogs = 0
- MatchedRules = @()
- DataToProcess = @()
- }
+ #$FunctionStartTime = Get-Date
- # Get the CacheWebhooks table for removing processed rows
- $CacheWebhooksTable = Get-CippTable -TableName 'CacheWebhooks'
+ $Results = [PSCustomObject]@{
+ TotalLogs = 0
+ MatchedLogs = 0
+ MatchedRules = @()
+ DataToProcess = @()
+ }
- $ExtendedPropertiesIgnoreList = @(
- 'OAuth2:Authorize'
- 'OAuth2:Token'
- 'SAS:EndAuth'
- 'SAS:ProcessAuth'
- 'deviceAuth:ReprocessTls'
- 'Consent:Set'
- )
+ # Get the CacheWebhooks table for removing processed rows
+ $CacheWebhooksTable = Get-CippTable -TableName 'CacheWebhooks'
- $TrustedIPTable = Get-CIPPTable -TableName 'trustedIps'
- $ConfigTable = Get-CIPPTable -TableName 'WebhookRules'
- $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable
- $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } | ForEach-Object {
- [pscustomobject]@{
- Tenants = ($_.Tenants | ConvertFrom-Json)
- Excluded = ($_.excludedTenants | ConvertFrom-Json -ErrorAction SilentlyContinue)
- Conditions = $_.Conditions
- Actions = $_.Actions
- LogType = $_.Type
- }
- }
+ $ExtendedPropertiesIgnoreList = @(
+ 'OAuth2:Authorize'
+ 'OAuth2:Token'
+ 'SAS:EndAuth'
+ 'SAS:ProcessAuth'
+ 'deviceAuth:ReprocessTls'
+ 'Consent:Set'
+ )
- # Collect bulk data for users/groups/devices/applications
- $Requests = @(
- @{
- id = 'users'
- url = '/users?$select=id,displayName,userPrincipalName,accountEnabled&$top=999'
- method = 'GET'
- }
- @{
- id = 'groups'
- url = '/groups?$select=id,displayName,mailEnabled,securityEnabled&$top=999'
- method = 'GET'
- }
- @{
- id = 'devices'
- url = '/devices?$select=id,displayName,deviceId&$top=999'
- method = 'GET'
- }
- @{
- id = 'servicePrincipals'
- url = '/servicePrincipals?$select=id,displayName&$top=999'
- method = 'GET'
+ $TrustedIPTable = Get-CIPPTable -TableName 'trustedIps'
+ $ConfigTable = Get-CIPPTable -TableName 'WebhookRules'
+ $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable
+ $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } | ForEach-Object {
+ [pscustomobject]@{
+ Tenants = ($_.Tenants | ConvertFrom-Json)
+ Excluded = ($_.excludedTenants | ConvertFrom-Json -ErrorAction SilentlyContinue)
+ Conditions = $_.Conditions
+ Actions = $_.Actions
+ LogType = $_.Type
+ }
}
- )
- $Response = New-GraphBulkRequest -TenantId $TenantFilter -Requests $Requests
- # partner users
- $PartnerUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$select=id,displayName,userPrincipalName,accountEnabled&`$top=999" -AsApp $true -NoAuthCheck $true
+ # Collect bulk data for users/groups/devices/applications
+ $Requests = @(
+ @{
+ id = 'users'
+ url = '/users?$select=id,displayName,userPrincipalName,accountEnabled&$top=999'
+ method = 'GET'
+ }
+ @{
+ id = 'groups'
+ url = '/groups?$select=id,displayName,mailEnabled,securityEnabled&$top=999'
+ method = 'GET'
+ }
+ @{
+ id = 'devices'
+ url = '/devices?$select=id,displayName,deviceId&$top=999'
+ method = 'GET'
+ }
+ @{
+ id = 'servicePrincipals'
+ url = '/servicePrincipals?$select=id,displayName&$top=999'
+ method = 'GET'
+ }
+ )
+ $Response = New-GraphBulkRequest -TenantId $TenantFilter -Requests $Requests
+ # partner users
+ $PartnerUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$select=id,displayName,userPrincipalName,accountEnabled&`$top=999" -AsApp $true -NoAuthCheck $true
- $Users = $Response | Where-Object { $_.id -eq 'users' } | Select-Object -ExpandProperty body | Select-Object -ExpandProperty value
- $Groups = $Response | Where-Object { $_.id -eq 'groups' } | Select-Object -ExpandProperty body | Select-Object -ExpandProperty value
- $Devices = $Response | Where-Object { $_.id -eq 'devices' } | Select-Object -ExpandProperty body | Select-Object -ExpandProperty value
- $ServicePrincipals = $Response | Where-Object { $_.id -eq 'servicePrincipals' } | Select-Object -ExpandProperty body | Select-Object -ExpandProperty value
+ $Users = ($Response | Where-Object { $_.id -eq 'users' }).body.value
+ $Groups = ($Response | Where-Object { $_.id -eq 'groups' }).body.value ?? @()
+ $Devices = ($Response | Where-Object { $_.id -eq 'devices' }).body.value ?? @()
+ $ServicePrincipals = ($Response | Where-Object { $_.id -eq 'servicePrincipals' }).body.value
- Write-Warning '## Audit Log Configuration ##'
- Write-Information ($Configuration | ConvertTo-Json -Depth 10)
+ Write-Warning '## Audit Log Configuration ##'
+ Write-Information ($Configuration | ConvertTo-Json -Depth 10)
- try {
- $LogCount = $Rows.count
- $RunGuid = (New-Guid).Guid
- Write-Warning "Logs to process: $LogCount - RunGuid: $($RunGuid) - $($TenantFilter)"
- $Results.TotalLogs = $LogCount
- Write-Information "RunGuid: $RunGuid - Collecting logs"
- $SearchResults = $Rows
- } catch {
- Write-Warning "Error getting audit logs: $($_.Exception.Message)"
- Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit logs' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter
- throw $_
- }
+ try {
+ $LogCount = $Rows.count
+ $RunGuid = (New-Guid).Guid
+ Write-Warning "Logs to process: $LogCount - RunGuid: $($RunGuid) - $($TenantFilter)"
+ $Results.TotalLogs = $LogCount
+ Write-Information "RunGuid: $RunGuid - Collecting logs"
+ $SearchResults = $Rows
+ } catch {
+ Write-Warning "Error getting audit logs: $($_.Exception.Message)"
+ Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit logs' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter
+ throw $_
+ }
- if ($LogCount -gt 0) {
- $LocationTable = Get-CIPPTable -TableName 'knownlocationdbv2'
- $ProcessedData = foreach ($AuditRecord in $SearchResults) {
- $RecordStartTime = Get-Date
- Write-Information "Processing RowKey $($AuditRecord.id)"
- $RootProperties = $AuditRecord | Select-Object * -ExcludeProperty auditData
- $Data = $AuditRecord.auditData | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties, AuditRecord -ErrorAction SilentlyContinue
- try {
- # Attempt to locate GUIDs in $Data and match them with their corresponding user, group, device, or service principal recursively by checking each key/value once located lets store these mapped values in a CIPP$KeyName property
- Write-Information 'Checking Data for GUIDs to map to users, groups, devices, or service principals'
- Add-CIPPGuidMappings -DataObject $Data -Users $Users -Groups $Groups -Devices $Devices -ServicePrincipals $ServicePrincipals -PartnerUsers $PartnerUsers -PropertyPrefix 'CIPP'
-
- # Also check root properties for GUIDs and partner UPNs
- Write-Information 'Checking RootProperties for GUIDs to map to users, groups, devices, or service principals'
- Add-CIPPGuidMappings -DataObject $RootProperties -Users $Users -Groups $Groups -Devices $Devices -ServicePrincipals $ServicePrincipals -PartnerUsers $PartnerUsers
-
- if ($Data.ExtendedProperties) {
- $Data.CIPPExtendedProperties = ($Data.ExtendedProperties | ConvertTo-Json -Compress)
- $Data.ExtendedProperties | ForEach-Object {
- if ($_.Value -in $ExtendedPropertiesIgnoreList) {
- #write-warning "No need to process this operation as its in our ignore list. Some extended information: $($data.operation):$($_.Value) - $($TenantFilter)"
- continue
+ if ($LogCount -gt 0) {
+ $LocationTable = Get-CIPPTable -TableName 'knownlocationdbv2'
+ $ProcessedData = foreach ($AuditRecord in $SearchResults) {
+ $RecordStartTime = Get-Date
+ Write-Information "Processing RowKey $($AuditRecord.id)"
+ $RootProperties = $AuditRecord | Select-Object * -ExcludeProperty auditData
+ $Data = $AuditRecord.auditData | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties, AuditRecord -ErrorAction SilentlyContinue
+ try {
+ # Attempt to locate GUIDs in $Data and match them with their corresponding user, group, device, or service principal recursively by checking each key/value once located lets store these mapped values in a CIPP$KeyName property
+ Write-Information 'Checking Data for GUIDs to map to users, groups, devices, or service principals'
+ Add-CIPPGuidMappings -DataObject $Data -Users $Users -Groups $Groups -Devices $Devices -ServicePrincipals $ServicePrincipals -PartnerUsers $PartnerUsers -PropertyPrefix 'CIPP'
+
+ # Also check root properties for GUIDs and partner UPNs
+ Write-Information 'Checking RootProperties for GUIDs to map to users, groups, devices, or service principals'
+ Add-CIPPGuidMappings -DataObject $RootProperties -Users $Users -Groups $Groups -Devices $Devices -ServicePrincipals $ServicePrincipals -PartnerUsers $PartnerUsers
+
+ if ($Data.ExtendedProperties) {
+ $Data.CIPPExtendedProperties = ($Data.ExtendedProperties | ConvertTo-Json -Compress)
+ $Data.ExtendedProperties | ForEach-Object {
+ if ($_.Value -in $ExtendedPropertiesIgnoreList) {
+ #write-warning "No need to process this operation as its in our ignore list. Some extended information: $($data.operation):$($_.Value) - $($TenantFilter)"
+ continue
+ }
+ $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue
}
- $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue
}
- }
- if ($Data.DeviceProperties) {
- $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json -Compress)
- $Data.DeviceProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue }
- }
- if ($Data.parameters) {
- $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json -Compress)
- $Data.parameters | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue }
- }
- if ($Data.ModifiedProperties) {
- $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json -Compress)
- try {
- $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue }
- } catch {
- ##write-warning ($Data.ModifiedProperties | ConvertTo-Json -Depth 10)
+ if ($Data.DeviceProperties) {
+ $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json -Compress)
+ $Data.DeviceProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue }
}
- try {
- $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue }
- } catch {
- ##write-warning ($Data.ModifiedProperties | ConvertTo-Json -Depth 10)
+ if ($Data.parameters) {
+ $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json -Compress)
+ $Data.parameters | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue }
+ }
+ if ($Data.ModifiedProperties) {
+ $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json -Compress)
+ try {
+ $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue }
+ } catch {
+ ##write-warning ($Data.ModifiedProperties | ConvertTo-Json -Depth 10)
+ }
+ try {
+ $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue }
+ } catch {
+ ##write-warning ($Data.ModifiedProperties | ConvertTo-Json -Depth 10)
+ }
}
- }
-
-
- $HasLocationData = $false
- if (![string]::IsNullOrEmpty($Data.clientip) -and $Data.clientip -notmatch '[X]+') {
- # Ignore IP addresses that have been redacted
- $IPRegex = '^(?(?:\d{1,3}(?:\.\d{1,3}){3}|\[[0-9a-fA-F:]+\]|[0-9a-fA-F:]+))(?::\d+)?$'
- $Data.clientip = $Data.clientip -replace $IPRegex, '$1' -replace '[\[\]]', ''
- # Check if IP is on trusted IP list
- $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "((PartitionKey eq '$TenantFilter') or (PartitionKey eq 'AllTenants')) and RowKey eq '$($Data.clientip)' and state eq 'Trusted'"
- if ($TrustedIP) {
- #write-warning "IP $($Data.clientip) is trusted"
- $Trusted = $true
- }
- if (!$Trusted) {
- $CacheLookupStartTime = Get-Date
- $Location = Get-AzDataTableEntity @LocationTable -Filter "PartitionKey eq 'ip' and RowKey eq '$($Data.clientIp)'" | Select-Object -ExcludeProperty Tenant
- $CacheLookupEndTime = Get-Date
- $CacheLookupSeconds = ($CacheLookupEndTime - $CacheLookupStartTime).TotalSeconds
- Write-Warning "Cache lookup for IP $($Data.clientip) took $CacheLookupSeconds seconds"
-
- if ($Location) {
- $Country = $Location.CountryOrRegion
- $City = $Location.City
- $Proxy = $Location.Proxy
- $hosting = $Location.Hosting
- $ASName = $Location.ASName
- } else {
- try {
- $IPLookupStartTime = Get-Date
- $Location = Get-CIPPGeoIPLocation -IP $Data.clientip
- $IPLookupEndTime = Get-Date
- $IPLookupSeconds = ($IPLookupEndTime - $IPLookupStartTime).TotalSeconds
- Write-Warning "IP lookup for $($Data.clientip) took $IPLookupSeconds seconds"
- } catch {
- #write-warning "Unable to get IP location for $($Data.clientip): $($_.Exception.Message)"
- }
- $Country = if ($Location.countryCode) { $Location.countryCode } else { 'Unknown' }
- $City = if ($Location.city) { $Location.city } else { 'Unknown' }
- $Proxy = if ($Location.proxy -ne $null) { $Location.proxy } else { 'Unknown' }
- $hosting = if ($Location.hosting -ne $null) { $Location.hosting } else { 'Unknown' }
- $ASName = if ($Location.asname) { $Location.asname } else { 'Unknown' }
- $IP = $Data.ClientIP
- $LocationInfo = @{
- RowKey = [string]$Data.clientip
- PartitionKey = 'ip'
- Tenant = [string]$TenantFilter
- CountryOrRegion = "$Country"
- City = "$City"
- Proxy = "$Proxy"
- Hosting = "$hosting"
- ASName = "$ASName"
- }
+ $HasLocationData = $false
+ if (![string]::IsNullOrEmpty($Data.clientip) -and $Data.clientip -notmatch '[X]+') {
+ # Ignore IP addresses that have been redacted
- try {
- $null = Add-CIPPAzDataTableEntity @LocationTable -Entity $LocationInfo -Force
- } catch {
- #write-warning "Failed to add location info for $($Data.clientip) to cache: $($_.Exception.Message)"
+ $IPRegex = '^(?(?:\d{1,3}(?:\.\d{1,3}){3}|\[[0-9a-fA-F:]+\]|[0-9a-fA-F:]+))(?::\d+)?$'
+ $Data.clientip = $Data.clientip -replace $IPRegex, '$1' -replace '[\[\]]', ''
+ # Check if IP is on trusted IP list
+ $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "((PartitionKey eq '$TenantFilter') or (PartitionKey eq 'AllTenants')) and RowKey eq '$($Data.clientip)' and state eq 'Trusted'"
+ if ($TrustedIP) {
+ #write-warning "IP $($Data.clientip) is trusted"
+ $Trusted = $true
+ }
+ if (!$Trusted) {
+ $CacheLookupStartTime = Get-Date
+ $Location = Get-AzDataTableEntity @LocationTable -Filter "PartitionKey eq 'ip' and RowKey eq '$($Data.clientIp)'" | Select-Object -ExcludeProperty Tenant
+ $CacheLookupEndTime = Get-Date
+ $CacheLookupSeconds = ($CacheLookupEndTime - $CacheLookupStartTime).TotalSeconds
+ Write-Warning "Cache lookup for IP $($Data.clientip) took $CacheLookupSeconds seconds"
+
+ if ($Location) {
+ $Country = $Location.CountryOrRegion
+ $City = $Location.City
+ $Proxy = $Location.Proxy
+ $hosting = $Location.Hosting
+ $ASName = $Location.ASName
+ } else {
+ try {
+ $IPLookupStartTime = Get-Date
+ $Location = Get-CIPPGeoIPLocation -IP $Data.clientip
+ $IPLookupEndTime = Get-Date
+ $IPLookupSeconds = ($IPLookupEndTime - $IPLookupStartTime).TotalSeconds
+ Write-Warning "IP lookup for $($Data.clientip) took $IPLookupSeconds seconds"
+ } catch {
+ #write-warning "Unable to get IP location for $($Data.clientip): $($_.Exception.Message)"
+ }
+ $Country = if ($Location.countryCode) { $Location.countryCode } else { 'Unknown' }
+ $City = if ($Location.city) { $Location.city } else { 'Unknown' }
+ $Proxy = if ($Location.proxy -ne $null) { $Location.proxy } else { 'Unknown' }
+ $hosting = if ($Location.hosting -ne $null) { $Location.hosting } else { 'Unknown' }
+ $ASName = if ($Location.asname) { $Location.asname } else { 'Unknown' }
+ $IP = $Data.ClientIP
+ $LocationInfo = @{
+ RowKey = [string]$Data.clientip
+ PartitionKey = 'ip'
+ Tenant = [string]$TenantFilter
+ CountryOrRegion = "$Country"
+ City = "$City"
+ Proxy = "$Proxy"
+ Hosting = "$hosting"
+ ASName = "$ASName"
+ }
+
+ try {
+ $null = Add-CIPPAzDataTableEntity @LocationTable -Entity $LocationInfo -Force
+ } catch {
+ #write-warning "Failed to add location info for $($Data.clientip) to cache: $($_.Exception.Message)"
+
+ }
}
+ $Data.CIPPGeoLocation = $Country
+ $Data.CIPPBadRepIP = $Proxy
+ $Data.CIPPHostedIP = $hosting
+ $Data.CIPPIPDetected = $IP
+ $Data.CIPPLocationInfo = ($Location | ConvertTo-Json -Compress)
+ $HasLocationData = $true
}
- $Data.CIPPGeoLocation = $Country
- $Data.CIPPBadRepIP = $Proxy
- $Data.CIPPHostedIP = $hosting
- $Data.CIPPIPDetected = $IP
- $Data.CIPPLocationInfo = ($Location | ConvertTo-Json -Compress)
- $HasLocationData = $true
}
+ $Data.AuditRecord = [string]($RootProperties | ConvertTo-Json -Compress)
+ $Data | Select-Object *,
+ @{n = 'HasLocationData'; exp = { $HasLocationData } } -ExcludeProperty ExtendedProperties, DeviceProperties, parameters
+ } catch {
+ #write-warning "Audit log: Error processing data: $($_.Exception.Message)`r`n$($_.InvocationInfo.PositionMessage)"
+ Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit Log Data' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter
}
- $Data.AuditRecord = [string]($RootProperties | ConvertTo-Json -Compress)
- $Data | Select-Object *,
- @{n = 'HasLocationData'; exp = { $HasLocationData } } -ExcludeProperty ExtendedProperties, DeviceProperties, parameters
- } catch {
- #write-warning "Audit log: Error processing data: $($_.Exception.Message)`r`n$($_.InvocationInfo.PositionMessage)"
- Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit Log Data' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter
- }
- Write-Information "Removing row $($AuditRecord.id) from cache"
- try {
- Write-Information 'Removing processed rows from cache'
- $RowEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($AuditRecord.id)'"
- Remove-AzDataTableEntity @CacheWebhooksTable -Entity $RowEntity -Force
- Write-Information "Removed row $($AuditRecord.id) from cache"
- } catch {
- Write-Information "Error removing rows from cache: $($_.Exception.Message)"
- } finally {
- $RecordEndTime = Get-Date
- $RecordSeconds = ($RecordEndTime - $RecordStartTime).TotalSeconds
- Write-Warning "Task took $RecordSeconds seconds for RowKey $($AuditRecord.id)"
+ Write-Information "Removing row $($AuditRecord.id) from cache"
+ try {
+ Write-Information 'Removing processed rows from cache'
+ $RowEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($AuditRecord.id)'"
+ Remove-AzDataTableEntity @CacheWebhooksTable -Entity $RowEntity -Force
+ Write-Information "Removed row $($AuditRecord.id) from cache"
+ } catch {
+ Write-Information "Error removing rows from cache: $($_.Exception.Message)"
+ } finally {
+ $RecordEndTime = Get-Date
+ $RecordSeconds = ($RecordEndTime - $RecordStartTime).TotalSeconds
+ Write-Warning "Task took $RecordSeconds seconds for RowKey $($AuditRecord.id)"
+ }
}
- }
- #write-warning "Processed Data: $(($ProcessedData | Measure-Object).Count) - This should be higher than 0 in many cases, because the where object has not run yet."
- #write-warning "Creating filters - $(($ProcessedData.operation | Sort-Object -Unique) -join ',') - $($TenantFilter)"
+ #write-warning "Processed Data: $(($ProcessedData | Measure-Object).Count) - This should be higher than 0 in many cases, because the where object has not run yet."
+ #write-warning "Creating filters - $(($ProcessedData.operation | Sort-Object -Unique) -join ',') - $($TenantFilter)"
- try {
- $Where = foreach ($Config in $Configuration) {
- if ($TenantFilter -in $Config.Excluded.value) {
- continue
- }
- $conditions = $Config.Conditions | ConvertFrom-Json | Where-Object { $Config.Input.value -ne '' }
- $actions = $Config.Actions
- $conditionStrings = [System.Collections.Generic.List[string]]::new()
- $CIPPClause = [System.Collections.Generic.List[string]]::new()
- $AddedLocationCondition = $false
- foreach ($condition in $conditions) {
- if ($condition.Property.label -eq 'CIPPGeoLocation' -and !$AddedLocationCondition) {
- $conditionStrings.Add("`$_.HasLocationData -eq `$true")
- $CIPPClause.Add('HasLocationData is true')
- $AddedLocationCondition = $true
+ try {
+ $Where = foreach ($Config in $Configuration) {
+ if ($TenantFilter -in $Config.Excluded.value) {
+ continue
}
- $value = if ($condition.Input.value -is [array]) {
- $arrayAsString = $condition.Input.value | ForEach-Object {
- "'$_'"
+ $conditions = $Config.Conditions | ConvertFrom-Json | Where-Object { $Config.Input.value -ne '' }
+ $actions = $Config.Actions
+ $conditionStrings = [System.Collections.Generic.List[string]]::new()
+ $CIPPClause = [System.Collections.Generic.List[string]]::new()
+ $AddedLocationCondition = $false
+ foreach ($condition in $conditions) {
+ if ($condition.Property.label -eq 'CIPPGeoLocation' -and !$AddedLocationCondition) {
+ $conditionStrings.Add("`$_.HasLocationData -eq `$true")
+ $CIPPClause.Add('HasLocationData is true')
+ $AddedLocationCondition = $true
}
- "@($($arrayAsString -join ', '))"
- } else { "'$($condition.Input.value)'" }
+ $value = if ($condition.Input.value -is [array]) {
+ $arrayAsString = $condition.Input.value | ForEach-Object {
+ "'$_'"
+ }
+ "@($($arrayAsString -join ', '))"
+ } else { "'$($condition.Input.value)'" }
- $conditionStrings.Add("`$(`$_.$($condition.Property.label)) -$($condition.Operator.value) $value")
- $CIPPClause.Add("$($condition.Property.label) is $($condition.Operator.label) $value")
- }
- $finalCondition = $conditionStrings -join ' -AND '
+ $conditionStrings.Add("`$(`$_.$($condition.Property.label)) -$($condition.Operator.value) $value")
+ $CIPPClause.Add("$($condition.Property.label) is $($condition.Operator.label) $value")
+ }
+ $finalCondition = $conditionStrings -join ' -AND '
- [PSCustomObject]@{
- clause = $finalCondition
- expectedAction = $actions
- CIPPClause = $CIPPClause
+ [PSCustomObject]@{
+ clause = $finalCondition
+ expectedAction = $actions
+ CIPPClause = $CIPPClause
+ }
}
+ } catch {
+ Write-Warning "Error creating where clause: $($_.Exception.Message)"
+ Write-Information $_.InvocationInfo.PositionMessage
+ #Write-LogMessage -API 'Webhooks' -message 'Error creating where clause' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter
+ throw $_
}
- } catch {
- Write-Warning "Error creating where clause: $($_.Exception.Message)"
- Write-Information $_.InvocationInfo.PositionMessage
- #Write-LogMessage -API 'Webhooks' -message 'Error creating where clause' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter
- throw $_
- }
- $MatchedRules = [System.Collections.Generic.List[string]]::new()
- $DataToProcess = foreach ($clause in $Where) {
- $ClauseStartTime = Get-Date
- Write-Warning "Webhook: Processing clause: $($clause.clause)"
- $ReturnedData = $ProcessedData | Where-Object { Invoke-Expression $clause.clause }
- if ($ReturnedData) {
- Write-Warning "Webhook: There is matching data: $(($ReturnedData.operation | Select-Object -Unique) -join ', ')"
- $ReturnedData = foreach ($item in $ReturnedData) {
- $item.CIPPAction = $clause.expectedAction
- $item.CIPPClause = $clause.CIPPClause -join ' and '
- $MatchedRules.Add($clause.CIPPClause -join ' and ')
- $item
+ $MatchedRules = [System.Collections.Generic.List[string]]::new()
+ $DataToProcess = foreach ($clause in $Where) {
+ $ClauseStartTime = Get-Date
+ Write-Warning "Webhook: Processing clause: $($clause.clause)"
+ $ReturnedData = $ProcessedData | Where-Object { Invoke-Expression $clause.clause }
+ if ($ReturnedData) {
+ Write-Warning "Webhook: There is matching data: $(($ReturnedData.operation | Select-Object -Unique) -join ', ')"
+ $ReturnedData = foreach ($item in $ReturnedData) {
+ $item.CIPPAction = $clause.expectedAction
+ $item.CIPPClause = $clause.CIPPClause -join ' and '
+ $MatchedRules.Add($clause.CIPPClause -join ' and ')
+ $item
+ }
}
+ $ClauseEndTime = Get-Date
+ $ClauseSeconds = ($ClauseEndTime - $ClauseStartTime).TotalSeconds
+ Write-Warning "Task took $ClauseSeconds seconds for clause: $($clause.clause)"
+ $ReturnedData
}
- $ClauseEndTime = Get-Date
- $ClauseSeconds = ($ClauseEndTime - $ClauseStartTime).TotalSeconds
- Write-Warning "Task took $ClauseSeconds seconds for clause: $($clause.clause)"
- $ReturnedData
+ $Results.MatchedRules = @($MatchedRules | Select-Object -Unique)
+ $Results.MatchedLogs = ($DataToProcess | Measure-Object).Count
+ $Results.DataToProcess = $DataToProcess
}
- $Results.MatchedRules = @($MatchedRules | Select-Object -Unique)
- $Results.MatchedLogs = ($DataToProcess | Measure-Object).Count
- $Results.DataToProcess = $DataToProcess
- }
- if ($DataToProcess) {
- $CippConfigTable = Get-CippTable -tablename Config
- $CippConfig = Get-CIPPAzDataTableEntity @CippConfigTable -Filter "PartitionKey eq 'InstanceProperties' and RowKey eq 'CIPPURL'"
- $CIPPURL = 'https://{0}' -f $CippConfig.Value
- foreach ($AuditLog in $DataToProcess) {
- Write-Information "Processing $($AuditLog.operation)"
- $Webhook = @{
- Data = $AuditLog
- CIPPURL = [string]$CIPPURL
- TenantFilter = $TenantFilter
- }
- try {
- Invoke-CippWebhookProcessing @Webhook
- } catch {
- Write-Warning "Error sending final step of auditlog processing: $($_.Exception.Message)"
- Write-Information $_.InvocationInfo.PositionMessage
+ if ($DataToProcess) {
+ $CippConfigTable = Get-CippTable -tablename Config
+ $CippConfig = Get-CIPPAzDataTableEntity @CippConfigTable -Filter "PartitionKey eq 'InstanceProperties' and RowKey eq 'CIPPURL'"
+ $CIPPURL = 'https://{0}' -f $CippConfig.Value
+ foreach ($AuditLog in $DataToProcess) {
+ Write-Information "Processing $($AuditLog.operation)"
+ $Webhook = @{
+ Data = $AuditLog
+ CIPPURL = [string]$CIPPURL
+ TenantFilter = $TenantFilter
+ }
+ try {
+ Invoke-CippWebhookProcessing @Webhook
+ } catch {
+ Write-Warning "Error sending final step of auditlog processing: $($_.Exception.Message)"
+ Write-Information $_.InvocationInfo.PositionMessage
+ }
}
}
- }
- try {
- Write-Information 'Removing processed rows from cache'
- foreach ($Row in $Rows) {
- if ($Row.id) {
- $RowEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Row.id)'"
- if ($RowEntity) {
- Remove-AzDataTableEntity @CacheWebhooksTable -Entity $RowEntity -Force
- Write-Information "Removed row $($Row.id) from cache at final pass."
+ try {
+ Write-Information 'Removing processed rows from cache'
+ foreach ($Row in $Rows) {
+ if ($Row.id) {
+ $RowEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Row.id)'"
+ if ($RowEntity) {
+ Remove-AzDataTableEntity @CacheWebhooksTable -Entity $RowEntity -Force
+ Write-Information "Removed row $($Row.id) from cache at final pass."
+ }
}
}
+ } catch {
+ Write-Information "Error removing rows from cache: $($_.Exception.Message)"
}
+
} catch {
- Write-Information "Error removing rows from cache: $($_.Exception.Message)"
+ Write-Warning "An error occurred during the Test-CIPPAuditLogRules execution: $($_.Exception.Message)"
+ Write-Information $_.InvocationInfo.PositionMessage
}
-
return $Results
}
diff --git a/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1 b/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1
index 971111aa4003..e387161ad89e 100644
--- a/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1
+++ b/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1
@@ -6,24 +6,28 @@ function New-BreachTenantSearch {
)
$Table = Get-CIPPTable -TableName UserBreaches
- $LatestBreach = Get-BreachInfo -TenantFilter $TenantFilter
+ $LatestBreach = Get-BreachInfo -TenantFilter $TenantFilter | Group-Object -Property clientDomain
$usersResults = foreach ($domain in $LatestBreach) {
- $ExistingBreaches = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$TenantFilter'"
- if ($null -eq $domain.result) {
- Write-Host "No breaches found for domain $($domain.domain)"
+ $ExistingBreaches = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($domain.name)'"
+ if ($null -eq $domain.Group) {
+ Write-Host "No breaches found for domain $($domain.name)"
continue
}
- $SumOfBreaches = ($LatestBreach | Measure-Object -Sum -Property found).sum
- if ($ExistingBreaches.sum -eq $SumOfBreaches -and $Force.IsPresent -eq $false) {
- Write-Host "No new breaches found for tenant $TenantFilter"
- continue
+ $SumOfBreaches = $domain.Count
+ if ($ExistingBreaches.sum -eq $SumOfBreaches) {
+ if ($Force.IsPresent -eq $true) {
+ Write-Host "Forcing update for tenant $TenantFilter"
+ } else {
+ Write-Host "No new breaches found for tenant $TenantFilter"
+ continue
+ }
}
@{
- RowKey = $domain.domain
+ RowKey = $domain.name
PartitionKey = $TenantFilter
- breaches = "$($LatestBreach.Result | ConvertTo-Json -Depth 10 -Compress)"
+ breaches = "$($domain.Group | ConvertTo-Json -Depth 10 -Compress)"
sum = $SumOfBreaches
}
}
@@ -32,7 +36,7 @@ function New-BreachTenantSearch {
if ($usersResults) {
try {
$null = Add-CIPPAzDataTableEntity @Table -Entity $usersResults -Force
- return $LatestBreach.Result
+ return $LatestBreach.Group
} catch {
Write-Error "Failed to add breaches to table: $($_.Exception.Message)"
return $null
diff --git a/version_latest.txt b/version_latest.txt
index 2bf50aaf17a6..56b6be4ebb2f 100644
--- a/version_latest.txt
+++ b/version_latest.txt
@@ -1 +1 @@
-8.3.0
+8.3.1