Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
194e4c6
remove redundant logging
kris6673 Oct 8, 2025
ed5be4d
Fix: error handling in Get-GraphToken to fix "Conversion from JSON fa…
kris6673 Oct 8, 2025
50d591e
Fix: change throw to return
kris6673 Oct 8, 2025
b862e05
We should get more than 1 user at a time...
Zacgoose Oct 9, 2025
3386990
Merge pull request #1669 from kris6673/fix-json-conversion-error
JohnDuprey Oct 9, 2025
8a6ebff
fixes
Zacgoose Oct 9, 2025
5d2b8f2
count for guests
Zacgoose Oct 9, 2025
63ac6f0
Update Invoke-ListUserCounts.ps1
Zacgoose Oct 9, 2025
66bc54c
changes
Zacgoose Oct 9, 2025
b29d20b
Merge pull request #1670 from Zacgoose/listuserpatch
JohnDuprey Oct 9, 2025
fb8f129
Fix: Remove deprecated option and refactor EDR assignment to not use …
kris6673 Oct 9, 2025
361ef55
Fix: improve error handling and logging in calendar and contact permi…
kris6673 Oct 9, 2025
ffc992f
fix endpoint
JohnDuprey Oct 10, 2025
7ba441a
Merge pull request #1667 from kris6673/addGroupLogging
JohnDuprey Oct 10, 2025
548f03d
Merge pull request #1671 from kris6673/defender-edr-assignment
JohnDuprey Oct 10, 2025
a049b92
Merge pull request #1672 from kris6673/exchange-page
JohnDuprey Oct 10, 2025
1afea25
Extension sync rescheduling support
JohnDuprey Oct 10, 2025
93cf530
fix package bug
JohnDuprey Oct 10, 2025
2297e4a
prevent package tags from being overwritten
JohnDuprey Oct 10, 2025
b8e37c2
ensure string values for gdap invite
JohnDuprey Oct 10, 2025
4357c79
fix task name
JohnDuprey Oct 10, 2025
dc2d4cf
improve ListTenants
JohnDuprey Oct 10, 2025
f25793c
remove null properties before deploying template
JohnDuprey Oct 10, 2025
bb69fa9
clean up .net 4.7.2 binaries to free up 20mb
JohnDuprey Oct 10, 2025
bcb820a
http graph rate limit throttle priority
JohnDuprey Oct 10, 2025
3c65460
capture response headers for rate limiting info
JohnDuprey Oct 10, 2025
dc2a278
up version
JohnDuprey Oct 10, 2025
38fe413
Merge pull request #1673 from KelvinTegelaar/dev
JohnDuprey Oct 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ function Invoke-ExecSetPackageTag {
if ($Remove -eq $true) {
# Remove package tag by setting it to null/empty
$PackageValue = $null
$LogMessage = "Successfully removed package tag from template with GUID"
$SuccessMessage = "Successfully removed package tag from template(s)"
$LogMessage = 'Successfully removed package tag from template with GUID'
$SuccessMessage = 'Successfully removed package tag from template(s)'
} else {
# Add package tag (existing logic)
$PackageValue = $Request.body.Package | Select-Object -First 1
$LogMessage = "Successfully updated template with GUID"
$PackageValue = [string]($Request.body.Package | Select-Object -First 1)
$LogMessage = 'Successfully updated template with GUID'
$SuccessMessage = "Successfully updated template(s) with package tag: $PackageValue"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ function Invoke-ListGraphRequest {

try {
$Results = Get-GraphRequestList @GraphRequestParams

if ($script:LastGraphResponseHeaders) {
$Metadata.GraphHeaders = $script:LastGraphResponseHeaders
}

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)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Function Invoke-ExecExtensionSync {
}
}
'Hudu' {
Register-CIPPExtensionScheduledTasks -Reschedule
Register-CIPPExtensionScheduledTasks -Reschedule -Extensions 'Hudu'
$Results = [pscustomobject]@{'Results' = 'Extension sync tasks have been rescheduled and will start within 15 minutes' }
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Function Invoke-ExecExtensionsConfig {
function Invoke-ExecExtensionsConfig {
<#
.FUNCTIONALITY
Entrypoint
Expand Down Expand Up @@ -27,6 +27,14 @@ Function Invoke-ExecExtensionsConfig {
}
}

if ($Body.Hudu.NextSync) {
#parse unixtime for addedtext
$Timestamp = [datetime]::UnixEpoch.AddSeconds([int]$Body.Hudu.NextSync).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
Register-CIPPExtensionScheduledTasks -Reschedule -NextSync $Body.Hudu.NextSync -Extensions 'Hudu'
$AddedText = " Next sync will be at $Timestamp."
$Body.Hudu.NextSync = ''
}

$Table = Get-CIPPTable -TableName Extensionsconfig
foreach ($APIKey in $Body.PSObject.Properties.Name) {
Write-Information "Working on $apikey"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,37 @@ function Invoke-ExecModifyCalPerms {
$APIName = $Request.Params.CIPPEndpoint
$Headers = $Request.Headers


# UPN of the mailbox to modify calendar permissions for
$Username = $Request.Body.userID

$TenantFilter = $Request.Body.tenantFilter
$Permissions = $Request.Body.permissions

Write-LogMessage -headers $Headers -API $APIName -message "Processing request for user: $Username, tenant: $TenantFilter" -Sev 'Debug'

if ($null -eq $Username) {
Write-LogMessage -headers $Headers -API $APIName -message 'Username is null' -Sev 'Error'
$body = [pscustomobject]@{'Results' = @('Username is required') }
if ([string]::IsNullOrWhiteSpace($Username)) {
Write-LogMessage -headers $Headers -API $APIName -message 'Username is null or whitespace' -Sev 'Error'
return ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::BadRequest
Body = $Body
Body = @{'Results' = @('Username is required') }
})
return
}

try {
$UserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)" -tenantid $TenantFilter).id
Write-LogMessage -headers $Headers -API $APIName -message "Retrieved user ID: $UserId" -Sev 'Debug'
try {
$UserId = [guid]$Username
} catch {
# If not a GUID, assume it's a UPN and look up the ID via Graph
$UserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)" -tenantid $TenantFilter).id
Write-LogMessage -headers $Headers -API $APIName -message "Retrieved user ID: $UserId" -Sev 'Debug'
}
} catch {
Write-LogMessage -headers $Headers -API $APIName -message "Failed to get user ID: $($_.Exception.Message)" -Sev 'Error'
$body = [pscustomobject]@{'Results' = @("Failed to get user ID: $($_.Exception.Message)") }
$ErrorMessage = Get-CippException -Exception $_
Write-LogMessage -headers $Headers -API $APIName -message "Failed to get user ID: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage
return ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::NotFound
Body = $Body
Body = @{'Results' = @("Failed to get user ID: $($ErrorMessage.NormalizedError)") }
})
return
}
Expand Down Expand Up @@ -91,24 +96,22 @@ function Invoke-ExecModifyCalPerms {
# Write-Host "Request params: $($Params | ConvertTo-Json)"
$Result = Set-CIPPCalendarPermission @Params

$null = $Results.Add($Result)
$Results.Add($Result)
} catch {
$HasErrors = $true
$null = $Results.Add("$($_.Exception.Message)")
$Results.Add("$($_.Exception.Message)")
}
}
}

if ($Results.Count -eq 0) {
Write-LogMessage -headers $Headers -API $APIName -message 'No results were generated from the operation' -Sev 'Warning'
$null = $Results.Add('No results were generated from the operation. Please check the logs for more details.')
$Results.Add('No results were generated from the operation. Please check the logs for more details.')
$HasErrors = $true
}

$Body = [pscustomobject]@{'Results' = @($Results) }

return ([HttpResponseContext]@{
StatusCode = if ($HasErrors) { [HttpStatusCode]::InternalServerError } else { [HttpStatusCode]::OK }
Body = $Body
Body = @{'Results' = @($Results) }
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,37 @@ function Invoke-ExecModifyContactPerms {
$APIName = $Request.Params.CIPPEndpoint
$Headers = $Request.Headers


# UPN of the mailbox to modify contact permissions for
$Username = $Request.Body.userID

$TenantFilter = $Request.Body.tenantFilter
$Permissions = $Request.Body.permissions

Write-LogMessage -headers $Headers -API $APIName -message "Processing request for user: $Username, tenant: $TenantFilter" -Sev 'Debug'

if ($null -eq $Username) {
Write-LogMessage -headers $Headers -API $APIName -message 'Username is null' -Sev 'Error'
$body = [pscustomobject]@{'Results' = @('Username is required') }
if ([string]::IsNullOrWhiteSpace($Username)) {
Write-LogMessage -headers $Headers -API $APIName -message 'Username is null or whitespace' -Sev 'Error'
return ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::BadRequest
Body = $Body
Body = @{'Results' = @('Username is required') }
})
return
}

try {
$UserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)" -tenantid $TenantFilter).id
Write-LogMessage -headers $Headers -API $APIName -message "Retrieved user ID: $UserId" -Sev 'Debug'
try {
$UserId = [guid]$Username
} catch {
# If not a GUID, assume it's a UPN and look up the ID via Graph
$UserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)" -tenantid $TenantFilter).id
Write-LogMessage -headers $Headers -API $APIName -message "Retrieved user ID: $UserId" -Sev 'Debug'
}
} catch {
Write-LogMessage -headers $Headers -API $APIName -message "Failed to get user ID: $($_.Exception.Message)" -Sev 'Error'
$body = [pscustomobject]@{'Results' = @("Failed to get user ID: $($_.Exception.Message)") }
$ErrorMessage = Get-CippException -Exception $_
Write-LogMessage -headers $Headers -API $APIName -message "Failed to get user ID: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage
return ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::NotFound
Body = $Body
Body = @{'Results' = @("Failed to get user ID: $($ErrorMessage.NormalizedError)") }
})
return
}
Expand Down Expand Up @@ -90,24 +95,23 @@ function Invoke-ExecModifyContactPerms {
# Write-Host "Request params: $($Params | ConvertTo-Json)"
$Result = Set-CIPPContactPermission @Params

$null = $Results.Add($Result)
$Results.Add($Result)
} catch {
$HasErrors = $true
$null = $Results.Add("$($_.Exception.Message)")
$Results.Add("$($_.Exception.Message)")
}
}
}

if ($Results.Count -eq 0) {
Write-LogMessage -headers $Headers -API $APIName -message 'No results were generated from the operation' -Sev 'Warning'
$null = $Results.Add('No results were generated from the operation. Please check the logs for more details.')
$Results.Add('No results were generated from the operation. Please check the logs for more details.')
$HasErrors = $true
}

$Body = [pscustomobject]@{'Results' = @($Results) }

return ([HttpResponseContext]@{
StatusCode = if ($HasErrors) { [HttpStatusCode]::InternalServerError } else { [HttpStatusCode]::OK }
Body = $Body
Body = @{'Results' = @($Results) }
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ function Invoke-AddTransportRule {

$RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications

# Remove null properties from payload
$RequestParams.PSObject.Properties | Where-Object { $_.Value -eq $null } | ForEach-Object { $RequestParams.PSObject.Properties.Remove($_.Name) }

$Tenants = ($Request.body.selectedTenants).value

$AllowedTenants = Test-CippAccess -Request $Request -TenantList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,22 +228,7 @@ function Invoke-AddDefenderDeployment {
}
}
}
{ $_.Telemetry } {
@{
'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'
settingInstance = @{
'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'
settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_telemetryreportingfrequency'
choiceSettingValue = @{
settingValueTemplateReference = @{settingValueTemplateId = '350b0bea-b67b-43d4-9a04-c796edb961fd' }
'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'
'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_telemetryreportingfrequency_2'
}
settingInstanceTemplateReference = @{settingInstanceTemplateId = '03de6095-07c4-4f35-be38-c1cd3bae4484' }
}
}

}
{ $_.Config } {
@{
'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'
Expand Down Expand Up @@ -279,10 +264,11 @@ function Invoke-AddDefenderDeployment {
"$($tenant): EDR Policy already exists. Skipping"
} else {
$EDRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $EDRbody
if ($ASR -and $ASR.AssignTo -ne 'none') {
$AssignBody = if ($ASR.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($asr.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' }
# Assign if needed
if ($EDR.AssignTo -and $EDR.AssignTo -ne 'none') {
$AssignBody = if ($EDR.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($EDR.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' }
$null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($EDRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody
Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenant) -message "Assigned EDR policy $($DisplayName) to $($ASR.AssignTo)" -Sev 'Info'
Write-LogMessage -headers $Headers -API $APIName -tenant $($tenant) -message "Assigned EDR policy $($DisplayName) to $($EDR.AssignTo)" -Sev 'Info'
}
"$($tenant): Successfully added EDR Settings"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ function Invoke-AddGroup {

$APIName = $Request.Params.CIPPEndpoint
$SelectedTenants = if ('AllTenants' -in $SelectedTenants) { (Get-Tenants).defaultDomainName } else { $Request.body.tenantFilter.value ? $Request.body.tenantFilter.value : $Request.body.tenantFilter }
Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev Debug


$GroupObject = $Request.body
Expand All @@ -28,7 +27,6 @@ function Invoke-AddGroup {
}
} catch {
$ErrorMessage = Get-CippException -Exception $_
Write-LogMessage -headers $Request.Headers -API $APIName -tenant $tenant -message "Group creation API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage
"Failed to create group. $($GroupObject.displayName) for $($tenant) $($ErrorMessage.NormalizedError)"
$StatusCode = [HttpStatusCode]::InternalServerError
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ function Invoke-AddUser {
$UserObj = $Request.Body

if ($UserObj.Scheduled.Enabled) {
$Username = $UserObj.username ?? $UserObj.mailNickname
$TaskBody = [pscustomobject]@{
TenantFilter = $UserObj.tenantFilter
Name = "New user creation: $($UserObj.mailNickname)@$($UserObj.PrimDomain.value)"
Name = "New user creation: $($Username)@$($UserObj.PrimDomain.value)"
Command = @{
value = 'New-CIPPUserTask'
label = 'New-CIPPUserTask'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,48 +22,48 @@ Function Invoke-ListUserCounts {
@{
id = 'Users'
method = 'GET'
url = "/users?`$count=true&`$top=1"
url = "/users/`$count"
headers = @{
'ConsistencyLevel' = 'eventual'
}
}
@{
id = 'LicUsers'
method = 'GET'
url = "/users?`$count=true&`$top=1&`$filter=assignedLicenses/`$count ne 0"
url = "/users/`$count?`$top=1&`$filter=assignedLicenses/`$count ne 0"
headers = @{
'ConsistencyLevel' = 'eventual'
}
}
@{
id = 'GAs'
method = 'GET'
url = "/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members?`$count=true"
url = "/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members/`$count"
headers = @{
'ConsistencyLevel' = 'eventual'
}
}
@{
id = 'Guests'
method = 'GET'
url = "/users?`$count=true&`$top=1&`$filter=userType eq 'Guest'"
url = "/users/`$count?`$top=1&`$filter=userType eq 'Guest'"
headers = @{
'ConsistencyLevel' = 'eventual'
}
}
)

# Execute bulk request
$BulkResults = New-GraphBulkRequest -Requests @($BulkRequests) -tenantid $TenantFilter @('Users', 'LicUsers', 'GAs', 'Guests')
$BulkResults = New-GraphBulkRequest -Requests @($BulkRequests) -noPaginateIds @('LicUsers') -tenantid $TenantFilter @('Users', 'LicUsers', 'GAs', 'Guests')

# Check if any requests failed
$FailedRequests = $BulkResults | Where-Object { $_.status -ne 200 }

if ($FailedRequests) {
# If any requests failed, return an error response
$FailedIds = ($FailedRequests | ForEach-Object { $_.id }) -join ', '
$ErrorMessage = "Failed to retrieve counts for: $FailedIds"

return ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::InternalServerError
Body = @{
Expand All @@ -75,13 +75,13 @@ Function Invoke-ListUserCounts {

# All requests succeeded, extract the counts
$BulkResults | ForEach-Object {
$Count = $_.body.'@odata.count'
$UsersCount = $_.body

switch ($_.id) {
'Users' { $Users = $Count }
'LicUsers' { $LicUsers = $Count }
'GAs' { $GAs = $Count }
'Guests' { $Guests = $Count }
'Users' { $Users = $UsersCount }
'LicUsers' { $LicUsers = $UsersCount }
'GAs' { $GAs = $UsersCount }
'Guests' { $Guests = $UsersCount }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ function New-CippCoreRequest {
}

if ($PSCmdlet.ShouldProcess("Processing request for $($Request.Params.CIPPEndpoint)")) {
# Set script scope variables for Graph API to indicate HTTP request/high priority
$script:XMsThrottlePriority = 'high'

if ((Get-Command -Name $FunctionName -ErrorAction SilentlyContinue) -or $FunctionName -eq 'Invoke-Me') {
try {
$Access = Test-CIPPAccess -Request $Request
Expand Down
Loading