diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 2e0ad55e9807..9dbddea96dbc 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -12,6 +12,8 @@ function Test-CIPPAccess { # Check help for role $APIRole = $Help.Role + $AnyTenantAllowedFunctions = @('ListTenants', 'ListUserSettings', 'ListUserPhoto', 'GetCippAlerts', 'GetVersion') + if ($Request.Headers.'x-ms-client-principal-idp' -eq 'aad' -and $Request.Headers.'x-ms-client-principal-name' -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}$') { # Direct API Access $ForwardedFor = $Request.Headers.'x-forwarded-for' -split ',' | Select-Object -First 1 @@ -106,13 +108,14 @@ function Test-CIPPAccess { } if ($APIAllowed) { + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter ?? $env:TenantID # Check tenant level access if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') { $TenantAllowed = $true - } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { + } elseif ($TenantFilter -eq 'AllTenants') { $TenantAllowed = $false } else { - $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId + $Tenant = ($Tenants | Where-Object { $TenantFilter -eq $_.customerId -or $TenantFilter -eq $_.defaultDomainName }).customerId if ($Role.AllowedTenants -contains 'AllTenants') { $AllowedTenants = $Tenants.customerId } else { @@ -132,7 +135,7 @@ function Test-CIPPAccess { if (!$APIAllowed) { throw "Access to this CIPP API endpoint is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" } - if (!$TenantAllowed) { + if (!$TenantAllowed -and $AnyTenantAllowedFunctions -notcontains $Request.Params.CIPPEndpoint) { throw 'Access to this tenant is not allowed' } else { return $true diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 index a116159aba13..6249f4cde350 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 @@ -39,7 +39,8 @@ function Push-ListGraphRequestQueue { } $RawGraphRequest = try { - Get-GraphRequestList @GraphRequestParams + $Results = Get-GraphRequestList @GraphRequestParams + $Results | Select-Object -First ($Results.Count - 1) } catch { $CippException = Get-CippException -Exception $_.Exception [PSCustomObject]@{ @@ -57,6 +58,7 @@ function Push-ListGraphRequestQueue { Data = [string]$Json } Add-CIPPAzDataTableEntity @Table -Entity $GraphResults -Force | Out-Null + return $true } catch { Write-Warning "Queue Error: $($_.Exception.Message)" #Write-Information ($GraphResults | ConvertTo-Json -Depth 10 -Compress) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 index eacfe5b53646..c264c87ea898 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 @@ -15,7 +15,7 @@ Function Invoke-ExecSetCIPPAutoBackup { Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $unixtime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds - if ($Request.Body.Enabled -eq 'True') { + if ($Request.Body.Enabled -eq $true) { $Table = Get-CIPPTable -TableName 'ScheduledTasks' $AutomatedCIPPBackupTask = Get-AzDataTableEntity @table -Filter "Name eq 'Automated CIPP Backup'" $task = @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 index 045d9e55d818..bd36ddb9462c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 @@ -15,10 +15,12 @@ function Invoke-ListGraphBulkRequest { $TenantFilter = $Request.Body.tenantFilter $AsApp = $Request.Body.asApp $Requests = $Request.Body.requests + $NoPaginateIds = $Request.Body.noPaginateIds $GraphRequestParams = @{ tenantid = $TenantFilter Requests = @() + NoPaginateIds = $NoPaginateIds ?? @() } if ($AsApp) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 index 01f7a7d1f2c0..99faf0266fef 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 @@ -44,7 +44,6 @@ Function Invoke-ListScheduledItems { } $Tasks = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Hidden -ne $HiddenTasks } if ($Type) { - $Tasks.Command $Tasks = $Tasks | Where-Object { $_.command -eq $Type } } @@ -61,13 +60,16 @@ Function Invoke-ListScheduledItems { } else { $Task | Add-Member -NotePropertyName Parameters -NotePropertyValue @{} } + if ($Task.Recurrence -eq 0 -or [string]::IsNullOrEmpty($Task.Recurrence)) { + $Task.Recurrence = 'Once' + } $Task } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @($ScheduledTasks) + Body = @($ScheduledTasks | Sort-Object -Property ExecutedTime -Descending) }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 index e926564f1f4f..ebd8ee39f7a6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 @@ -10,8 +10,8 @@ Function Invoke-ExecHideFromGAL { [CmdletBinding()] param($Request, $TriggerMetadata) - $Headers = $Request.Headers $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' @@ -22,19 +22,17 @@ Function Invoke-ExecHideFromGAL { $HideFromGAL = [System.Convert]::ToBoolean($HideFromGAL) Try { - $HideResults = Set-CIPPHideFromGAL -tenantFilter $TenantFilter -UserID $UserId -hidefromgal $Hidden -Headers $Request.Headers -APIName $APIName - $Results = [pscustomobject]@{'Results' = $HideResults } + $Result = Set-CIPPHideFromGAL -tenantFilter $TenantFilter -UserID $UserId -hidefromgal $HideFromGAL -Headers $Headers -APIName $APIName $StatusCode = [HttpStatusCode]::OK } catch { - $ErrorMessage = Get-CippException -Exception $_ - $Results = [pscustomobject]@{'Results' = "Failed. $($ErrorMessage.NormalizedError)" } + $Result = $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = $Results + Body = @{ 'Results' = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 index 6a03af82ed65..86c26f5daf33 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 @@ -24,7 +24,6 @@ Function Invoke-ExecStartManagedFolderAssistant { $ExoParams = @{ Identity = $Identity - AggMailboxCleanup = $true FullCrawl = $true } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 index deb836716d5d..89111ef324c8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 @@ -11,10 +11,11 @@ Function Invoke-ListMailboxes { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $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. - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Query.tenantFilter try { $Select = 'id,ExchangeGuid,ArchiveGuid,UserPrincipalName,DisplayName,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses,WhenSoftDeleted,IsInactiveMailbox,ForwardingSmtpAddress,DeliverToMailboxAndForward,ForwardingAddress,HiddenFromAddressListsEnabled,ExternalDirectoryObjectId,MessageCopyForSendOnBehalfEnabled,MessageCopyForSentAsEnabled' $ExoRequest = @{ @@ -32,6 +33,7 @@ Function Invoke-ListMailboxes { @{Parameter = 'PublicFolder'; Type = 'Bool' } @{Parameter = 'RecipientTypeDetails'; Type = 'String' } @{Parameter = 'SoftDeletedMailbox'; Type = 'Bool' } + @{Parameter = 'Identity'; Type = 'String' } ) foreach ($Param in $Request.Query.PSObject.Properties.Name) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 index a54285faeef4..dd44396c9b43 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 @@ -43,6 +43,16 @@ Function Invoke-ListIntunePolicy { method = 'GET' url = "/deviceManagement/windowsFeatureUpdateProfiles?`$expand=assignments&top=200" } + @{ + id = 'windowsQualityUpdatePolicies' + method = 'GET' + url = "/deviceManagement/windowsQualityUpdatePolicies?`$expand=assignments&top=200" + } + @{ + id = 'windowsQualityUpdateProfiles' + method = 'GET' + url = "/deviceManagement/windowsQualityUpdateProfiles?`$expand=assignments&top=200" + } @{ id = 'GroupPolicyConfigurations' method = 'GET' @@ -78,6 +88,11 @@ Function Invoke-ListIntunePolicy { '*microsoft.graph.macOSEndpointProtectionConfiguration*' { 'MacOS Endpoint Protection' } '*microsoft.graph.androidWorkProfileGeneralDeviceConfiguration*' { 'Android Configuration' } '*windowsFeatureUpdateProfiles*' { 'Feature Update' } + '*windowsQualityUpdatePolicies*' { 'Quality Update' } + '*windowsQualityUpdateProfiles*' { 'Quality Update' } + '*iosUpdateConfiguration*' { 'iOS Update Configuration' } + '*windowsDriverUpdateProfiles*' { 'Driver Update' } + '*configurationPolicies*' { 'Device Configuration' } default { $_.'assignments@odata.context' } } $Assignments = $_.assignments.target | Select-Object -Property '@odata.type', groupId diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 index d2b0e4efce53..d22cca0f8e9e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 @@ -1,47 +1,47 @@ -function Invoke-ExecDismissRiskyUser { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Identity.User.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $Headers = $Request.Headers - Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - - # Interact with the query or body of the request - $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter - $SuspectUser = $Request.Query.userId ?? $Request.Body.userId - $userDisplayName = $Request.Query.userDisplayName ?? $Request.Body.userDisplayName - - $GraphRequest = @{ - 'uri' = 'https://graph.microsoft.com/beta/riskyUsers/dismiss' - 'tenantid' = $TenantFilter - 'type' = 'POST' - 'contentType' = 'application/json; charset=utf-8' - 'body' = @{ - 'userIds' = @($SuspectUser) - } | ConvertTo-Json - } - - try { - $GraphResults = New-GraphPostRequest @GraphRequest - Write-LogMessage -API $APIName -tenant $TenantFilter -message "Dismissed user risk for $userDisplayName" -sev 'Info' - $Result = "Successfully dismissed User Risk for user $userDisplayName. $GraphResults" - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-CippException -Exception $_ - $Result = "Failed to dismiss user risk for $userDisplayName. $($ErrorMessage.NormalizedError)" - Write-LogMessage -API $APIName -tenant $TenantFilter -message $Result -sev 'Error' -LogData $ErrorMessage - $StatusCode = [HttpStatusCode]::InternalServerError - } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @{ 'Results' = $Result } - }) -} +function Invoke-ExecDismissRiskyUser { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.User.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with the query or body of the request + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $SuspectUser = $Request.Query.userId ?? $Request.Body.userId + $userDisplayName = $Request.Query.userDisplayName ?? $Request.Body.userDisplayName + + $GraphRequest = @{ + 'uri' = 'https://graph.microsoft.com/beta/riskyUsers/dismiss' + 'tenantid' = $TenantFilter + 'type' = 'POST' + 'contentType' = 'application/json; charset=utf-8' + 'body' = @{ + 'userIds' = @($SuspectUser) + } | ConvertTo-Json + } + + try { + $GraphResults = New-GraphPostRequest @GraphRequest + Write-LogMessage -API $APIName -tenant $TenantFilter -message "Dismissed user risk for $userDisplayName" -sev 'Info' + $Result = "Successfully dismissed User Risk for user $userDisplayName. $GraphResults" + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to dismiss user risk for $userDisplayName. $($ErrorMessage.NormalizedError)" + Write-LogMessage -API $APIName -tenant $TenantFilter -message $Result -sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ 'Results' = $Result } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 index cac7e39d7514..9f3d7a4f9092 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 @@ -183,7 +183,20 @@ Function Invoke-ListUserMailboxDetails { AutoExpandingArchive = $AutoExpandingArchiveEnabled RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails Mailbox = $MailboxDetailedRequest - } + MailboxActionsData = ($MailboxDetailedRequest | Select-Object id, ExchangeGuid, ArchiveGuid, WhenSoftDeleted, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, + @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, + @{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } }, + @{ Name = 'recipientType'; Expression = { $_.'RecipientType' } }, + @{ Name = 'recipientTypeDetails'; Expression = { $_.'RecipientTypeDetails' } }, + @{ Name = 'AdditionalEmailAddresses'; Expression = { ($_.'EmailAddresses' | Where-Object { $_ -clike 'smtp:*' }).Replace('smtp:', '') -join ', ' } }, + @{Name = 'ForwardingSmtpAddress'; Expression = { $_.'ForwardingSmtpAddress' -replace 'smtp:', '' } }, + @{Name = 'InternalForwardingAddress'; Expression = { $_.'ForwardingAddress' } }, + DeliverToMailboxAndForward, + HiddenFromAddressListsEnabled, + ExternalDirectoryObjectId, + MessageCopyForSendOnBehalfEnabled, + MessageCopyForSentAsEnabled) + } # Select statement taken from ListMailboxes to save a EXO request Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 index 1d24bf7e2ddd..cd84ca1057b1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 @@ -18,8 +18,9 @@ Function Invoke-ListBPATemplates { $Table = Get-CippTable -tablename 'templates' $Templates = Get-ChildItem 'Config\*.BPATemplate.json' | ForEach-Object { + $TemplateJson = Get-Content $_ | ConvertFrom-Json | ConvertTo-Json -Compress -Depth 10 $Entity = @{ - JSON = "$(Get-Content $_)" + JSON = "$TemplateJson" RowKey = "$($_.name)" PartitionKey = 'BPATemplate' GUID = "$($_.name)" @@ -31,10 +32,14 @@ Function Invoke-ListBPATemplates { $Templates = Get-CIPPAzDataTableEntity @Table -Filter $Filter if ($Request.Query.RawJson) { + foreach ($Template in $Templates) { + $Template.JSON = $Template.JSON -replace '"parameters":', '"Parameters":' + } $Templates = $Templates.JSON | ConvertFrom-Json } else { $Templates = $Templates | ForEach-Object { - $Template = $_.JSON | ConvertFrom-Json + $TemplateJson = $_.JSON -replace '"parameters":', '"Parameters":' + $Template = $TemplateJson | ConvertFrom-Json @{ GUID = $_.GUID Data = $Template.fields diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 index 011839ad6364..514473f084a6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 @@ -18,7 +18,7 @@ Function Invoke-AddBPATemplate { $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ - JSON = "$($Request.body | ConvertTo-Json -Depth 10)" + JSON = "$($Request.body | ConvertTo-Json -Depth 10 -Compress)" RowKey = $Request.body.name PartitionKey = 'BPATemplate' GUID = $Request.body.name diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 index 6753e0053477..2036ff01b2c6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 @@ -14,13 +14,19 @@ Function Invoke-ListCSPsku { Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.Query.tenantFilter - if ($Request.Query.currentSkuOnly) { - $GraphRequest = Get-SherwebCurrentSubscription -TenantFilter $TenantFilter - } else { - $GraphRequest = Get-SherwebCatalog -TenantFilter $TenantFilter + try { + if ($Request.Query.currentSkuOnly) { + $GraphRequest = Get-SherwebCurrentSubscription -TenantFilter $TenantFilter + } else { + $GraphRequest = Get-SherwebCatalog -TenantFilter $TenantFilter + } + } catch { + $GraphRequest = [PSCustomObject]@{ + name = @(@{value = 'Error getting catalog' }) + sku = $_.Exception.Message + } } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @($GraphRequest) diff --git a/Modules/CIPPCore/Public/Get-CIPPLAPSPassword.ps1 b/Modules/CIPPCore/Public/Get-CIPPLAPSPassword.ps1 index e7fa518f0b7b..4f007009a130 100644 --- a/Modules/CIPPCore/Public/Get-CIPPLAPSPassword.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPLAPSPassword.ps1 @@ -12,7 +12,11 @@ function Get-CIPPLapsPassword { $GraphRequest = (New-GraphGetRequest -noauthcheck $true -uri "https://graph.microsoft.com/beta/directory/deviceLocalCredentials/$($device)?`$select=credentials" -tenantid $TenantFilter).credentials | Select-Object -First 1 | ForEach-Object { $PlainText = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($_.passwordBase64)) $date = $_.BackupDateTime - "The password for $($_.AccountName) is $($PlainText) generated at $($date)" + [PSCustomObject]@{ + resultText = "LAPS password retrieved, generated at $($date). Copy the password by clicking the copy button" + copyField = $PlainText + state = 'success' + } } if ($GraphRequest) { return $GraphRequest } else { return "No LAPS password found for $device" } } catch { diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 index dcdb0a3ae7a0..01935a2928fa 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 @@ -31,7 +31,7 @@ function New-ExoRequest { [Parameter(ParameterSetName = 'AvailableCmdlets')] [switch]$AvailableCmdlets, - $ModuleVersion = '3.5.1', + $ModuleVersion = '3.7.1', [switch]$AsApp ) if ((Get-AuthorisedRequest -TenantID $tenantid) -or $NoAuthCheck -eq $True) { diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 index d0502b973082..de474b22f1f7 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 @@ -8,7 +8,8 @@ function New-GraphBulkRequest { $NoAuthCheck, $scope, $asapp, - $Requests + $Requests, + $NoPaginateIds = @() ) if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { @@ -43,6 +44,9 @@ function New-GraphBulkRequest { $Return } foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) { + if ($NoPaginateIds -contains $MoreData.id) { + continue + } Write-Host 'Getting more' Write-Host $MoreData.body.'@odata.nextLink' $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck $NoAuthCheck -scope $scope -AsApp $asapp diff --git a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 index 9e67a03f1ba0..4727cbe71914 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 @@ -40,7 +40,7 @@ function New-CIPPBackup { $Table = Get-CippTable -tablename 'CIPPBackup' try { if ($PSCmdlet.ShouldProcess('CIPP Backup', 'Create')) { - $Result = Add-CIPPAzDataTableEntity @Table -Entity $entity -Force + $null = Add-CIPPAzDataTableEntity @Table -Entity $entity -Force Write-LogMessage -headers $Headers -API $APINAME -message 'Created CIPP Backup' -Sev 'Debug' } } catch { @@ -66,21 +66,24 @@ function New-CIPPBackup { RowKey = $RowKey TenantFilter = $TenantFilter } - Write-Host "Scheduled backup value psproperties: $(([pscustomobject]$ScheduledBackupValues).psobject.Properties)" + Write-Information "Scheduled backup value psproperties: $(([pscustomobject]$ScheduledBackupValues).psobject.Properties)" foreach ($ScheduledBackup in ([pscustomobject]$ScheduledBackupValues).psobject.Properties.Name) { - $BackupResult = New-CIPPBackupTask -Task $ScheduledBackup -TenantFilter $TenantFilter | ConvertTo-Json -Depth 100 -Compress | Out-String - $entity[$ScheduledBackup] = "$BackupResult" + try { + $BackupResult = New-CIPPBackupTask -Task $ScheduledBackup -TenantFilter $TenantFilter | ConvertTo-Json -Depth 100 -Compress | Out-String + $entity[$ScheduledBackup] = "$BackupResult" + } catch { + Write-Information "Failed to create backup for $ScheduledBackup - $($_.Exception.Message)" + } } $Table = Get-CippTable -tablename 'ScheduledBackup' try { - $Result = Add-CIPPAzDataTableEntity @Table -entity $entity -Force + $null = Add-CIPPAzDataTableEntity @Table -entity $entity -Force Write-LogMessage -headers $Headers -API $APINAME -message 'Created backup' -Sev 'Debug' $State = 'Backup finished succesfully' - $Result } catch { $State = 'Failed to write backup to table storage' $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APINAME -message "Failed to create backup for Conditional Access Policies: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + Write-LogMessage -headers $Headers -API $APINAME -message "Failed to create tenant backup: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage [pscustomobject]@{'Results' = "Backup Creation failed: $($ErrorMessage.NormalizedError)" } } } diff --git a/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 b/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 index 142958410cfd..05f2b0added7 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 @@ -23,7 +23,7 @@ function New-CIPPBackupTask { } 'ca' { Write-Host "Backup Conditional Access Policies for $TenantFilter" - $Policies = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/conditionalAccess/policies?$top=999' -tenantid $TenantFilter + $Policies = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/conditionalAccess/policies?$top=999' -tenantid $TenantFilter -AsApp $true Write-Host 'Creating templates for found Conditional Access Policies' foreach ($policy in $policies) { try { @@ -40,6 +40,9 @@ function New-CIPPBackupTask { "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=999" "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' + 'https://graph.microsoft.com/beta/deviceManagement/windowsFeatureUpdateProfiles' + 'https://graph.microsoft.com/beta/deviceManagement/windowsQualityUpdatePolicies' + 'https://graph.microsoft.com/beta/deviceManagement/windowsQualityUpdateProfiles' ) $Policies = foreach ($url in $GraphURLS) { @@ -129,13 +132,6 @@ function New-CIPPBackupTask { $ScheduledTasks = Get-CIPPTable -TableName 'ScheduledTasks' Get-CIPPAzDataTableEntity @ScheduledTasks | Where-Object { $_.hidden -eq $true -and $_.command -like 'Get-CippAlert*' -and $TenantFilter -in $_.Tenant } } - 'CippStandards' { - Write-Host "Backup Standards for $TenantFilter" - $Table = Get-CippTable -tablename 'standards' - $Filter = "PartitionKey eq 'standards' and RowKey eq '$($TenantFilter)'" - (Get-CIPPAzDataTableEntity @Table -Filter $Filter) - } - } return $BackupData } diff --git a/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 index 6b89083b332b..452e81574db6 100644 --- a/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 @@ -103,6 +103,18 @@ function New-CIPPIntuneTemplate { $DisplayName = $Template.displayName $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress } + 'windowsQualityUpdatePolicies' { + $Type = 'windowsQualityUpdatePolicies' + $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)/$($ID)" -tenantid $tenantfilter | Select-Object * -ExcludeProperty id, lastModifiedDateTime, '@odata.context', 'ScopeTagIds', 'supportsScopeTags', 'createdDateTime' + $DisplayName = $Template.displayName + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress + } + 'windowsQualityUpdateProfiles' { + $Type = 'windowsQualityUpdateProfiles' + $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)/$($ID)" -tenantid $tenantfilter | Select-Object * -ExcludeProperty id, lastModifiedDateTime, '@odata.context', 'ScopeTagIds', 'supportsScopeTags', 'createdDateTime' + $DisplayName = $Template.displayName + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress + } } return [PSCustomObject]@{ TemplateJson = $TemplateJson diff --git a/Modules/CIPPCore/Public/New-CIPPRestore.ps1 b/Modules/CIPPCore/Public/New-CIPPRestore.ps1 index 484b6178199c..52042e261780 100644 --- a/Modules/CIPPCore/Public/New-CIPPRestore.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPRestore.ps1 @@ -11,7 +11,7 @@ function New-CIPPRestore { Write-Host "Scheduled Restore psproperties: $(([pscustomobject]$RestoreValues).psobject.Properties)" Write-LogMessage -headers $Headers -API $APINAME -message 'Restored backup' -Sev 'Debug' $RestoreData = foreach ($ScheduledBackup in ([pscustomobject]$RestoreValues).psobject.Properties.Name | Where-Object { $_ -notin 'email', 'webhook', 'psa', 'backup', 'overwrite' }) { - New-CIPPRestoreTask -Task $ScheduledBackup -TenantFilter $TenantFilter -backup $RestoreValues.backup.value -overwrite $RestoreValues.overwrite -Headers $Headers -APIName $APIName + New-CIPPRestoreTask -Task $ScheduledBackup -TenantFilter $TenantFilter -backup $RestoreValues.backup -overwrite $RestoreValues.overwrite -Headers $Headers -APIName $APIName } return $RestoreData } diff --git a/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 b/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 index 3f4a3bc2a6cb..a16760daf7ce 100644 --- a/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 @@ -479,7 +479,6 @@ function New-CIPPRestoreTask { } } } - 'CippWebhookAlerts' { Write-Host "Restore Webhook Alerts for $TenantFilter" $WebhookTable = Get-CIPPTable -TableName 'WebhookRules' @@ -502,18 +501,6 @@ function New-CIPPRestoreTask { "Could not restore Scripted Alerts $ErrorMessage " } } - 'CippStandards' { - Write-Host "Restore Standards for $TenantFilter" - $Table = Get-CippTable -tablename 'standards' - $StandardsBackup = $BackupData.CippStandards | ConvertFrom-Json - try { - Add-CIPPAzDataTableEntity @Table -Entity $StandardsBackup -Force - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - "Could not restore Standards $ErrorMessage " - } - } - } return $RestoreData } diff --git a/Modules/CIPPCore/Public/New-CIPPTemplateRun.ps1 b/Modules/CIPPCore/Public/New-CIPPTemplateRun.ps1 index ba6144f6b69d..1c10bda343be 100644 --- a/Modules/CIPPCore/Public/New-CIPPTemplateRun.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPTemplateRun.ps1 @@ -90,6 +90,9 @@ function New-CIPPTemplateRun { "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=999" "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' + 'https://graph.microsoft.com/beta/deviceManagement/windowsFeatureUpdateProfiles' + 'https://graph.microsoft.com/beta/deviceManagement/windowsQualityUpdatePolicies' + 'https://graph.microsoft.com/beta/deviceManagement/windowsQualityUpdateProfiles' ) $Policies = foreach ($url in $GraphURLS) { diff --git a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 index 173a37b874a9..49c40c9c6c4a 100644 --- a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 @@ -122,6 +122,8 @@ function Set-CIPPIntunePolicy { $DisplayName = ($RawJSON | ConvertFrom-Json).Name $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($DisplayName -in $CheckExististing.name) { + $PolicyFile = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty Platform, PolicyType, CreationSource + $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 100 -Compress $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $DisplayName $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property Name -EQ $DisplayName @@ -140,11 +142,12 @@ function Set-CIPPIntunePolicy { $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($DisplayName -in $CheckExististing.displayName) { $PostType = 'edited' + $PolicyFile = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty inventorySyncStatus, newUpdates, deviceReporting, approvalType + $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 100 -Compress $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname Write-Host 'We are editing' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName - } else { $PostType = 'added' $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON @@ -159,9 +162,11 @@ function Set-CIPPIntunePolicy { $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($DisplayName -in $CheckExististing.displayName) { $PostType = 'edited' + $PolicyFile = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty deployableContentDisplayName, endOfSupportDate, installLatestWindows10OnWindows11IneligibleDevice + $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 100 -Compress $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname Write-Host 'We are editing' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName } else { @@ -170,7 +175,46 @@ function Set-CIPPIntunePolicy { Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } - + 'windowsQualityUpdatePolicies' { + $PlatformType = 'deviceManagement' + $TemplateTypeURL = 'windowsQualityUpdatePolicies' + $File = ($RawJSON | ConvertFrom-Json) + $DisplayName = $File.displayName ?? $File.Name + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter + if ($DisplayName -in $CheckExististing.displayName) { + $PostType = 'edited' + $PolicyFile = $RawJSON | ConvertFrom-Json | Select-Object * + $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 100 -Compress + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname + Write-Host 'We are editing' + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName + } else { + $PostType = 'added' + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' + } + } + 'windowsQualityUpdateProfiles' { + $PlatformType = 'deviceManagement' + $TemplateTypeURL = 'windowsQualityUpdateProfiles' + $File = ($RawJSON | ConvertFrom-Json) + $DisplayName = $File.displayName ?? $File.Name + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter + if ($DisplayName -in $CheckExististing.displayName) { + $PostType = 'edited' + $PolicyFile = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty releaseDateDisplayName, deployableContentDisplayName + $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 100 -Compress + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname + Write-Host 'We are editing' + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName + } else { + $PostType = 'added' + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' + } + } } Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "$($PostType) policy $($Displayname)" -Sev 'Info' if ($AssignTo) { diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 53417bacbeab..58cf21e284ee 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -17,16 +17,16 @@ function Get-CIPPStandards { $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'StandardsTemplateV2'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | - ForEach-Object { - try { - # Fix old "Action" => "action" - $JSON = $_ -replace '"Action":', '"action":' - ConvertFrom-Json -InputObject $JSON -ErrorAction SilentlyContinue - } catch {} - } | - Where-Object { - $_.GUID -like $TemplateId -and $_.runManually -eq $runManually - } + ForEach-Object { + try { + # Fix old "Action" => "action" + $JSON = $_ -replace '"Action":', '"action":' -replace '"permissionlevel":', '"permissionLevel":' + ConvertFrom-Json -InputObject $JSON -ErrorAction SilentlyContinue + } catch {} + } | + Where-Object { + $_.GUID -like $TemplateId -and $_.runManually -eq $runManually + } # 2. Get tenant list, filter if needed $AllTenantsList = Get-Tenants diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 index c36603c329b4..ca72eac437d5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 @@ -47,8 +47,9 @@ function Invoke-CIPPStandardGroupTemplate { 'mailNickname' = $groupobj.username mailEnabled = [bool]$false securityEnabled = [bool]$true - isAssignableToRole = [bool]($groupobj | Where-Object -Property groupType -EQ 'AzureRole') - + } + if ($groupobj.groupType -eq 'AzureRole') { + $BodyToship | Add-Member -NotePropertyName 'isAssignableToRole' -NotePropertyValue $true } if ($groupobj.membershipRules) { $BodyToship | Add-Member -NotePropertyName 'membershipRule' -NotePropertyValue ($groupobj.membershipRules) @@ -56,6 +57,7 @@ function Invoke-CIPPStandardGroupTemplate { $BodyToship | Add-Member -NotePropertyName 'membershipRuleProcessingState' -NotePropertyValue 'On' } if (!$CheckExististing) { + $ActionType = 'create' if ($groupobj.groupType -in 'Generic', 'azurerole', 'dynamic') { $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenant -type POST -body (ConvertTo-Json -InputObject $BodyToship -Depth 10) -verbose } else { @@ -80,6 +82,7 @@ function Invoke-CIPPStandardGroupTemplate { } Write-LogMessage -API 'Standards' -tenant $tenant -message "Created group $($groupobj.displayname) with id $($GraphRequest.id) " -Sev 'Info' } else { + $ActionType = 'update' if ($groupobj.groupType -in 'Generic', 'azurerole', 'dynamic') { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($CheckExististing.id)" -tenantid $tenant -type PATCH -body (ConvertTo-Json -InputObject $BodyToship -Depth 10) -verbose } else { @@ -107,10 +110,8 @@ function Invoke-CIPPStandardGroupTemplate { } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create group: $ErrorMessage" -sev 'Error' + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to $ActionType group $($groupobj.displayname). Error: $ErrorMessage" -sev 'Error' } } - - } } diff --git a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 index bfea4f518ebe..42adae4b24de 100644 --- a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 @@ -85,7 +85,7 @@ function Invoke-CippWebhookProcessing { } $LogId = Send-CIPPAlert @CIPPAlert - $AuditLogLink = '{0}/tenant/administration/audit-logs/log?logId={2}' -f $CIPPURL, $LogId + $AuditLogLink = '{0}/tenant/administration/audit-logs/log?logId={1}&tenantFilter={2}' -f $CIPPURL, $LogId, $Tenant.defaultDomainName $GenerateEmail = New-CIPPAlertTemplate -format 'html' -data $Data -ActionResults $ActionResults -CIPPURL $CIPPURL -Tenant $Tenant.defaultDomainName -AuditLogLink $AuditLogLink Write-Host 'Going to create the content' diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index 1b8732c5b702..c3ef710b52b2 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -187,9 +187,9 @@ function Receive-CippActivityTrigger { if ($Item.FunctionName) { $FunctionName = 'Push-{0}' -f $Item.FunctionName try { - Write-Warning "Activity starting Function: Push-$FunctionName." + Write-Warning "Activity starting Function: $FunctionName." Invoke-Command -ScriptBlock { & $FunctionName -Item $Item } - Write-Warning "Activity completed Function: Push-$FunctionName." + Write-Warning "Activity completed Function: $FunctionName." if ($TaskStatus) { $QueueTask.Status = 'Completed' $null = Set-CippQueueTask @QueueTask diff --git a/Modules/CippExtensions/Public/Extension Functions/Register-CippExtensionScheduledTasks.ps1 b/Modules/CippExtensions/Public/Extension Functions/Register-CippExtensionScheduledTasks.ps1 index a560660fd8eb..fadd489958f0 100644 --- a/Modules/CippExtensions/Public/Extension Functions/Register-CippExtensionScheduledTasks.ps1 +++ b/Modules/CippExtensions/Public/Extension Functions/Register-CippExtensionScheduledTasks.ps1 @@ -14,7 +14,7 @@ function Register-CIPPExtensionScheduledTasks { $PushTasks = Get-CIPPAzDataTableEntity @ScheduledTasksTable -Filter 'Hidden eq true' | Where-Object { $_.Command -match 'Push-CippExtensionData' } $Tenants = Get-Tenants -IncludeErrors - $Extensions = @('Hudu') + $Extensions = @('Hudu', 'NinjaOne') $MappedTenants = [System.Collections.Generic.List[string]]::new() foreach ($Extension in $Extensions) { $ExtensionConfig = $Config.$Extension @@ -30,14 +30,9 @@ function Register-CIPPExtensionScheduledTasks { $SyncTypes.Add('Overview') $SyncTypes.Add('Groups') - - if ($FieldSync.Users) { - $SyncTypes.Add('Users') - $SyncTypes.Add('Mailboxes') - } - if ($FieldSync.Devices) { - $SyncTypes.Add('Devices') - } + $SyncTypes.Add('Users') + $SyncTypes.Add('Mailboxes') + $SyncTypes.Add('Devices') foreach ($Mapping in $Mappings) { $Tenant = $Tenants | Where-Object { $_.customerId -eq $Mapping.RowKey } @@ -73,7 +68,7 @@ function Register-CIPPExtensionScheduledTasks { } $ExistingPushTask = $PushTasks | Where-Object { $_.Tenant -eq $Tenant.defaultDomainName -and $_.SyncType -eq $Extension } - if (!$ExistingPushTask -or $Reschedule.IsPresent) { + if ((!$ExistingPushTask -or $Reschedule.IsPresent) -and $Extension -ne 'NinjaOne') { # push cached data to extension $in30mins = [int64](([datetime]::UtcNow.AddMinutes(30)) - (Get-Date '1/1/1970')).TotalSeconds $Task = [pscustomobject]@{ diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index 7f5826e18556..889034fc4278 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -1045,24 +1045,24 @@ function Invoke-NinjaOneTenantSync { $CIPPUserLinksData = @( @{ Name = 'View User' - Link = "https://$($CIPPURL)/identity/administration/users/view?userId=$($User.id)&tenantDomain=$($Customer.defaultDomainName)" + Link = "https://$($CIPPURL)/identity/administration/users/user?userId=$($User.id)&tenantFilter=$($Customer.defaultDomainName)" Icon = 'far fa-eye' }, @{ Name = 'Edit User' - Link = "https://$($CIPPURL)/identity/administration/users/edit?userId=$($User.id)&tenantDomain=$($Customer.defaultDomainName)" + Link = "https://$($CIPPURL)/identity/administration/users/user/edit?userId=$($User.id)&tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-users-cog' }, @{ Name = 'Research Compromise' - Link = "https://$($CIPPURL)/identity/administration/ViewBec?userId=$($User.id)&tenantDomain=$($Customer.defaultDomainName)" + Link = "https://$($CIPPURL)/identity/administration/users/user/bec?userId=$($User.id)&tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-user-secret' } ) # Actions $ActionsHTML = @" -   +     "@ diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 index a7cd3a8f406a..e1970e058b62 100644 --- a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 @@ -4,13 +4,18 @@ function Get-SherwebCatalog { [string]$CustomerId, [string]$TenantFilter ) + if ($TenantFilter) { - Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { - Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" - $CustomerId = $_.IntegrationId - } + $TenantFilter = (Get-Tenants -TenantFilter $TenantFilter).customerId + $CustomerId = Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | Select-Object -ExpandProperty IntegrationId + } + + if (![string]::IsNullOrEmpty($CustomerId)) { + Write-Information "Getting catalog for $CustomerId" + $AuthHeader = Get-SherwebAuthentication + $SubscriptionsList = Invoke-RestMethod -Uri "https://api.sherweb.com/service-provider/v1/customer-catalogs/$CustomerId" -Method GET -Headers $AuthHeader + return $SubscriptionsList.catalogItems + } else { + throw 'No Sherweb mapping found' } - $AuthHeader = Get-SherwebAuthentication - $SubscriptionsList = Invoke-RestMethod -Uri "https://api.sherweb.com/service-provider/v1/customer-catalogs/$CustomerId" -Method GET -Headers $AuthHeader - return $SubscriptionsList.catalogItems } diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 index aada3ea21a9c..f0cf0308dc7c 100644 --- a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 @@ -11,6 +11,7 @@ function Get-SherwebCurrentSubscription { $CustomerId = Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | Select-Object -ExpandProperty IntegrationId } + Write-Information "Getting current subscription for $CustomerId" $AuthHeader = Get-SherwebAuthentication $Uri = "https://api.sherweb.com/service-provider/v1/billing/subscriptions/details?customerId=$CustomerId" $SubscriptionDetails = Invoke-RestMethod -Uri $Uri -Method GET -Headers $AuthHeader diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 index b315ee4ae057..d59d5e168357 100644 --- a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 @@ -5,10 +5,8 @@ function Get-SherwebCustomerConfiguration { [string]$TenantFilter ) if ($TenantFilter) { - Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { - Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" - $CustomerId = $_.IntegrationId - } + $TenantFilter = (Get-Tenants -TenantFilter $TenantFilter).customerId + $CustomerId = Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | Select-Object -ExpandProperty IntegrationId } $AuthHeader = Get-SherwebAuthentication $Uri = "https://api.sherweb.com/service-provider/v1/customers/$($CustomerId)/platforms-configurations/" diff --git a/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 b/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 index cfdfc21c8148..87ca1c483d48 100644 --- a/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 +++ b/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 @@ -7,10 +7,8 @@ function Remove-SherwebSubscription { [string]$TenantFilter ) if ($TenantFilter) { - Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { - Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" - $CustomerId = $_.IntegrationId - } + $TenantFilter = (Get-Tenants -TenantFilter $TenantFilter).customerId + $CustomerId = Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | Select-Object -ExpandProperty IntegrationId } $AuthHeader = Get-SherwebAuthentication $Body = ConvertTo-Json -Depth 10 -InputObject @{ diff --git a/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 b/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 index 057a198966ac..d0ebc5d35616 100644 --- a/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 +++ b/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 @@ -10,10 +10,8 @@ function Set-SherwebSubscription { [string]$TenantFilter ) if ($TenantFilter) { - Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { - Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" - $CustomerId = $_.IntegrationId - } + $TenantFilter = (Get-Tenants -TenantFilter $TenantFilter).customerId + $CustomerId = Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | Select-Object -ExpandProperty IntegrationId } $AuthHeader = Get-SherwebAuthentication $ExistingSubscription = Get-SherwebCurrentSubscription -CustomerId $CustomerId -SKU $SKU diff --git a/version_latest.txt b/version_latest.txt index 643916c03f1f..eab246c063bd 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -7.3.1 +7.3.2