diff --git a/.github/workflows/dev_cippckdtz.yml b/.github/workflows/dev_cippckdtz.yml new file mode 100644 index 000000000000..6e0c53e9df0a --- /dev/null +++ b/.github/workflows/dev_cippckdtz.yml @@ -0,0 +1,30 @@ +# 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 - cippckdtz + +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: windows-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: 'cippckdtz' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_2101C7175BFB47E58240ABD1E72E81C2 }} \ No newline at end of file diff --git a/BestPracticeAnalyser_Orchestration/run.ps1 b/BestPracticeAnalyser_Orchestration/run.ps1 index 11fa99a62ec4..891f7e3fb6a4 100644 --- a/BestPracticeAnalyser_Orchestration/run.ps1 +++ b/BestPracticeAnalyser_Orchestration/run.ps1 @@ -2,7 +2,7 @@ param($Context) $DurableRetryOptions = @{ FirstRetryInterval = (New-TimeSpan -Seconds 5) - MaxNumberOfAttempts = 3 + MaxNumberOfAttempts = 1 BackoffCoefficient = 2 } $RetryOptions = New-DurableRetryOptions @DurableRetryOptions diff --git a/CIPPActivityFunction/function.json b/CIPPActivityFunction/function.json new file mode 100644 index 000000000000..e8a29dde00c3 --- /dev/null +++ b/CIPPActivityFunction/function.json @@ -0,0 +1,16 @@ +{ + "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", + "entryPoint": "Receive-CippActivityTrigger", + "bindings": [ + { + "name": "Item", + "type": "activityTrigger", + "direction": "in" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" + } + ] +} diff --git a/CIPPOrchestrator/function.json b/CIPPOrchestrator/function.json new file mode 100644 index 000000000000..011113dbc618 --- /dev/null +++ b/CIPPOrchestrator/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "../Modules/CippEntryPoints/CippEntryPoints.psm1", + "entryPoint": "Receive-CippOrchestrationTrigger", + "bindings": [ + { + "name": "Context", + "type": "orchestrationTrigger", + "direction": "in" + } + ] +} diff --git a/DomainAnalyser_All/run.ps1 b/DomainAnalyser_All/run.ps1 index d0da4a3e09da..c9f0b989c04e 100644 --- a/DomainAnalyser_All/run.ps1 +++ b/DomainAnalyser_All/run.ps1 @@ -39,6 +39,7 @@ $Result = [PSCustomObject]@{ GUID = $($Domain.Replace('.', '')) LastRefresh = $(Get-Date (Get-Date).ToUniversalTime() -UFormat '+%Y-%m-%dT%H:%M:%S.000Z') Domain = $Domain + NSRecords = (Read-NSRecord -Domain $Domain).Records ExpectedSPFRecord = '' ActualSPFRecord = '' SPFPassAll = '' @@ -52,6 +53,7 @@ $Result = [PSCustomObject]@{ DNSSECPresent = '' MailProvider = '' DKIMEnabled = '' + DKIMRecords = '' Score = '' MaximumScore = 160 ScorePercentage = '' @@ -218,6 +220,7 @@ try { if ($DkimRecordCount -gt 0 -and $DkimFailCount -eq 0) { $Result.DKIMEnabled = $true $ScoreDomain += $Scores.DKIMActiveAndWorking + $Result.DKIMRecords = $DkimRecord.Records | Select-Object Selector, Record } else { $Result.DKIMEnabled = $false $ScoreExplanation.Add('DKIM Not Configured') | Out-Null diff --git a/DomainAnalyser_Orchestration/run.ps1 b/DomainAnalyser_Orchestration/run.ps1 index 74a45a92e253..34848e03284d 100644 --- a/DomainAnalyser_Orchestration/run.ps1 +++ b/DomainAnalyser_Orchestration/run.ps1 @@ -1,44 +1,40 @@ param($Context) -try { +try { - $DurableRetryOptions = @{ - FirstRetryInterval = (New-TimeSpan -Seconds 5) - MaxNumberOfAttempts = 3 - BackoffCoefficient = 2 - } - $RetryOptions = New-DurableRetryOptions @DurableRetryOptions + $DurableRetryOptions = @{ + FirstRetryInterval = (New-TimeSpan -Seconds 5) + MaxNumberOfAttempts = 1 + BackoffCoefficient = 2 + } + $RetryOptions = New-DurableRetryOptions @DurableRetryOptions - # Sync tenants - try { - Invoke-ActivityFunction -FunctionName 'DomainAnalyser_GetTenantDomains' -Input 'Tenants' - } - catch { Write-Host "EXCEPTION: TenantDomains $($_.Exception.Message)" } + # Sync tenants + try { + Invoke-ActivityFunction -FunctionName 'DomainAnalyser_GetTenantDomains' -Input 'Tenants' + } catch { Write-Host "EXCEPTION: TenantDomains $($_.Exception.Message)" } - # Get list of all domains to process - $Batch = Invoke-ActivityFunction -FunctionName 'Activity_GetAllTableRows' -Input 'Domains' - - $ParallelTasks = foreach ($Item in $Batch) { - Invoke-DurableActivity -FunctionName 'DomainAnalyser_All' -Input $item -NoWait -RetryOptions $RetryOptions - } - - # Collect activity function results and send to database - $TableParams = Get-CippTable -tablename 'Domains' - $TableParams.Entity = Wait-ActivityFunction -Task $ParallelTasks - $TableParams.Force = $true - $TableParams = $TableParams | ConvertTo-Json -Compress + # Get list of all domains to process + $Batch = Invoke-ActivityFunction -FunctionName 'Activity_GetAllTableRows' -Input 'Domains' - try { - Invoke-ActivityFunction -FunctionName 'Activity_AddOrUpdateTableRows' -Input $TableParams - } - catch { - Write-Host "Orchestrator exception UpdateDomains $($_.Exception.Message)" - } -} -catch { - Write-LogMessage -API 'DomainAnalyser' -message "Domain Analyser Orchestrator Error $($_.Exception.Message)" -sev info - #Write-Host $_.Exception | ConvertTo-Json -} -finally { - Write-LogMessage -API 'DomainAnalyser' -message 'Domain Analyser has Finished' -sev Info + $ParallelTasks = foreach ($Item in $Batch) { + Invoke-DurableActivity -FunctionName 'DomainAnalyser_All' -Input $item -NoWait -RetryOptions $RetryOptions + } + + # Collect activity function results and send to database + $TableParams = Get-CippTable -tablename 'Domains' + $TableParams.Entity = Wait-ActivityFunction -Task $ParallelTasks + $TableParams.Force = $true + $TableParams = $TableParams | ConvertTo-Json -Compress + + try { + Invoke-ActivityFunction -FunctionName 'Activity_AddOrUpdateTableRows' -Input $TableParams + } catch { + Write-Host "Orchestrator exception UpdateDomains $($_.Exception.Message)" + } +} catch { + Write-LogMessage -API 'DomainAnalyser' -message "Domain Analyser Orchestrator Error $($_.Exception.Message)" -sev info + #Write-Host $_.Exception | ConvertTo-Json +} finally { + Write-LogMessage -API 'DomainAnalyser' -message 'Domain Analyser has Finished' -sev Info } \ No newline at end of file diff --git a/ExecExtensionNinjaOneQueue/function.json b/ExecExtensionNinjaOneQueue/function.json deleted file mode 100644 index 058a42bd6db9..000000000000 --- a/ExecExtensionNinjaOneQueue/function.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "NinjaOneQueue" - }, - { - "type": "queue", - "direction": "out", - "name": "NinjaProcess", - "queueName": "NinjaOneQueue" - } - ] -} diff --git a/ExecExtensionNinjaOneQueue/run.ps1 b/ExecExtensionNinjaOneQueue/run.ps1 deleted file mode 100644 index 21720a79b6a5..000000000000 --- a/ExecExtensionNinjaOneQueue/run.ps1 +++ /dev/null @@ -1,13 +0,0 @@ -# Input bindings are passed in via param block. -param($QueueItem, $TriggerMetadata) - -# Write out the queue message and metadata to the information log. -Write-Host "PowerShell NinjaOne queue trigger function processed work item: $($QueueItem.NinjaAction)" - - -Switch ($QueueItem.NinjaAction) { - 'StartAutoMapping' { Invoke-NinjaOneOrgMapping } - 'AutoMapTenant' { Invoke-NinjaOneOrgMappingTenant -QueueItem $QueueItem } - 'SyncTenant' { Invoke-NinjaOneTenantSync -QueueItem $QueueItem } - 'SyncTenants' {Invoke-NinjaOneSync} -} diff --git a/ExecGDAPInviteApproved_Timer/function.json b/ExecGDAPInviteApproved_Timer/function.json index 32b454a2a015..f8904bbb0a7f 100644 --- a/ExecGDAPInviteApproved_Timer/function.json +++ b/ExecGDAPInviteApproved_Timer/function.json @@ -7,10 +7,9 @@ "schedule": "0 0 */3 * * *" }, { - "type": "queue", - "direction": "out", - "name": "gdapinvitequeue", - "queueName": "gdapinvitequeue" + "name": "starter", + "type": "durableClient", + "direction": "in" } ] } diff --git a/ExecGDAPInviteQueue/function.json b/ExecGDAPInviteQueue/function.json deleted file mode 100644 index e51e66299d6f..000000000000 --- a/ExecGDAPInviteQueue/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "gdapinvitequeue" - } - ] -} diff --git a/ExecGDAPInviteQueue/run.ps1 b/ExecGDAPInviteQueue/run.ps1 deleted file mode 100644 index 1b95a443bab0..000000000000 --- a/ExecGDAPInviteQueue/run.ps1 +++ /dev/null @@ -1,7 +0,0 @@ -# Input bindings are passed in via param block. -param( $QueueItem, $TriggerMetadata) - -# Write out the queue message and metadata to the information log. -Write-Host "PowerShell queue trigger function processed work item: $($QueueItem.customer.displayName)" - -Set-CIPPGDAPInviteGroups -Relationship $QueueItem \ No newline at end of file diff --git a/ExecScheduledCommand/function.json b/ExecScheduledCommand/function.json deleted file mode 100644 index e4c27b23b985..000000000000 --- a/ExecScheduledCommand/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "scheduledcommandprocessor" - } - ] -} diff --git a/ExecScheduledCommand/run.ps1 b/ExecScheduledCommand/run.ps1 deleted file mode 100644 index 180df3368b87..000000000000 --- a/ExecScheduledCommand/run.ps1 +++ /dev/null @@ -1,83 +0,0 @@ -# Input bindings are passed in via param block. -param($QueueItem, $TriggerMetadata) - -$Table = Get-CippTable -tablename 'ScheduledTasks' -$task = $QueueItem.TaskInfo -$commandParameters = $QueueItem.Parameters - -$tenant = $QueueItem.Parameters['TenantFilter'] -Write-Host 'started task' -try { - try { - $results = & $QueueItem.command @commandParameters - } catch { - $results = "Task Failed: $($_.Exception.Message)" - - } - - Write-Host 'ran the command' - if ($results -is [String]) { - $results = @{ Results = $results } - } - if ($results -is [array]) { - $results = $results | Where-Object { $_ -is [string] } - $results = $results | ForEach-Object { @{ Results = $_ } } - } - - $results = $results | Select-Object * -ExcludeProperty RowKey, PartitionKey - - $StoredResults = $results | ConvertTo-Json -Compress -Depth 20 | Out-String - if ($StoredResults.Length -gt 64000 -or $task.Tenant -eq 'AllTenants') { - $StoredResults = @{ Results = 'The results for this query are too long to store in this table, or the query was meant for All Tenants. Please use the options to send the results to another target to be able to view the results. ' } | ConvertTo-Json -Compress - } -} catch { - $errorMessage = $_.Exception.Message - if ($task.Recurrence -gt 0) { $State = 'Failed - Planned' } else { $State = 'Failed' } - Update-AzDataTableEntity @Table -Entity @{ - PartitionKey = $task.PartitionKey - RowKey = $task.RowKey - Results = "$errorMessage" - TaskState = $State - } - Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error -} - - -$TableDesign = '' -$HTML = ($results | Select-Object * -ExcludeProperty RowKey, PartitionKey | ConvertTo-Html -Fragment) -replace '', "$TableDesign
" | Out-String -$title = "Scheduled Task $($task.Name) - $($task.ExpectedRunTime)" -Write-Host $title -switch -wildcard ($task.PostExecution) { - '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML } - '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML } - '*webhook*' { - $Webhook = [PSCustomObject]@{ - 'Tenant' = $tenant - 'TaskInfo' = $QueueItem.TaskInfo - 'Results' = $Results - } - Send-CIPPAlert -Type 'webhook' -Title $title -JSONContent $($Webhook | ConvertTo-Json -Depth 20) - } -} - -Write-Host 'ran the command' - -if ($task.Recurrence -le '0' -or $task.Recurrence -eq $null) { - Update-AzDataTableEntity @Table -Entity @{ - PartitionKey = $task.PartitionKey - RowKey = $task.RowKey - Results = "$StoredResults" - TaskState = 'Completed' - } -} else { - $nextRun = (Get-Date).AddDays($task.Recurrence) - $nextRunUnixTime = [int64]($nextRun - (Get-Date '1/1/1970')).TotalSeconds - Update-AzDataTableEntity @Table -Entity @{ - PartitionKey = $task.PartitionKey - RowKey = $task.RowKey - Results = "$StoredResults" - TaskState = 'Planned' - ScheduledTime = "$nextRunUnixTime" - } -} -Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Successfully executed task: $($task.name)" -sev Info \ No newline at end of file diff --git a/ListLicensesAllTenants/function.json b/ListLicensesAllTenants/function.json deleted file mode 100644 index eee973c7ede2..000000000000 --- a/ListLicensesAllTenants/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "licqueue" - } - ] -} diff --git a/ListLicensesAllTenants/run.ps1 b/ListLicensesAllTenants/run.ps1 deleted file mode 100644 index abc69465c094..000000000000 --- a/ListLicensesAllTenants/run.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -# Input bindings are passed in via param block. -param([string] $QueueItem, $TriggerMetadata) - -# Write out the queue message and metadata to the information log. -Write-Host "PowerShell queue trigger function processed work item: $QueueItem" - -$RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module '.\Modules\AzBobbyTables' - Import-Module '.\Modules\CIPPCore' - try { - Write-Host "Processing $domainName" - Get-CIPPLicenseOverview -TenantFilter $domainName - } - catch { - [pscustomobject]@{ - Tenant = [string]$domainName - License = "Could not connect to client: $($_.Exception.Message)" - 'PartitionKey' = 'License' - 'RowKey' = "$($domainName)-$(New-Guid)" - } - } -} - -$Table = Get-CIPPTable -TableName cachelicenses -foreach ($GraphRequest in $RawGraphRequest) { - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null -} \ No newline at end of file diff --git a/ListMFAUsersAllTenants/function.json b/ListMFAUsersAllTenants/function.json deleted file mode 100644 index 7bb9da79d405..000000000000 --- a/ListMFAUsersAllTenants/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "mfaqueue" - } - ] -} diff --git a/ListMFAUsersAllTenants/run.ps1 b/ListMFAUsersAllTenants/run.ps1 deleted file mode 100644 index 8ab611e514fe..000000000000 --- a/ListMFAUsersAllTenants/run.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -# Input bindings are passed in via param block. -param([string] $QueueItem, $TriggerMetadata) - -# Write out the queue message and metadata to the information log. -Write-Host "PowerShell queue trigger function processed work item: $QueueItem" - - -Write-Information "Item: $QueueItem" -Write-Information ($TriggerMetadata | ConvertTo-Json) - -try { - Update-CippQueueEntry -RowKey $QueueItem -Status 'Running' - - $GraphRequest = Get-Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module '.\modules\CippCore' - $Table = Get-CIPPTable -TableName cachemfa - Try { - $GraphRequest = Get-CIPPMFAState -TenantFilter $domainName -ErrorAction Stop - } - catch { - $GraphRequest = $null - } - if (!$GraphRequest) { - $GraphRequest = @{ - Tenant = [string]$tenantName - UPN = [string]$domainName - AccountEnabled = 'none' - PerUser = [string]'Could not connect to tenant' - MFARegistration = 'none' - CoveredByCA = [string]'Could not connect to tenant' - CoveredBySD = 'none' - RowKey = [string]"$domainName" - PartitionKey = 'users' - } - } - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } -} -catch { - $Table = Get-CIPPTable -TableName cachemfa - $GraphRequest = @{ - Tenant = [string]$tenantName - UPN = [string]$domainName - AccountEnabled = 'none' - PerUser = [string]'Could not connect to tenant' - MFARegistration = 'none' - CoveredByCA = [string]'Could not connect to tenant' - CoveredBySD = 'none' - RowKey = [string]"$domainName" - PartitionKey = 'users' - } - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null -} -finally { - Update-CippQueueEntry -RowKey $QueueItem -Status "Completed" -} diff --git a/ListMailboxRulesAllTenants/function.json b/ListMailboxRulesAllTenants/function.json deleted file mode 100644 index 776ec6ebfdcb..000000000000 --- a/ListMailboxRulesAllTenants/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "mbxrulequeue" - } - ] -} diff --git a/MailProviders/Mesh.json b/MailProviders/Mesh.json deleted file mode 100644 index 3109cc8c4876..000000000000 --- a/MailProviders/Mesh.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Name": "Mesh Email Security", - "_MxComment": "https://docs.emailsecurity.app/help-center/connection-details", - "MxMatch": "emailsecurity.app", - "_SpfComment": "https://docs.emailsecurity.app/help-center/connection-details", - "SpfInclude": "spf1.emailsecurity.app", - "_DkimComment": "No configuration found", - "Selectors": [""] -} \ No newline at end of file diff --git a/Modules/AzBobbyTables/3.1.0/AzBobbyTables.PS.dll b/Modules/AzBobbyTables/3.1.0/AzBobbyTables.PS.dll deleted file mode 100644 index 28610eb68077..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/AzBobbyTables.PS.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/AzBobbyTables.Core.dll b/Modules/AzBobbyTables/3.1.0/dependencies/AzBobbyTables.Core.dll deleted file mode 100644 index 0349c1394f6f..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/AzBobbyTables.Core.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/Azure.Core.dll b/Modules/AzBobbyTables/3.1.0/dependencies/Azure.Core.dll deleted file mode 100644 index 27fcd7b909f6..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/Azure.Core.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/Azure.Data.Tables.dll b/Modules/AzBobbyTables/3.1.0/dependencies/Azure.Data.Tables.dll deleted file mode 100644 index 8073b79d2b68..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/Azure.Data.Tables.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.Bcl.AsyncInterfaces.dll b/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.Bcl.AsyncInterfaces.dll deleted file mode 100644 index 39fd1311f266..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.Bcl.AsyncInterfaces.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.VisualStudio.Threading.dll b/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.VisualStudio.Threading.dll deleted file mode 100644 index a94e9380c16f..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.VisualStudio.Threading.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.VisualStudio.Validation.dll b/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.VisualStudio.Validation.dll deleted file mode 100644 index 4966e018e7dd..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.VisualStudio.Validation.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Diagnostics.DiagnosticSource.dll b/Modules/AzBobbyTables/3.1.0/dependencies/System.Diagnostics.DiagnosticSource.dll deleted file mode 100644 index a2b54fb042de..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/System.Diagnostics.DiagnosticSource.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Runtime.CompilerServices.Unsafe.dll b/Modules/AzBobbyTables/3.1.0/dependencies/System.Runtime.CompilerServices.Unsafe.dll deleted file mode 100644 index 02d9849738f2..000000000000 Binary files a/Modules/AzBobbyTables/3.1.0/dependencies/System.Runtime.CompilerServices.Unsafe.dll and /dev/null differ diff --git a/Modules/AzBobbyTables/3.1.3/AzBobbyTables.PS.dll b/Modules/AzBobbyTables/3.1.3/AzBobbyTables.PS.dll new file mode 100644 index 000000000000..72910599b85e Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/AzBobbyTables.PS.dll differ diff --git a/Modules/AzBobbyTables/3.1.3/AzBobbyTables.PS.pdb b/Modules/AzBobbyTables/3.1.3/AzBobbyTables.PS.pdb new file mode 100644 index 000000000000..38ccee09c6c2 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/AzBobbyTables.PS.pdb differ diff --git a/Modules/AzBobbyTables/3.1.0/AzBobbyTables.psd1 b/Modules/AzBobbyTables/3.1.3/AzBobbyTables.psd1 similarity index 93% rename from Modules/AzBobbyTables/3.1.0/AzBobbyTables.psd1 rename to Modules/AzBobbyTables/3.1.3/AzBobbyTables.psd1 index bd0cb30ca5a8..5bd7c13ba243 100644 --- a/Modules/AzBobbyTables/3.1.0/AzBobbyTables.psd1 +++ b/Modules/AzBobbyTables/3.1.3/AzBobbyTables.psd1 @@ -4,7 +4,7 @@ RootModule = 'AzBobbyTables.PS.dll' # Version number of this module. -ModuleVersion = '3.1.0' +ModuleVersion = '3.1.3' # Supported PSEditions CompatiblePSEditions = @('Core') @@ -108,7 +108,14 @@ PrivateData = @{ # IconUri = '' # ReleaseNotes of this module - # ReleaseNotes = '' + ReleaseNotes = '## [3.1.3] - 2024-01-20 + +### Added + +- Added Sampler ([#48](https://github.com/PalmEmanuel/AzBobbyTables/issues/48)). +- Added support for user-assigned managed identities ([#54](https://github.com/PalmEmanuel/AzBobbyTables/issues/54)). + +' # Prerelease string of this module # Prerelease = '' @@ -130,4 +137,3 @@ PrivateData = @{ # DefaultCommandPrefix = '' } - diff --git a/Modules/AzBobbyTables/3.1.3/CHANGELOG.md b/Modules/AzBobbyTables/3.1.3/CHANGELOG.md new file mode 100644 index 000000000000..c7880a5f68cf --- /dev/null +++ b/Modules/AzBobbyTables/3.1.3/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog for the module + +The format is based on and uses the types of changes according to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Added Sampler ([#48](https://github.com/PalmEmanuel/AzBobbyTables/issues/48)). +- Added support for user-assigned managed identities ([#54](https://github.com/PalmEmanuel/AzBobbyTables/issues/54)). + +## [3.1.2] - 2024-01-05 + +### Added + +- Help documentation for a DateTime problem caused by the SDK (#43). + +### Fixed + +### Changed + +### Removed + +## 3.1.1 - 2023-05-03 + +[Unreleased]: https://github.com/PalmEmanuel/AzBobbyTables/compare/v3.1.2...HEAD + +[3.1.2]: https://github.com/PalmEmanuel/AzBobbyTables/compare/d854153aca6c5cce35a123deb86653a0d3289b07...v3.1.2 diff --git a/Modules/AzBobbyTables/3.1.3/LICENSE b/Modules/AzBobbyTables/3.1.3/LICENSE new file mode 100644 index 000000000000..d4e4667fe6da --- /dev/null +++ b/Modules/AzBobbyTables/3.1.3/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Emanuel Palm + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Modules/AzBobbyTables/3.1.0/PSGetModuleInfo.xml b/Modules/AzBobbyTables/3.1.3/PSGetModuleInfo.xml similarity index 67% rename from Modules/AzBobbyTables/3.1.0/PSGetModuleInfo.xml rename to Modules/AzBobbyTables/3.1.3/PSGetModuleInfo.xml index a2c736a1e170..775321568df1 100644 --- a/Modules/AzBobbyTables/3.1.0/PSGetModuleInfo.xml +++ b/Modules/AzBobbyTables/3.1.3/PSGetModuleInfo.xml @@ -7,13 +7,13 @@ AzBobbyTables - 3.1.0 + 3.1.3 Module A module for handling Azure Table Storage operations by wrapping the Azure Data Tables SDK. Emanuel Palm PalmEmanuel (c) Emanuel Palm. All rights reserved. -
2023-03-24T21:51:21-04:00
+
2024-01-20T16:49:22-05:00
https://github.com/PalmEmanuel/AzBobbyTables/blob/main/LICENSE @@ -43,8 +43,23 @@ - Command + RoleCapability + + + + + + Function + + + + DscResource + + + + Command + Add-AzDataTableEntity @@ -58,13 +73,6 @@ - - Function - - - - - Cmdlet @@ -83,20 +91,12 @@ Workflow - - - - DscResource - - - - RoleCapability - + - + ## [3.1.3] - 2024-01-20_x000A__x000A_### Added_x000A__x000A_- Added Sampler ([#48](https://github.com/PalmEmanuel/AzBobbyTables/issues/48))._x000A_- Added support for user-assigned managed identities ([#54](https://github.com/PalmEmanuel/AzBobbyTables/issues/54)). @@ -113,28 +113,29 @@ (c) Emanuel Palm. All rights reserved. A module for handling Azure Table Storage operations by wrapping the Azure Data Tables SDK. False + ## [3.1.3] - 2024-01-20_x000A__x000A_### Added_x000A__x000A_- Added Sampler ([#48](https://github.com/PalmEmanuel/AzBobbyTables/issues/48))._x000A_- Added support for user-assigned managed identities ([#54](https://github.com/PalmEmanuel/AzBobbyTables/issues/54)). True True - 2 - 2005 - 1261744 - 3/24/2023 9:51:21 PM -04:00 - 3/24/2023 9:51:21 PM -04:00 - 3/25/2023 4:22:25 PM -04:00 + 3242 + 12058 + 1356423 + 1/20/2024 4:49:22 PM -05:00 + 1/20/2024 4:49:22 PM -05:00 + 3/18/2024 2:41:34 PM -04:00 azure storage table cosmos cosmosdb data PSModule PSEdition_Core PSCmdlet_Add-AzDataTableEntity PSCommand_Add-AzDataTableEntity PSCmdlet_Clear-AzDataTable PSCommand_Clear-AzDataTable PSCmdlet_Get-AzDataTableEntity PSCommand_Get-AzDataTableEntity PSCmdlet_Remove-AzDataTableEntity PSCommand_Remove-AzDataTableEntity PSCmdlet_Update-AzDataTableEntity PSCommand_Update-AzDataTableEntity PSCmdlet_New-AzDataTableContext PSCommand_New-AzDataTableContext PSCmdlet_Remove-AzDataTable PSCommand_Remove-AzDataTable PSCmdlet_New-AzDataTable PSCommand_New-AzDataTable PSIncludes_Cmdlet False - 2023-03-25T16:22:25Z - 3.1.0 + 2024-03-18T14:41:34Z + 3.1.3 Emanuel Palm false Module - AzBobbyTables.nuspec|dependencies\System.Numerics.Vectors.dll|dependencies\System.Security.Principal.Windows.dll|dependencies\System.Threading.Tasks.Extensions.dll|dependencies\AzBobbyTables.Core.dll|dependencies\Microsoft.Bcl.AsyncInterfaces.dll|dependencies\Microsoft.Win32.Registry.dll|dependencies\System.Linq.Async.dll|dependencies\System.Runtime.CompilerServices.Unsafe.dll|dependencies\System.Text.Encodings.Web.dll|en-US\AzBobbyTables.PS.dll-Help.xml|AzBobbyTables.PS.dll|dependencies\Azure.Core.dll|dependencies\Microsoft.VisualStudio.Threading.dll|dependencies\System.Buffers.dll|dependencies\System.Memory.Data.dll|dependencies\System.Security.AccessControl.dll|dependencies\System.Text.Json.dll|AzBobbyTables.psd1|dependencies\Azure.Data.Tables.dll|dependencies\Microsoft.VisualStudio.Validation.dll|dependencies\System.Diagnostics.DiagnosticSource.dll|dependencies\System.Memory.dll + AzBobbyTables.nuspec|CHANGELOG.md|dependencies\AzBobbyTables.Core.pdb|dependencies\Microsoft.VisualStudio.Validation.dll|dependencies\System.Memory.Data.dll|dependencies\System.Runtime.CompilerServices.Unsafe.dll|dependencies\System.Numerics.Vectors.dll|dependencies\System.Text.Json.dll|LICENSE|dependencies\AzBobbyTables.Core.dll|dependencies\System.Threading.Tasks.Extensions.dll|dependencies\Microsoft.VisualStudio.Threading.dll|AzBobbyTables.PS.pdb|dependencies\System.Security.AccessControl.dll|dependencies\Microsoft.Win32.Registry.dll|dependencies\System.Text.Encodings.Web.dll|AzBobbyTables.psd1|dependencies\System.Buffers.dll|dependencies\Azure.Data.Tables.dll|dependencies\System.Memory.dll|AzBobbyTables.PS.dll|dependencies\System.Diagnostics.DiagnosticSource.dll|dependencies\Microsoft.Bcl.AsyncInterfaces.dll|dependencies\System.Security.Principal.Windows.dll|en-US\AzBobbyTables.PS.dll-Help.xml|dependencies\System.Linq.Async.dll|dependencies\Azure.Core.dll eead4f42-5080-4f83-8901-340c529a5a11 7.0 pipe.how
- C:\Users\jduprey.CNS\Documents\GitHub\CIPP-API\Modules\AzBobbyTables\3.1.0 + C:\GitHub\CIPP Workspace\CIPP-API\Modules\AzBobbyTables\3.1.3 diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/AzBobbyTables.Core.dll b/Modules/AzBobbyTables/3.1.3/dependencies/AzBobbyTables.Core.dll new file mode 100644 index 000000000000..1a9a170b6f32 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/AzBobbyTables.Core.dll differ diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/AzBobbyTables.Core.pdb b/Modules/AzBobbyTables/3.1.3/dependencies/AzBobbyTables.Core.pdb new file mode 100644 index 000000000000..252b9c04eaa6 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/AzBobbyTables.Core.pdb differ diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/Azure.Core.dll b/Modules/AzBobbyTables/3.1.3/dependencies/Azure.Core.dll new file mode 100644 index 000000000000..f7369932f113 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/Azure.Core.dll differ diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/Azure.Data.Tables.dll b/Modules/AzBobbyTables/3.1.3/dependencies/Azure.Data.Tables.dll new file mode 100644 index 000000000000..33b1aaf7903e Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/Azure.Data.Tables.dll differ diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.Bcl.AsyncInterfaces.dll b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.Bcl.AsyncInterfaces.dll new file mode 100644 index 000000000000..cd1ca92a2beb Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.Bcl.AsyncInterfaces.dll differ diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.VisualStudio.Threading.dll b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.VisualStudio.Threading.dll new file mode 100644 index 000000000000..f3b23c328c0f Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.VisualStudio.Threading.dll differ diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.VisualStudio.Validation.dll b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.VisualStudio.Validation.dll new file mode 100644 index 000000000000..8c4956f420e1 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.VisualStudio.Validation.dll differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.Win32.Registry.dll b/Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.Win32.Registry.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/Microsoft.Win32.Registry.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/Microsoft.Win32.Registry.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Buffers.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Buffers.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Buffers.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Buffers.dll diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/System.Diagnostics.DiagnosticSource.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Diagnostics.DiagnosticSource.dll new file mode 100644 index 000000000000..aacf2c145fa0 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/System.Diagnostics.DiagnosticSource.dll differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Linq.Async.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Linq.Async.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Linq.Async.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Linq.Async.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Memory.Data.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Memory.Data.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Memory.Data.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Memory.Data.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Memory.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Memory.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Memory.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Memory.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Numerics.Vectors.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Numerics.Vectors.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Numerics.Vectors.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Numerics.Vectors.dll diff --git a/Modules/AzBobbyTables/3.1.3/dependencies/System.Runtime.CompilerServices.Unsafe.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 000000000000..491a80a97880 Binary files /dev/null and b/Modules/AzBobbyTables/3.1.3/dependencies/System.Runtime.CompilerServices.Unsafe.dll differ diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Security.AccessControl.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Security.AccessControl.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Security.AccessControl.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Security.AccessControl.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Security.Principal.Windows.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Security.Principal.Windows.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Security.Principal.Windows.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Security.Principal.Windows.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Text.Encodings.Web.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Text.Encodings.Web.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Text.Encodings.Web.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Text.Encodings.Web.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Text.Json.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Text.Json.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Text.Json.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Text.Json.dll diff --git a/Modules/AzBobbyTables/3.1.0/dependencies/System.Threading.Tasks.Extensions.dll b/Modules/AzBobbyTables/3.1.3/dependencies/System.Threading.Tasks.Extensions.dll similarity index 100% rename from Modules/AzBobbyTables/3.1.0/dependencies/System.Threading.Tasks.Extensions.dll rename to Modules/AzBobbyTables/3.1.3/dependencies/System.Threading.Tasks.Extensions.dll diff --git a/Modules/AzBobbyTables/3.1.0/en-US/AzBobbyTables.PS.dll-Help.xml b/Modules/AzBobbyTables/3.1.3/en-US/AzBobbyTables.PS.dll-Help.xml similarity index 95% rename from Modules/AzBobbyTables/3.1.0/en-US/AzBobbyTables.PS.dll-Help.xml rename to Modules/AzBobbyTables/3.1.3/en-US/AzBobbyTables.PS.dll-Help.xml index ab60d025a0c0..ca1b9df08912 100644 --- a/Modules/AzBobbyTables/3.1.0/en-US/AzBobbyTables.PS.dll-Help.xml +++ b/Modules/AzBobbyTables/3.1.3/en-US/AzBobbyTables.PS.dll-Help.xml @@ -135,7 +135,9 @@ - + Regarding Dates, DateTime, and DateTimeOffset: + The underlying Azure.Data.Tables SDK expects to work with DateTime fields in UTC format for conversion to DateTimeOffset objects. When submitting a DateTimeOffset object to the SDK, it will be converted to UTC timezone rather than preserving the existing timezone/offset info. Similarly, if a `DateTime` object is submitted in the entity with its Kind set to "local" or "unspecified", the SDK will return an error and state that `Azure SDK requires it to be UTC`. While there isn't any change needed to get `DateTimeOffset` objects to work with AzBobbyTables, the workaround for `DateTime` objects is to set the property to a new `DateTime` object with its `Kind` property set to `Utc`. e.g. `$obj.Time = $obj.Time.ToUniversalFormat()`. Related issue (https://github.com/Azure/azure-sdk-for-net/issues/30644). + It is possible via the Azure Storage Explorer to set DateTime fields with offsets other than UTC/+00:00. Note that searches with queries set to type `DateTime` do properly calculate to a specific moment, and find equivilent moments. e.g. a `-Filter` set to `Time eq datetime'2023-12-26T18:05:40.5345634+00:00'` will match an entry where the Time property is set to `2023-12-26T17:05:40.5345634-01:00`. @@ -610,10 +612,10 @@ PS C:\> New-AzDataTable -Context $Context New-AzDataTableContext - - ConnectionString + + ClientId - The connection string to the storage account. + Specifies the client id when using a user-assigned managed identity. String @@ -623,9 +625,20 @@ PS C:\> New-AzDataTable -Context $Context None - TableName + ManagedIdentity - The name of the table. + Specifies that the command is run by a managed identity (such as in an Azure Function), and authorization will be handled using that identity. + + + SwitchParameter + + + False + + + StorageAccountName + + The name of the storage account. String @@ -634,24 +647,25 @@ PS C:\> New-AzDataTable -Context $Context None - - - New-AzDataTableContext - ManagedIdentity + TableName - Specifies that the command is run by a managed identity (such as in an Azure Function), and authorization will be handled using that identity. + The name of the table. + String - SwitchParameter + String - False + None + + + New-AzDataTableContext - StorageAccountName + ConnectionString - The name of the storage account. + The connection string to the storage account. String @@ -780,6 +794,18 @@ PS C:\> New-AzDataTable -Context $Context + + ClientId + + Specifies the client id when using a user-assigned managed identity. + + String + + String + + + None + ConnectionString diff --git a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 index 2ff3c406102b..a4c66a07cb7b 100644 --- a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 @@ -16,7 +16,7 @@ function Add-CIPPGroupMember( } else { New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)" -tenantid $TenantFilter -type patch -body $addmemberbody -Verbose } - $Message = "Successfully added user $($Member) to $GroupId." + $Message = "Successfully added user $($Member) to $($GroupId)." Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' return $message return diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 index 9bc6df14e424..ad22d9aef8b1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddAlert.ps1 @@ -32,7 +32,7 @@ Function Invoke-AddAlert { MFAAlertUsers = [bool]$Request.body.MFAAlertUsers NewGA = [bool]$Request.body.NewGA NewRole = [bool]$Request.body.NewRole - QuotaUsed = [bool]$Request.body.QuotaUsed + QuotaUsed = [int]$Request.body.QuotaUsedQuota UnusedLicenses = [bool]$Request.body.UnusedLicenses OverusedLicenses = [bool]$Request.body.OverusedLicenses AppSecretExpiry = [bool]$Request.body.AppSecretExpiry @@ -41,7 +41,7 @@ Function Invoke-AddAlert { DepTokenExpiry = [bool]$Request.body.DepTokenExpiry NoCAConfig = [bool]$Request.body.NoCAConfig SecDefaultsUpsell = [bool]$Request.body.SecDefaultsUpsell - SharePointQuota = [bool]$Request.body.SharePointQuota + SharePointQuota = [int]$Request.body.SharePointQuotaQuota ExpiringLicenses = [bool]$Request.body.ExpiringLicenses type = 'Alert' RowKey = $TenantID diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 index 3686d66c124d..b3246cea773d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddExConnector.ps1 @@ -18,12 +18,12 @@ Function Invoke-AddExConnector { $Result = foreach ($Tenantfilter in $tenants) { try { $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams - "Successfully created transport rule for $Tenantfilter." - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Created transport rule for $($Tenantfilter)" -sev 'Info' + "Successfully created Connector for $Tenantfilter." + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Created Connector for $($Tenantfilter)" -sev 'Info' } catch { - "Could not create created transport rule for $($Tenantfilter): $($_.Exception.message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Could not create created transport rule for $($Tenantfilter): $($_.Exception.message)" -sev 'Error' + "Could not create created Connector for $($Tenantfilter): $($_.Exception.message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Could not create created Connector for $($Tenantfilter): $($_.Exception.message)" -sev 'Error' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 index c1d7512b14d6..41c1004a8cf6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddUser.ps1 @@ -59,6 +59,7 @@ Function Invoke-AddUser { } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Failed to create user. Error:$($_.Exception.Message)" -Sev 'Error' $body = $results.add("Failed to create user. $($_.Exception.Message)" ) + exit 1 } try { diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceDelete.ps1 index 843764a6d5d4..25e64be478b3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceDelete.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecDeviceDelete.ps1 @@ -14,13 +14,16 @@ Function Invoke-ExecDeviceDelete { # Interact with query parameters or the body of the request. - try { + try { $url = "https://graph.microsoft.com/beta/devices/$($request.query.id)" if ($Request.query.action -eq 'delete') { $ActionResult = New-GraphPOSTRequest -uri $url -type DELETE -tenantid $Request.Query.TenantFilter - } else { + } elseif ($Request.query.action -eq 'disable') { $ActionResult = New-GraphPOSTRequest -uri $url -type PATCH -tenantid $Request.Query.TenantFilter -body '{"accountEnabled": false }' + } elseif ($Request.query.action -eq 'enable') { + $ActionResult = New-GraphPOSTRequest -uri $url -type PATCH -tenantid $Request.Query.TenantFilter -body '{"accountEnabled": true }' } + Write-Host $ActionResult $body = [pscustomobject]@{'Results' = "Executed action $($Request.query.action) on $($Request.query.id)" } } catch { $body = [pscustomobject]@{'Results' = "Failed to queue action $($Request.query.action) on $($request.query.id): $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionMapping.ps1 index 1e4c8c8677e3..f35e5a38c94f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionMapping.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionMapping.ps1 @@ -1,6 +1,6 @@ - using namespace System.Net +using namespace System.Net - Function Invoke-ExecExtensionMapping { +Function Invoke-ExecExtensionMapping { <# .FUNCTIONALITY Entrypoint @@ -8,74 +8,82 @@ [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -# Write to the Azure Functions log stream. -Write-Host 'PowerShell HTTP trigger function processed a request.' -$Table = Get-CIPPTable -TableName CippMapping + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + $Table = Get-CIPPTable -TableName CippMapping -if ($Request.Query.List) { - switch ($Request.Query.List) { - 'Halo' { - $body = Get-HaloMapping -CIPPMapping $Table - } - - 'NinjaOrgs' { - $Body = Get-NinjaOneOrgMapping -CIPPMapping $Table - } - - 'NinjaFields' { - $Body = Get-NinjaOneFieldMapping -CIPPMapping $Table - - } - } -} - -try { - if ($Request.Query.AddMapping) { - switch ($Request.Query.AddMapping) { + if ($Request.Query.List) { + switch ($Request.Query.List) { 'Halo' { - $body = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request + $body = Get-HaloMapping -CIPPMapping $Table } - + 'NinjaOrgs' { - $Body = Set-NinjaOneOrgMapping -CIPPMapping $Table -APIName $APIName -Request $Request + $Body = Get-NinjaOneOrgMapping -CIPPMapping $Table } - + 'NinjaFields' { - $Body = Set-NinjaOneFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -TriggerMetadata $TriggerMetadata + $Body = Get-NinjaOneFieldMapping -CIPPMapping $Table + } } } -} -catch { - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } -} -try { - if ($Request.Query.AutoMapping) { - switch ($Request.Query.AutoMapping) { - 'NinjaOrgs' { - Push-OutputBinding -Name NinjaProcess -Value @{'NinjaAction' = 'StartAutoMapping' } - $Body = [pscustomobject]@{'Results' = 'Automapping Request has been queued. Exact name matches will appear first and matches on device names and serials will take longer. Please check the CIPP Logbook and refresh the page once complete.' } - } + try { + if ($Request.Query.AddMapping) { + switch ($Request.Query.AddMapping) { + 'Halo' { + $body = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request + } + 'NinjaOrgs' { + $Body = Set-NinjaOneOrgMapping -CIPPMapping $Table -APIName $APIName -Request $Request + } + 'NinjaFields' { + $Body = Set-NinjaOneFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -TriggerMetadata $TriggerMetadata + } + } } + } catch { + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } } -} -catch { - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) + try { + if ($Request.Query.AutoMapping) { + switch ($Request.Query.AutoMapping) { + 'NinjaOrgs' { + #Push-OutputBinding -Name NinjaProcess -Value @{'NinjaAction' = 'StartAutoMapping' } + $Batch = [PSCustomObject]@{ + 'NinjaAction' = 'StartAutoMapping' + 'FunctionName' = 'NinjaOneQueue' + } + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + $Body = [pscustomobject]@{'Results' = 'Automapping Request has been queued. Exact name matches will appear first and matches on device names and serials will take longer. Please check the CIPP Logbook and refresh the page once complete.' } + } + } + } + } catch { + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 index effb15af199d..57e44b3f946f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionSync.ps1 @@ -42,28 +42,50 @@ Function Invoke-ExecExtensionSync { $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } if ($Request.Query.TenantID) { - $Tenant = $TenantsToProcess | Where-Object {$_.RowKey -eq $Request.Query.TenantID} - if (($Tenant | Measure-Object).count -eq 1){ - Push-OutputBinding -Name NinjaProcess -Value @{ + $Tenant = $TenantsToProcess | Where-Object { $_.RowKey -eq $Request.Query.TenantID } + if (($Tenant | Measure-Object).count -eq 1) { + <#Push-OutputBinding -Name NinjaProcess -Value @{ 'NinjaAction' = 'SyncTenant' 'MappedTenant' = $Tenant + }#> + $Batch = [PSCustomObject]@{ + 'NinjaAction' = 'SyncTenant' + 'MappedTenant' = $Tenant + 'FunctionName' = 'NinjaOneQueue' + } + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + $Results = [pscustomobject]@{'Results' = "NinjaOne Synchronization Queued for $($Tenant.NinjaOneName)" } } else { - $Results = [pscustomobject]@{'Results' = "Tenant was not found." } - } - + $Results = [pscustomobject]@{'Results' = 'Tenant was not found.' } + } + } else { - - Push-OutputBinding -Name NinjaProcess -Value @{ + <#Push-OutputBinding -Name NinjaProcess -Value @{ 'NinjaAction' = 'SyncTenants' + }#> + $Batch = [PSCustomObject]@{ + 'NinjaAction' = 'SyncTenants' + 'FunctionName' = 'NinjaOneQueue' } - + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" $Results = [pscustomobject]@{'Results' = "NinjaOne Synchronization Queuing $(($TenantsToProcess | Measure-Object).count) Tenants" } } - + } catch { $Results = [pscustomobject]@{'Results' = "Could not start NinjaOne Sync: $($_.Exception.Message)" } Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message "Could not start NinjaOne Sync $($_.Exception.Message)" -sev Error diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 index e9e23c2a174e..41365297ca4f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecOnboardTenant.ps1 @@ -52,13 +52,19 @@ function Invoke-ExecOnboardTenant { } Add-CIPPAzDataTableEntity @OnboardTable -Entity $TenantOnboarding -Force -ErrorAction Stop - Push-OutputBinding -Name QueueItem -Value ([pscustomobject]@{ - FunctionName = 'ExecOnboardTenantQueue' - id = $Id - Roles = $Request.Body.gdapRoles - AddMissingGroups = $Request.Body.addMissingGroups - AutoMapRoles = $Request.Body.autoMapRoles - }) + $Item = [pscustomobject]@{ + FunctionName = 'ExecOnboardTenantQueue' + id = $Id + Roles = $Request.Body.gdapRoles + AddMissingGroups = $Request.Body.addMissingGroups + AutoMapRoles = $Request.Body.autoMapRoles + } + + $InputObject = @{ + OrchestratorName = 'OnboardingOrchestrator' + Batch = @($Item) + } + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) } $Steps = $TenantOnboarding.OnboardingSteps | ConvertFrom-Json diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 index 76469b49b477..ab9092f13c1d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 @@ -11,18 +11,17 @@ function Invoke-ExecUserSettings { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' try { - $object = $request.body.currentSettings | Select-Object * -ExcludeProperty CurrentTenant, pageSizes, sidebarShow, sidebarUnfoldable, _persist | ConvertTo-Json -Compress + $object = $request.body.currentSettings | Select-Object * -ExcludeProperty CurrentTenant, pageSizes, sidebarShow, sidebarUnfoldable, _persist | ConvertTo-Json -Compress -Depth 10 $Table = Get-CippTable -tablename 'UserSettings' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ JSON = "$object" RowKey = "$($Request.body.user)" - PartitionKey = "UserSettings" + PartitionKey = 'UserSettings' } $StatusCode = [HttpStatusCode]::OK - $Results = [pscustomobject]@{"Results" = "Successfully added user settings" } - } - catch { + $Results = [pscustomobject]@{'Results' = 'Successfully added user settings' } + } catch { $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) $Results = "Function Error: $ErrorMsg" $StatusCode = [HttpStatusCode]::BadRequest diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 index a9903b33ac16..7a0ca462e60e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 @@ -36,7 +36,7 @@ Function Invoke-ListFunctionStats { } $Table = Get-CIPPTable -tablename 'CippFunctionStats' - if (!$PartitionKey) { $PartitionKey = 'Queue' } + if (!$PartitionKey) { $PartitionKey = 'Durable' } if (![string]::IsNullOrEmpty($TenantFilter) -and $TenantFilter -ne 'AllTenants') { $TenantQuery = " and (tenant eq '{0}' or Tenant eq '{0}' or Tenantid eq '{0}' or tenantid eq '{0}')" -f $TenantFilter } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 index 27c2db9767a3..6870b020be6e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 @@ -18,18 +18,38 @@ Function Invoke-ListLicenses { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter $RawGraphRequest = if ($TenantFilter -ne 'AllTenants') { - $GraphRequest = Get-CIPPLicenseOverview -TenantFilter $TenantFilter + $GraphRequest = Get-CIPPLicenseOverview -TenantFilter $TenantFilter | ForEach-Object { + $TermInfo = $_.TermInfo | ConvertFrom-Json -ErrorAction SilentlyContinue + $_.TermInfo = $TermInfo + $_ + } } else { $Table = Get-CIPPTable -TableName cachelicenses $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddHours(-1) if (!$Rows) { - Push-OutputBinding -Name LicenseQueue -Value (Get-Date).ToString() + #Push-OutputBinding -Name LicenseQueue -Value (Get-Date).ToString() $GraphRequest = [PSCustomObject]@{ Tenant = 'Loading data for all tenants. Please check back in 1 minute' License = 'Loading data for all tenants. Please check back in 1 minute' } + $Tenants = Get-Tenants -IncludeErrors | ForEach-Object { $_ | Add-Member -NotePropertyName FunctionName -NotePropertyValue 'ListLicensesQueue'; $_ } + + if (($Tenants | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'ListLicensesOrchestrator' + Batch = @($Tenants) + SkipLog = $true + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + } } else { - $GraphRequest = $Rows + $GraphRequest = $Rows | ForEach-Object { + $TermInfo = $_.TermInfo | ConvertFrom-Json -ErrorAction SilentlyContinue + $_.TermInfo = $TermInfo + $_ + } } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicensesAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicensesAllTenants.ps1 deleted file mode 100644 index 7d6c25d9daa7..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicensesAllTenants.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -using namespace System.Net - -Function Invoke-ListLicensesAllTenants { - <# - .FUNCTIONALITY - Entrypoint - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - - $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - - Import-Module '.\Modules\AzBobbyTables' - Import-Module '.\Modules\CIPPCore' - try { - Write-Host "Processing $domainName" - Get-CIPPLicenseOverview -TenantFilter $domainName - } catch { - [pscustomobject]@{ - Tenant = [string]$domainName - License = "Could not connect to client: $($_.Exception.Message)" - 'PartitionKey' = 'License' - 'RowKey' = "$($domainName)-$(New-Guid)" - } - } - } - - $Table = Get-CIPPTable -TableName cachelicenses - foreach ($GraphRequest in $RawGraphRequest) { - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 index 32314d2298d8..99209bfc9c8f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 @@ -24,9 +24,24 @@ Function Invoke-ListMFAUsers { if (!$Rows) { $Queue = New-CippQueueEntry -Name 'MFA Users - All Tenants' -Link '/identity/reports/mfa-report?customerId=AllTenants' Write-Information ($Queue | ConvertTo-Json) - Push-OutputBinding -Name mfaqueue -Value $Queue.RowKey + #Push-OutputBinding -Name mfaqueue -Value $Queue.RowKey $GraphRequest = [PSCustomObject]@{ - UPN = 'Loading data for all tenants. Please check back in 10 minutes' + UPN = 'Loading data for all tenants. Please check back in a few minutes' + } + $Batch = Get-Tenants -IncludeErrors | ForEach-Object { + $_ | Add-Member -NotePropertyName FunctionName -NotePropertyValue 'ListMFAUsersQueue' + $_ | Add-Member -NotePropertyName QueueId -NotePropertyValue $Queue.RowKey + $_ + } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'ListMFAUsersOrchestrator' + Batch = @($Batch) + SkipLog = $true + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" } } else { $GraphRequest = $Rows diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsersAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsersAllTenants.ps1 deleted file mode 100644 index 8123a963e1ff..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsersAllTenants.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -using namespace System.Net - -Function Invoke-ListMFAUsersAllTenants { - <# - .FUNCTIONALITY - Entrypoint - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - - - Write-Information "Item: $QueueItem" - Write-Information ($TriggerMetadata | ConvertTo-Json) - - try { - Update-CippQueueEntry -RowKey $QueueItem -Status 'Running' - - $GraphRequest = Get-Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module '.\modules\CippCore' - Import-Module '.\Modules\AzBobbyTables' - - $Table = Get-CIPPTable -TableName cachemfa - Try { - $GraphRequest = Get-CIPPMFAState -TenantFilter $domainName -ErrorAction Stop - } catch { - $GraphRequest = $null - } - if (!$GraphRequest) { - $GraphRequest = @{ - Tenant = [string]$tenantName - UPN = [string]$domainName - AccountEnabled = 'none' - PerUser = [string]'Could not connect to tenant' - MFARegistration = 'none' - CoveredByCA = [string]'Could not connect to tenant' - CoveredBySD = 'none' - RowKey = [string]"$domainName" - PartitionKey = 'users' - } - } - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } - } catch { - $Table = Get-CIPPTable -TableName cachemfa - $GraphRequest = @{ - Tenant = [string]$tenantName - UPN = [string]$domainName - AccountEnabled = 'none' - PerUser = [string]'Could not connect to tenant' - MFARegistration = 'none' - CoveredByCA = [string]'Could not connect to tenant' - CoveredBySD = 'none' - RowKey = [string]"$domainName" - PartitionKey = 'users' - } - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } finally { - Update-CippQueueEntry -RowKey $QueueItem -Status 'Completed' - } - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 index a4ca980ba7d3..d1de06beada8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 @@ -19,14 +19,36 @@ Function Invoke-ListMailboxRules { $TenantFilter = $Request.Query.TenantFilter $Table = Get-CIPPTable -TableName cachembxrules + if ($TenantFilter -ne 'AllTenants') { + $Table.Filter = "Tenant eq '$TenantFilter'" + } $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).Addhours(-1) if (!$Rows) { - Push-OutputBinding -Name mbxrulequeue -Value $TenantFilter + #Push-OutputBinding -Name mbxrulequeue -Value $TenantFilter $GraphRequest = [PSCustomObject]@{ Tenant = 'Loading data. Please check back in 1 minute' Licenses = 'Loading data. Please check back in 1 minute' } + $Batch = if ($TenantFilter -eq 'AllTenants') { + Get-Tenants -IncludeErrors | ForEach-Object { $_ | Add-Member -NotePropertyName FunctionName -NotePropertyValue 'ListMailboxRulesQueue'; $_ } + } else { + [PSCustomObject]@{ + defaultDomainName = $TenantFilter + FunctionName = 'ListMailboxRulesQueue' + } + } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'ListMailboxRulesOrchestrator' + Batch = @($Batch) + SkipLog = $true + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + } + } else { if ($TenantFilter -ne 'AllTenants') { $Rows = $Rows | Where-Object -Property Tenant -EQ $TenantFilter diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRulesAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRulesAllTenants.ps1 deleted file mode 100644 index b3909976d4c9..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRulesAllTenants.ps1 +++ /dev/null @@ -1,60 +0,0 @@ -using namespace System.Net - -Function Invoke-ListMailboxRulesAllTenants { - <# - .FUNCTIONALITY - Entrypoint - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $Tenants = if ($QueueItem -ne 'AllTenants') { - [PSCustomObject]@{ - defaultDomainName = $QueueItem - } - } else { - Get-Tenants - } - $Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module '.\Modules\CIPPcore' - Import-Module '.\Modules\AzBobbyTables' - - try { - - $Rules = New-ExoRequest -tenantid $domainName -cmdlet 'Get-Mailbox' | ForEach-Object -Parallel { - New-ExoRequest -Anchor $_.UserPrincipalName -tenantid $domainName -cmdlet 'Get-InboxRule' -cmdParams @{Mailbox = $_.GUID } - } - foreach ($Rule in $Rules) { - $GraphRequest = @{ - Rules = [string]($Rule | ConvertTo-Json) - RowKey = [string](New-Guid).guid - Tenant = [string]$domainName - PartitionKey = 'mailboxrules' - } - $Table = Get-CIPPTable -TableName cachembxrules - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } - } catch { - $Rules = @{ - Name = "Could not connect to tenant $($_.Exception.message)" - } | ConvertTo-Json - $GraphRequest = @{ - Rules = [string]$Rules - RowKey = [string]$domainName - Tenant = [string]$domainName - - PartitionKey = 'mailboxrules' - } - $Table = Get-CIPPTable -TableName cachembxrules - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } - } - - - - $Table = Get-CIPPTable -TableName cachembxrules - Write-Host "$($GraphRequest.RowKey) - $($GraphRequest.tenant)" - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 new file mode 100644 index 000000000000..24c7020f0e31 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-ListPendingWebhooks { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + try { + $Table = Get-CIPPTable -TableName 'WebhookIncoming' + $Webhooks = Get-CIPPAzDataTableEntity @Table + $Results = $Webhooks | Select-Object -ExcludeProperty RowKey, PartitionKey, ETag, Timestamp + $PendingWebhooks = foreach ($Result in $Results) { + foreach ($Property in $Result.PSObject.Properties.Name) { + if (Test-Json -Json $Result.$Property -ErrorAction SilentlyContinue) { + $Result.$Property = $Result.$Property | ConvertFrom-Json + } + } + $Result + } + } catch { + $PendingWebhooks = @() + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ + Results = @($PendingWebhooks) + Metadata = @{ + Count = ($PendingWebhooks | Measure-Object).Count + } + } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 index d23de674c779..17a650f11196 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListScheduledItems.ps1 @@ -11,7 +11,10 @@ Function Invoke-ListScheduledItems { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' $Table = Get-CIPPTable -TableName 'ScheduledTasks' - $ScheduledTasks = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask' and Hidden ne 'True'" + $ScheduledTasks = foreach ($Task in Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask' and Hidden ne 'True'") { + $Task.Parameters = $Task.Parameters | ConvertFrom-Json + $Task + } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 index 274c5d8383f1..50781d922e7b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSettings.ps1 @@ -14,8 +14,8 @@ function Invoke-ListUserSettings { try { $Table = Get-CippTable -tablename 'UserSettings' $UserSettings = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'allUsers'" - if (!$UserSettings) { Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$username'" } - $UserSettings = $UserSettings | Select-Object -ExpandProperty JSON | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue + if (!$UserSettings) { $userSettings = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$username'" } + $UserSettings = $UserSettings.JSON | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue $StatusCode = [HttpStatusCode]::OK $Results = $UserSettings } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 index d4fe27a93764..d421b79441d5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListUserSigninLogs.ps1 @@ -40,9 +40,14 @@ Function Invoke-ListUserSigninLogs { @{ Name = 'FailureReason'; Expression = { $_.status.failureReason } }, @{ Name = 'FullDetails'; Expression = { $_ } } # Associate values to output bindings by calling 'Push-OutputBinding'. + if ($GraphRequest.FullDetails -eq $null) { + $GraphRequest = $null + } else { + $GraphRequest = @($GraphRequest) + } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) + Body = $GraphRequest }) } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Sign In report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 index 5ee5feb2924f..d585504f4254 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListWebhookAlert.ps1 @@ -11,12 +11,14 @@ Function Invoke-ListWebhookAlert { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Table = get-cipptable -TableName 'SchedulerConfig' - $WebhookRow = Get-CIPPAzDataTableEntity @Table | Where-Object -Property PartitionKey -EQ 'WebhookAlert' - + $WebhookRow = foreach ($Webhook in Get-CIPPAzDataTableEntity @Table | Where-Object -Property PartitionKey -EQ 'WebhookAlert') { + $Webhook.If = $Webhook.If | ConvertFrom-Json + $Webhook.execution = $Webhook.execution | ConvertFrom-Json + $Webhook + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @($WebhookRow) }) - - } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicWebhooks.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicWebhooks.ps1 new file mode 100644 index 000000000000..97c135235cd6 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicWebhooks.ps1 @@ -0,0 +1,128 @@ +using namespace System.Net +function Invoke-PublicWebhooks { + # Input bindings are passed in via param block. + param($Request, $TriggerMetadata) + + Set-Location (Get-Item $PSScriptRoot).Parent.FullName + $WebhookTable = Get-CIPPTable -TableName webhookTable + $WebhookIncoming = Get-CIPPTable -TableName WebhookIncoming + $Webhooks = Get-CIPPAzDataTableEntity @WebhookTable + Write-Host 'Received request' + Write-Host "CIPPID: $($request.Query.CIPPID)" + $url = ($request.headers.'x-ms-original-url').split('/API') | Select-Object -First 1 + Write-Host $url + if ($Request.Query.CIPPID -in $Webhooks.RowKey) { + Write-Host 'Found matching CIPPID' + if ($Webhooks.Resource -eq 'M365AuditLogs') { + Write-Host "Found M365AuditLogs - This is an old entry, we'll deny so Microsoft stops sending it." + $body = 'This webhook is not authorized, its an old entry.' + $StatusCode = [HttpStatusCode]::Forbidden + } + if ($Request.query.ValidationToken -or $Request.body.validationCode) { + Write-Host 'Validation token received' + $body = $request.query.ValidationToken + $StatusCode = [HttpStatusCode]::OK + } else { + Write-Host 'Received request' + Write-Host "CIPPID: $($request.Query.CIPPID)" + $url = ($request.headers.'x-ms-original-url').split('/API') | Select-Object -First 1 + Write-Host $url + + $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID + + if ($Request.Query.Type -eq 'GraphSubscription') { + # Graph Subscriptions + [pscustomobject]$ReceivedItem = $Request.Body.value + $Entity = [PSCustomObject]@{ + PartitionKey = 'Webhook' + RowKey = [string](New-Guid).Guid + Type = $Request.Query.Type + Data = [string]($ReceivedItem | ConvertTo-Json -Depth 10) + CIPPID = $Request.Query.CIPPID + WebhookInfo = [string]($WebhookInfo | ConvertTo-Json -Depth 10) + FunctionName = 'PublicWebhookProcess' + } + Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity + ## Push webhook data to queue + #Invoke-CippGraphWebhookProcessing -Data $ReceivedItem -CIPPID $request.Query.CIPPID -WebhookInfo $Webhookinfo + + } else { + # Auditlog Subscriptions + try { + foreach ($ReceivedItem In ($Request.body)) { + $ReceivedItem = [pscustomobject]$ReceivedItem + Write-Host "Received Item: $($ReceivedItem | ConvertTo-Json -Depth 15 -Compress))" + $TenantFilter = (Get-Tenants | Where-Object -Property customerId -EQ $ReceivedItem.TenantId).defaultDomainName + Write-Host "Webhook TenantFilter: $TenantFilter" + $ConfigTable = get-cipptable -TableName 'SchedulerConfig' + $Alertconfig = Get-CIPPAzDataTableEntity @ConfigTable | Where-Object { $_.Tenant -eq $TenantFilter -or $_.Tenant -eq 'AllTenants' } + $Operations = @(($AlertConfig.if | ConvertFrom-Json -ErrorAction SilentlyContinue).selection) + 'UserLoggedIn' + $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID + #Increased download efficiency: only download the data we need for processing. Todo: Change this to load from table or dynamic source. + $MappingTable = [pscustomobject]@{ + 'UserLoggedIn' = 'Audit.AzureActiveDirectory' + 'Add member to role.' = 'Audit.AzureActiveDirectory' + 'Disable account.' = 'Audit.AzureActiveDirectory' + 'Update StsRefreshTokenValidFrom Timestamp.' = 'Audit.AzureActiveDirectory' + 'Enable account.' = 'Audit.AzureActiveDirectory' + 'Disable Strong Authentication.' = 'Audit.AzureActiveDirectory' + 'Reset user password.' = 'Audit.AzureActiveDirectory' + 'Add service principal.' = 'Audit.AzureActiveDirectory' + 'HostedIP' = 'Audit.AzureActiveDirectory' + 'badRepIP' = 'Audit.AzureActiveDirectory' + 'UserLoggedInFromUnknownLocation' = 'Audit.AzureActiveDirectory' + 'customfield' = 'AnyLog' + 'anyAlert' = 'AnyLog' + 'New-InboxRule' = 'Audit.Exchange' + 'Set-InboxRule' = 'Audit.Exchange' + } + #Compare $Operations to $MappingTable. If there is a match, we make a new variable called $LogsToDownload + #Example: $Operations = 'UserLoggedIn', 'Set-InboxRule' makes : $LogsToDownload = @('Audit.AzureActiveDirectory',Audit.Exchange) + $LogsToDownload = $Operations | Where-Object { $MappingTable.$_ } | ForEach-Object { $MappingTable.$_ } + Write-Host "Our operations: $Operations" + Write-Host "Logs to download: $LogsToDownload" + if ($ReceivedItem.ContentType -in $LogsToDownload -or 'AnyLog' -in $LogsToDownload) { + $Data = New-GraphPostRequest -type GET -uri "https://manage.office.com/api/v1.0/$($ReceivedItem.tenantId)/activity/feed/audit/$($ReceivedItem.contentid)" -tenantid $TenantFilter -scope 'https://manage.office.com/.default' + } else { + Write-Host "No data to download for $($ReceivedItem.ContentType)" + continue + } + Write-Host "Data found: $($data.count) items" + $DataToProcess = if ('anylog' -NotIn $LogsToDownload) { $Data | Where-Object -Property Operation -In $Operations } else { $Data } + Write-Host "Data to process found: $($DataToProcess.count) items" + foreach ($Item in $DataToProcess) { + Write-Host "Processing $($item.operation)" + + ## Push webhook data to table + $Entity = [PSCustomObject]@{ + PartitionKey = 'Webhook' + RowKey = [string](New-Guid).Guid + Type = 'AuditLog' + Data = [string]($Item | ConvertTo-Json -Depth 10) + CIPPURL = $CIPPURL + TenantFilter = $TenantFilter + FunctionName = 'PublicWebhookProcess' + } + Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity -Force + #Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url + } + } + } catch { + Write-Host "Webhook Failed: $($_.Exception.Message). Line number $($_.InvocationInfo.ScriptLineNumber)" + } + } + + $Body = 'Webhook Recieved' + $StatusCode = [HttpStatusCode]::OK + } + } else { + $Body = 'This webhook is not authorized.' + $StatusCode = [HttpStatusCode]::Forbidden + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAdminPassword.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAdminPassword.ps1 index af03360c1973..63f371b10aa6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAdminPassword.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAdminPassword.ps1 @@ -3,17 +3,16 @@ function Push-CIPPAlertAdminPassword { [CmdletBinding()] param( [Parameter(Mandatory = $true)] - [pscustomobject]$QueueItem, - $TriggerMetadata + [pscustomobject]$Item ) try { - New-GraphGETRequest -uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'&`$expand=principal" -tenantid $($QueueItem.tenant) | Where-Object { ($_.principalOrganizationId -EQ $QueueItem.tenantid) -and ($_.principal.'@odata.type' -eq '#microsoft.graph.user') } | ForEach-Object { - $LastChanges = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/users/$($_.principalId)?`$select=UserPrincipalName,lastPasswordChangeDateTime" -tenant $($QueueItem.tenant) + New-GraphGETRequest -uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'&`$expand=principal" -tenantid $($Item.tenant) | Where-Object { ($_.principalOrganizationId -EQ $Item.tenantid) -and ($_.principal.'@odata.type' -eq '#microsoft.graph.user') } | ForEach-Object { + $LastChanges = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/users/$($_.principalId)?`$select=UserPrincipalName,lastPasswordChangeDateTime" -tenant $($Item.tenant) if ($LastChanges.LastPasswordChangeDateTime -gt (Get-Date).AddDays(-1)) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Admin password has been changed for $($LastChanges.UserPrincipalName) in last 24 hours" + Write-AlertMessage -tenant $($Item.tenant) -message "Admin password has been changed for $($LastChanges.UserPrincipalName) in last 24 hours" } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Could not get admin password changes for $($QueueItem.tenant): $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Could not get admin password changes for $($Item.tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1 index 07571db760aa..13a411f105e9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1 @@ -2,29 +2,16 @@ function Push-CIPPAlertApnCertExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) - $LastRunTable = Get-CIPPTable -Table AlertLastRun try { - $Filter = "RowKey eq 'ApnCertExpiry' and PartitionKey eq '{0}'" -f $QueueItem.tenantid - $LastRun = Get-CIPPAzDataTableEntity @LastRunTable -Filter $Filter - $Yesterday = (Get-Date).AddDays(-1) - if (-not $LastRun.Timestamp.DateTime -or ($LastRun.Timestamp.DateTime -le $Yesterday)) { - try { - $Apn = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/applePushNotificationCertificate' -tenantid $QueueItem.tenant - if ($Apn.expirationDateTime -lt (Get-Date).AddDays(30) -and $Apn.expirationDateTime -gt (Get-Date).AddDays(-7)) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message ('Intune: Apple Push Notification certificate for {0} is expiring on {1}' -f $Apn.appleIdentifier, $Apn.expirationDateTime) - } - } catch {} + $Apn = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/applePushNotificationCertificate' -tenantid $Item.tenant + if ($Apn.expirationDateTime -lt (Get-Date).AddDays(30) -and $Apn.expirationDateTime -gt (Get-Date).AddDays(-7)) { + Write-AlertMessage -tenant $($Item.tenant) -message ('Intune: Apple Push Notification certificate for {0} is expiring on {1}' -f $Apn.appleIdentifier, $Apn.expirationDateTime) } - $LastRun = @{ - RowKey = 'ApnCertExpiry' - PartitionKey = $QueueItem.tenantid - } - Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force } catch { - # Error handling + #no error because if a tenant does not have an APN, it'll error anyway. + #Write-AlertMessage -tenant $($Item.Tenant) -message "Failed to check APN certificate expiry for $($Item.Tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 index 82bcde9bb74f..7b1b8b12fd4f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1 @@ -2,39 +2,26 @@ function Push-CIPPAlertAppSecretExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) - $LastRunTable = Get-CIPPTable -Table AlertLastRun - try { - $Filter = "RowKey eq 'AppSecretExpiry' and PartitionKey eq '{0}'" -f $QueueItem.tenantid - $LastRun = Get-CIPPAzDataTableEntity @LastRunTable -Filter $Filter - $Yesterday = (Get-Date).AddDays(-1) - if (-not $LastRun.Timestamp.DateTime -or ($LastRun.Timestamp.DateTime -le $Yesterday)) { - Write-Host "Checking app expire for $($QueueItem.tenant)" - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$select=appId,displayName,passwordCredentials" -tenantid $QueueItem.tenant | ForEach-Object { - foreach ($App in $_) { - Write-Host "checking $($App.displayName)" - if ($App.passwordCredentials) { - foreach ($Credential in $App.passwordCredentials) { - if ($Credential.endDateTime -lt (Get-Date).AddDays(30) -and $Credential.endDateTime -gt (Get-Date).AddDays(-7)) { - Write-Host ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime) - Write-AlertMessage -tenant $($QueueItem.tenant) -message ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime) - } + Write-Host "Checking app expire for $($Item.tenant)" + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$select=appId,displayName,passwordCredentials" -tenantid $Item.tenant | ForEach-Object { + foreach ($App in $_) { + Write-Host "checking $($App.displayName)" + if ($App.passwordCredentials) { + foreach ($Credential in $App.passwordCredentials) { + if ($Credential.endDateTime -lt (Get-Date).AddDays(30) -and $Credential.endDateTime -gt (Get-Date).AddDays(-7)) { + Write-Host ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime) + Write-AlertMessage -tenant $($Item.Tenant) -message ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime) } } } } - $LastRun = @{ - RowKey = 'AppSecretExpiry' - PartitionKey = $QueueItem.tenantid - } - Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force } } catch { - + #Write-AlertMessage -tenant $($Item.Tenant) -message "Failed to check App registration expiry for $($Item.Tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderMalware.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderMalware.ps1 index b69ed1b50ab2..0d4d1c7b02ab 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderMalware.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderMalware.ps1 @@ -3,14 +3,13 @@ function Push-CIPPAlertDefenderMalware { [CmdletBinding()] param( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsDeviceMalwareStates?`$top=999&`$filter=tenantId eq '$($QueueItem.tenantid)'" | Where-Object { $_.malwareThreatState -eq 'Active' } | ForEach-Object { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$($_.managedDeviceName): Malware found and active. Severity: $($_.MalwareSeverity). Malware name: $($_.MalwareDisplayName)" + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsDeviceMalwareStates?`$top=999&`$filter=tenantId eq '$($Item.tenantid)'" | Where-Object { $_.malwareThreatState -eq 'Active' } | ForEach-Object { + Write-AlertMessage -tenant $($Item.tenant) -message "$($_.managedDeviceName): Malware found and active. Severity: $($_.MalwareSeverity). Malware name: $($_.MalwareDisplayName)" } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Could not get malware data for $($QueueItem.tenant): $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Could not get malware data for $($Item.tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderStatus.ps1 index e9d4e06adae0..7b42affa4e00 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderStatus.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDefenderStatus.ps1 @@ -1,16 +1,14 @@ - function Push-CIPPAlertDefenderStatus { [CmdletBinding()] param( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsProtectionStates?`$top=999&`$filter=tenantId eq '$($QueueItem.tenantid)'" | Where-Object { $_.realTimeProtectionEnabled -eq $false -or $_.MalwareprotectionEnabled -eq $false } | ForEach-Object { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$($_.managedDeviceName) - Real Time Protection: $($_.realTimeProtectionEnabled) & Malware Protection: $($_.MalwareprotectionEnabled)" + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsProtectionStates?`$top=999&`$filter=tenantId eq '$($Item.tenantid)'" | Where-Object { $_.realTimeProtectionEnabled -eq $false -or $_.MalwareprotectionEnabled -eq $false } | ForEach-Object { + Write-AlertMessage -tenant $($Item.tenant) -message "$($_.managedDeviceName) - Real Time Protection: $($_.realTimeProtectionEnabled) & Malware Protection: $($_.MalwareprotectionEnabled)" } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Could not get defender status for $($QueueItem.tenant): $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Could not get defender status for $($Item.tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1 index 804750e60705..8d457fcb012a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1 @@ -2,31 +2,30 @@ function Push-CIPPAlertDepTokenExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) $LastRunTable = Get-CIPPTable -Table AlertLastRun try { - $Filter = "RowKey eq 'DepTokenExpiry' and PartitionKey eq '{0}'" -f $QueueItem.tenantid + $Filter = "RowKey eq 'DepTokenExpiry' and PartitionKey eq '{0}'" -f $Item.tenantid $LastRun = Get-CIPPAzDataTableEntity @LastRunTable -Filter $Filter $Yesterday = (Get-Date).AddDays(-1) if (-not $LastRun.Timestamp.DateTime -or ($LastRun.Timestamp.DateTime -le $Yesterday)) { try { - $DepTokens = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings' -tenantid $QueueItem.tenant).value + $DepTokens = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings' -tenantid $Item.tenant).value foreach ($Dep in $DepTokens) { if ($Dep.tokenExpirationDateTime -lt (Get-Date).AddDays(30) -and $Dep.tokenExpirationDateTime -gt (Get-Date).AddDays(-7)) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message ('Apple Device Enrollment Program token expiring on {0}' -f $Dep.tokenExpirationDateTime) + Write-AlertMessage -tenant $($Item.tenant) -message ('Apple Device Enrollment Program token expiring on {0}' -f $Dep.tokenExpirationDateTime) } } } catch {} $LastRun = @{ RowKey = 'DepTokenExpiry' - PartitionKey = $QueueItem.tenantid + PartitionKey = $Item.tenantid } Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force } } catch { - # Error handling + Write-AlertMessage -tenant $($Item.tenant) -message "Failed to check Apple Device Enrollment Program token expiry for $($Item.tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertExpiringLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertExpiringLicenses.ps1 index 99a861bfb5d7..6e2a704b9ba3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertExpiringLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertExpiringLicenses.ps1 @@ -2,15 +2,14 @@ function Push-CIPPAlertExpiringLicenses { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - Get-CIPPLicenseOverview -TenantFilter $QueueItem.tenant | ForEach-Object { + Get-CIPPLicenseOverview -TenantFilter $Item.tenant | ForEach-Object { $timeTorenew = [int64]$_.TimeUntilRenew if ($timeTorenew -lt 30 -and $_.TimeUntilRenew -gt 0) { Write-Host "$($_.License) will expire in $($_.TimeUntilRenew) days. The estimated term is $($_.EstTerm)" - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$($_.License) will expire in $($_.TimeUntilRenew) days. The estimated term is $($_.EstTerm)" + Write-AlertMessage -tenant $($Item.tenant) -message "$($_.License) will expire in $($_.TimeUntilRenew) days. The estimated term is $($_.EstTerm)" } } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 index b0c8056e1f03..6b933fbf64a0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1 @@ -2,26 +2,25 @@ function Push-CIPPAlertMFAAdmins { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - $CAPolicies = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies?$top=999' -tenantid $QueueItem.tenant -ErrorAction Stop) + $CAPolicies = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies?$top=999' -tenantid $Item.tenant -ErrorAction Stop) foreach ($Policy in $CAPolicies) { if ($policy.grantControls.customAuthenticationFactors -eq 'RequireDuoMfa') { $DuoActive = $true } } if (!$DuoActive) { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$top=999&$filter=IsAdmin eq true' -tenantid $($QueueItem.tenant) | Where-Object -Property 'isMfaRegistered' -EQ $false - if ($users) { - Write-AlertMessage -tenant $QueueItem.tenant -message "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')" + $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$top=999&$filter=IsAdmin eq true' -tenantid $($Item.tenant) | Where-Object -Property 'isMfaRegistered' -EQ $false + if ($users.UserPrincipalName) { + Write-AlertMessage -tenant $Item.tenant -message "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')" } } else { - Write-LogMessage -message 'Potentially using Duo for MFA, could not check MFA status for Admins with 100% accuracy' -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Info - } + Write-LogMessage -message 'Potentially using Duo for MFA, could not check MFA status for Admins with 100% accuracy' -API 'MFA Alerts - Informational' -tenant $Item.tenant -sev Info + } } catch { - Write-LogMessage -message "Failed to check MFA status for Admins: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Error + Write-LogMessage -message "Failed to check MFA status for Admins: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $Item.tenant -sev Error } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 index 3537616d02ed..e6401a7b117f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 @@ -2,18 +2,17 @@ function Push-CIPPAlertMFAAlertUsers { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isMfaRegistered eq false and userType eq ''member''&$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered' -tenantid $($QueueItem.tenant) - if ($users) { - Write-AlertMessage -tenant $QueueItem.tenant -message "The following $($users.Count) users do not have MFA registered: $($users.UserPrincipalName -join ', ')" + $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isMfaRegistered eq false and userType eq ''member''&$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered' -tenantid $($Item.tenant) + if ($users.UserPrincipalName) { + Write-AlertMessage -tenant $Item.tenant -message "The following $($users.Count) users do not have MFA registered: $($users.UserPrincipalName -join ', ')" } - + } catch { - Write-LogMessage -message "Failed to check MFA status for all users: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $QueueItem.tenant -sev Info + Write-LogMessage -message "Failed to check MFA status for all users: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $Item.tenant -sev Info } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNewRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNewRole.ps1 index 504bb3ea3153..8ef2727ebb66 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNewRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNewRole.ps1 @@ -2,14 +2,13 @@ function Push-CIPPAlertNewRole { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) $Deltatable = Get-CIPPTable -Table DeltaCompare try { - $Filter = "PartitionKey eq 'AdminDelta' and RowKey eq '{0}'" -f $QueueItem.tenantid + $Filter = "PartitionKey eq 'AdminDelta' and RowKey eq '{0}'" -f $Item.tenantid $AdminDelta = (Get-CIPPAzDataTableEntity @Deltatable -Filter $Filter).delta | ConvertFrom-Json -ErrorAction SilentlyContinue - $NewDelta = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/directoryRoles?`$expand=members" -tenantid $QueueItem.tenant) | Select-Object displayname, Members | ForEach-Object { + $NewDelta = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/directoryRoles?`$expand=members" -tenantid $Item.tenant) | Select-Object displayname, Members | ForEach-Object { @{ GroupName = $_.displayname Members = $_.Members.UserPrincipalName @@ -18,7 +17,7 @@ function Push-CIPPAlertNewRole { $NewDeltatoSave = $NewDelta | ConvertTo-Json -Depth 10 -Compress -ErrorAction SilentlyContinue | Out-String $DeltaEntity = @{ PartitionKey = 'AdminDelta' - RowKey = [string]$QueueItem.tenantid + RowKey = [string]$Item.tenantid delta = "$NewDeltatoSave" } Add-CIPPAzDataTableEntity @DeltaTable -Entity $DeltaEntity -Force @@ -27,11 +26,11 @@ function Push-CIPPAlertNewRole { foreach ($Group in $NewDelta) { $OldDelta = $AdminDelta | Where-Object { $_.GroupName -eq $Group.GroupName } $Group.members | Where-Object { $_ -notin $OldDelta.members } | ForEach-Object { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$_ has been added to the $($Group.GroupName) Role" + Write-AlertMessage -tenant $($Item.tenant) -message "$_ has been added to the $($Group.GroupName) Role" } } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Could not get get role changes for $($QueueItem.tenant): $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Could not get get role changes for $($Item.tenant): $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 index 17b5363a1c54..c9b8309963ca 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertNoCAConfig.ps1 @@ -2,20 +2,19 @@ function Push-CIPPAlertNoCAConfig { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - $CAAvailable = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $QueueItem.Tenant -erroraction stop).serviceplans + $CAAvailable = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $Item.Tenant -erroraction stop).serviceplans if ('AAD_PREMIUM' -in $CAAvailable.servicePlanName) { - $CAPolicies = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies' -tenantid $QueueItem.Tenant) + $CAPolicies = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies' -tenantid $Item.Tenant) if (!$CAPolicies.id) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message 'Conditional Access is available, but no policies could be found.' + Write-AlertMessage -tenant $($Item.tenant) -message 'Conditional Access is available, but no policies could be found.' } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Conditional Access Config Alert: Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Conditional Access Config Alert: Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 index af90000fa4d0..d314a064a88a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertOverusedLicenses.ps1 @@ -2,26 +2,25 @@ function Push-CIPPAlertOverusedLicenses { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { $LicenseTable = Get-CIPPTable -TableName ExcludedLicenses $ExcludedSkuList = Get-CIPPAzDataTableEntity @LicenseTable - New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $QueueItem.tenant | ForEach-Object { + New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $Item.tenant | ForEach-Object { $skuid = $_ foreach ($sku in $skuid) { if ($sku.skuId -in $ExcludedSkuList.GUID) { continue } $PrettyName = ($ConvertTable | Where-Object { $_.GUID -eq $sku.skuid }).'Product_Display_Name' | Select-Object -Last 1 if (!$PrettyName) { $PrettyName = $sku.skuPartNumber } if ($sku.prepaidUnits.enabled - $sku.consumedUnits -lt 0) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$PrettyName has Overused licenses. Using $($_.consumedUnits) of $($_.prepaidUnits.enabled)." + Write-AlertMessage -tenant $($Item.tenant) -message "$PrettyName has Overused licenses. Using $($_.consumedUnits) of $($_.prepaidUnits.enabled)." } } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Overused Licenses Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Overused Licenses Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 index 47d455057c19..49ae4105071c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertQuotaUsed.ps1 @@ -2,17 +2,19 @@ function Push-CIPPAlertQuotaUsed { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application/json" -tenantid $QueueItem.tenant | ForEach-Object { + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application/json" -tenantid $Item.tenant | ForEach-Object { if ($_.StorageUsedInBytes -eq 0) { continue } $PercentLeft = [math]::round($_.StorageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes * 100) - if ($PercentLeft -gt 90) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$($_.UserPrincipalName): Mailbox has less than 10% space left. Mailbox is $PercentLeft% full" + if ($Item.value -eq $true) { + if ($Item.value) { $Value = $Item.value } else { $Value = 90 } + if ($PercentLeft -gt 90) { + Write-AlertMessage -tenant $($Item.tenant) -message "$($_.UserPrincipalName): Mailbox is more than $($value)% full. Mailbox is $PercentLeft% full" + } } } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSecDefaultsUpsell.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSecDefaultsUpsell.ps1 index 1380b73b4233..b89347a828a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSecDefaultsUpsell.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSecDefaultsUpsell.ps1 @@ -2,26 +2,25 @@ function Push-CIPPAlertSecDefaultsUpsell { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) $LastRunTable = Get-CIPPTable -Table AlertLastRun try { - $Filter = "RowKey eq 'SecDefaultsUpsell' and PartitionKey eq '{0}'" -f $QueueItem.tenantid + $Filter = "RowKey eq 'SecDefaultsUpsell' and PartitionKey eq '{0}'" -f $Item.tenantid $LastRun = Get-CIPPAzDataTableEntity @LastRunTable -Filter $Filter $Yesterday = (Get-Date).AddDays(-1) if (-not $LastRun.Timestamp.DateTime -or ($LastRun.Timestamp.DateTime -le $Yesterday)) { try { - $SecDefaults = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $QueueItem.tenant) + $SecDefaults = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $Item.tenant) if ($SecDefaults.isEnabled -eq $false -and $SecDefaults.securityDefaultsUpsell.action -in @('autoEnable', 'autoEnabledNotify')) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message ('Security Defaults will be automatically enabled on {0}' -f $SecDefaults.securityDefaultsUpsell.dueDateTime) + Write-AlertMessage -tenant $($Item.tenant) -message ('Security Defaults will be automatically enabled on {0}' -f $SecDefaults.securityDefaultsUpsell.dueDateTime) } } catch {} $LastRun = @{ RowKey = 'SecDefaultsUpsell' - PartitionKey = $QueueItem.tenantid + PartitionKey = $Item.tenantid } Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1 index 0f010b2bb59c..58dedd4888a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1 @@ -3,20 +3,22 @@ function Push-CIPPAlertSharepointQuota { [CmdletBinding()] param( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) Try { - $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $QueueItem.Tenant | Where-Object { $_.isInitial -eq $true }).id.Split('.')[0] - $sharepointToken = (Get-GraphToken -scope "https://$($tenantName)-admin.sharepoint.com/.default" -tenantid $QueueItem.Tenant) + $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $Item.Tenant | Where-Object { $_.isInitial -eq $true }).id.Split('.')[0] + $sharepointToken = (Get-GraphToken -scope "https://$($tenantName)-admin.sharepoint.com/.default" -tenantid $Item.Tenant) $sharepointToken.Add('accept', 'application/json') $sharepointQuota = (Invoke-RestMethod -Method 'GET' -Headers $sharepointToken -Uri "https://$($tenantName)-admin.sharepoint.com/_api/StorageQuotas()?api-version=1.3.2" -ErrorAction Stop).value if ($sharepointQuota) { + if ($Item.value -Is [Boolean]) { $Value = 90 } else { $Value = $Item.value } $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) - if ($UsedStoragePercentage -gt 90) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "SharePoint Storage is at $($UsedStoragePercentage)%" + if ($UsedStoragePercentage -gt $Value) { + Write-AlertMessage -tenant $($Item.tenant) -message "SharePoint Storage is at $($UsedStoragePercentage)%. Your alert threshold is $($Value)%" } } } catch { } -} + + +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 index 2bd58f8b6178..74be1a6e4030 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertUnusedLicenses.ps1 @@ -2,26 +2,25 @@ function Push-CIPPAlertUnusedLicenses { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) try { $LicenseTable = Get-CIPPTable -TableName ExcludedLicenses $ExcludedSkuList = Get-CIPPAzDataTableEntity @LicenseTable - New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $QueueItem.tenant | ForEach-Object { + New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $Item.tenant | ForEach-Object { $skuid = $_ foreach ($sku in $skuid) { if ($sku.skuId -in $ExcludedSkuList.GUID) { continue } $PrettyName = ($ConvertTable | Where-Object { $_.GUID -eq $sku.skuid }).'Product_Display_Name' | Select-Object -Last 1 if (!$PrettyName) { $PrettyName = $sku.skuPartNumber } if ($sku.prepaidUnits.enabled - $sku.consumedUnits -gt 0) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "$PrettyName has unused licenses. Using $($_.consumedUnits) of $($_.prepaidUnits.enabled)." + Write-AlertMessage -tenant $($Item.tenant) -message "$PrettyName has unused licenses. Using $($_.consumedUnits) of $($_.prepaidUnits.enabled)." } } } } catch { - Write-AlertMessage -tenant $($QueueItem.tenant) -message "Unused Licenses Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" + Write-AlertMessage -tenant $($Item.tenant) -message "Unused Licenses Alert Error occurred: $(Get-NormalizedError -message $_.Exception.message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertVppTokenExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertVppTokenExpiry.ps1 index d18dd28dd11d..d9a2e70d6531 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertVppTokenExpiry.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertVppTokenExpiry.ps1 @@ -2,31 +2,30 @@ function Push-CIPPAlertVppTokenExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - $QueueItem, - $TriggerMetadata + $Item ) $LastRunTable = Get-CIPPTable -Table AlertLastRun try { - $Filter = "RowKey eq 'VppTokenExpiry' and PartitionKey eq '{0}'" -f $QueueItem.tenantid + $Filter = "RowKey eq 'VppTokenExpiry' and PartitionKey eq '{0}'" -f $Item.tenantid $LastRun = Get-CIPPAzDataTableEntity @LastRunTable -Filter $Filter $Yesterday = (Get-Date).AddDays(-1) if (-not $LastRun.Timestamp.DateTime -or ($LastRun.Timestamp.DateTime -le $Yesterday)) { try { - $VppTokens = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceAppManagement/vppTokens' -tenantid $QueueItem.tenant).value + $VppTokens = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceAppManagement/vppTokens' -tenantid $Item.tenant).value foreach ($Vpp in $VppTokens) { if ($Vpp.state -ne 'valid') { - Write-AlertMessage -tenant $($QueueItem.tenant) -message 'Apple Volume Purchase Program Token is not valid, new token required' + Write-AlertMessage -tenant $($Item.tenant) -message 'Apple Volume Purchase Program Token is not valid, new token required' } if ($Vpp.expirationDateTime -lt (Get-Date).AddDays(30) -and $Vpp.expirationDateTime -gt (Get-Date).AddDays(-7)) { - Write-AlertMessage -tenant $($QueueItem.tenant) -message ('Apple Volume Purchase Program token expiring on {0}' -f $Vpp.expirationDateTime) + Write-AlertMessage -tenant $($Item.tenant) -message ('Apple Volume Purchase Program token expiring on {0}' -f $Vpp.expirationDateTime) } } } catch {} $LastRun = @{ RowKey = 'VppTokenExpiry' - PartitionKey = $QueueItem.tenantid + PartitionKey = $Item.tenantid } Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPStandard.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPStandard.ps1 index 89a9024a9389..dd9849da8514 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPStandard.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPStandard.ps1 @@ -1,15 +1,15 @@ function Push-CIPPStandard { param ( - $QueueItem, $TriggerMetadata + $Item ) - Write-Host "Received queue item for $($QueueItem.Tenant) and standard $($QueueItem.Standard)." - $Tenant = $QueueItem.Tenant - $Standard = $QueueItem.Standard + Write-Host "Received queue item for $($Item.Tenant) and standard $($Item.Standard)." + $Tenant = $Item.Tenant + $Standard = $Item.Standard $FunctionName = 'Invoke-CIPPStandard{0}' -f $Standard Write-Host "We'll be running $FunctionName" try { - & $FunctionName -Tenant $Tenant -Settings $QueueItem.Settings -ErrorAction Stop + & $FunctionName -Tenant $Item.Tenant -Settings $Item.Settings -ErrorAction Stop } catch { throw $_.Exception.Message } diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ExecGDAPInviteQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ExecGDAPInviteQueue.ps1 new file mode 100644 index 000000000000..833b498eb34e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ExecGDAPInviteQueue.ps1 @@ -0,0 +1,9 @@ +function Push-ExecGDAPInviteQueue { + # Input bindings are passed in via param block. + param($Item) + + # Write out the queue message and metadata to the information log. + Write-Host "PowerShell queue trigger function processed work item: $($Item.customer.displayName)" + + Set-CIPPGDAPInviteGroups -Relationship $Item +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 index 6c12ad723332..24d206b069c7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ExecOnboardTenantQueue.ps1 @@ -4,11 +4,11 @@ Function Push-ExecOnboardTenantQueue { Entrypoint #> [CmdletBinding()] - param($QueueItem, $TriggerMetadata) + param($Item) try { $DateFormat = '%Y-%m-%d %H:%M:%S' - $Id = $QueueItem.id - #Write-Host ($QueueItem.Roles | ConvertTo-Json) + $Id = $Item.id + #Write-Host ($Item.Roles | ConvertTo-Json) $Start = Get-Date $Logs = [System.Collections.Generic.List[object]]::new() $OnboardTable = Get-CIPPTable -TableName 'TenantOnboarding' @@ -117,7 +117,7 @@ Function Push-ExecOnboardTenantQueue { if ($OnboardingSteps.Step2.Status -eq 'succeeded') { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking group mapping' }) $AccessAssignments = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$Id/accessAssignments" - if ($AccessAssignments.id -and $QueueItem.AutoMapRoles -ne $true) { + if ($AccessAssignments.id -and $Item.AutoMapRoles -ne $true) { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Groups mapped' }) $OnboardingSteps.Step3.Status = 'succeeded' $OnboardingSteps.Step3.Message = 'Your GDAP relationship already has mapped security groups' @@ -136,8 +136,8 @@ Function Push-ExecOnboardTenantQueue { $MissingRoles = [System.Collections.Generic.List[object]]::new() $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Relationship has existing access assignments, checking for missing mappings' }) #Write-Host ($AccessAssignments | ConvertTo-Json -Depth 5) - if ($QueueItem.Roles -and $QueueItem.AutoMapRoles -eq $true) { - foreach ($Role in $QueueItem.Roles) { + if ($Item.Roles -and $Item.AutoMapRoles -eq $true) { + foreach ($Role in $Item.Roles) { if ($AccessAssignments.accessContainer.accessContainerid -notcontains $Role.GroupId -and $Relationship.accessDetails.unifiedRoles.roleDefinitionId -contains $Role.roleDefinitionId) { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Adding missing group to relationship: $($Role.GroupName)" }) $MissingRoles.Add([PSCustomObject]$Role) @@ -161,16 +161,16 @@ Function Push-ExecOnboardTenantQueue { } } - if (!$AccessAssignments.id -and !$Invite -and $QueueItem.Roles) { + if (!$AccessAssignments.id -and !$Invite -and $Item.Roles) { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'No access assignments found, using defined role mapping.' }) $MatchingRoles = [System.Collections.Generic.List[object]]::new() - foreach ($Role in $QueueItem.Roles) { + foreach ($Role in $Item.Roles) { if ($Relationship.accessDetails.unifiedRoles.roleDefinitionId -contains $Role.roleDefinitionId) { $MatchingRoles.Add([PSCustomObject]$Role) } } - if (($MatchingRoles | Measure-Object).Count -gt 0 -and $QueueItem.AutoMapRoles -eq $true) { + if (($MatchingRoles | Measure-Object).Count -gt 0 -and $Item.AutoMapRoles -eq $true) { $Invite = [PSCustomObject]@{ 'PartitionKey' = 'invite' 'RowKey' = $Id @@ -224,11 +224,11 @@ Function Push-ExecOnboardTenantQueue { if ($AccessAssignments.status -notcontains 'pending') { $OnboardingSteps.Step3.Message = 'Group check: Access assignments are mapped and active' $OnboardingSteps.Step3.Status = 'succeeded' - if ($QueueItem.AddMissingGroups -eq $true) { + if ($Item.AddMissingGroups -eq $true) { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking for missing groups for SAM user' }) $SamUserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me?`$select=id").id $CurrentMemberships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me/transitiveMemberOf?`$select=id,displayName" - foreach ($Role in $QueueItem.Roles) { + foreach ($Role in $Item.Roles) { if ($CurrentMemberships.id -notcontains $Role.GroupId) { $PostBody = @{ '@odata.id' = 'https://graph.microsoft.com/v1.0/directoryObjects/{0}' -f $SamUserId diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ExecScheduledCommand.ps1 new file mode 100644 index 000000000000..8e53dcbd8bd4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ExecScheduledCommand.ps1 @@ -0,0 +1,85 @@ +function Push-ExecScheduledCommand { + # Input bindings are passed in via param block. + param($Item) + + $Table = Get-CippTable -tablename 'ScheduledTasks' + $task = $Item.TaskInfo + $commandParameters = $Item.Parameters + + $tenant = $Item.Parameters['TenantFilter'] + Write-Host 'started task' + try { + try { + $results = & $Item.command @commandParameters + } catch { + $results = "Task Failed: $($_.Exception.Message)" + + } + + Write-Host 'ran the command' + if ($results -is [String]) { + $results = @{ Results = $results } + } + if ($results -is [array] -and $results[0] -is [string]) { + $results = $results | Where-Object { $_ -is [string] } + $results = $results | ForEach-Object { @{ Results = $_ } } + } + + $results = $results | Select-Object * -ExcludeProperty RowKey, PartitionKey + + $StoredResults = $results | ConvertTo-Json -Compress -Depth 20 | Out-String + if ($StoredResults.Length -gt 64000 -or $task.Tenant -eq 'AllTenants') { + $StoredResults = @{ Results = 'The results for this query are too long to store in this table, or the query was meant for All Tenants. Please use the options to send the results to another target to be able to view the results. ' } | ConvertTo-Json -Compress + } + } catch { + $errorMessage = $_.Exception.Message + if ($task.Recurrence -gt 0) { $State = 'Failed - Planned' } else { $State = 'Failed' } + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$errorMessage" + TaskState = $State + } + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error + } + + + $TableDesign = '' + $HTML = ($results | Select-Object * -ExcludeProperty RowKey, PartitionKey | ConvertTo-Html -Fragment) -replace '
', "$TableDesign
" | Out-String + $title = "Scheduled Task $($task.Name) - $($task.ExpectedRunTime)" + Write-Host $title + switch -wildcard ($task.PostExecution) { + '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML } + '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML } + '*webhook*' { + $Webhook = [PSCustomObject]@{ + 'Tenant' = $tenant + 'TaskInfo' = $Item.TaskInfo + 'Results' = $Results + } + Send-CIPPAlert -Type 'webhook' -Title $title -JSONContent $($Webhook | ConvertTo-Json -Depth 20) + } + } + + Write-Host 'ran the command' + + if ($task.Recurrence -le '0' -or $task.Recurrence -eq $null) { + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$StoredResults" + TaskState = 'Completed' + } + } else { + $nextRun = (Get-Date).AddDays($task.Recurrence) + $nextRunUnixTime = [int64]($nextRun - (Get-Date '1/1/1970')).TotalSeconds + Update-AzDataTableEntity @Table -Entity @{ + PartitionKey = $task.PartitionKey + RowKey = $task.RowKey + Results = "$StoredResults" + TaskState = 'Planned' + ScheduledTime = "$nextRunUnixTime" + } + } + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Successfully executed task: $($task.name)" -sev Info +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 index 82f12e1df665..1705df9a7f70 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ListGraphRequestQueue.ps1 @@ -4,36 +4,36 @@ function Push-ListGraphRequestQueue { Entrypoint #> # Input bindings are passed in via param block. - param($QueueItem, $TriggerMetadata) + param($Item) # Write out the queue message and metadata to the information log. - Write-Host "PowerShell queue trigger function processed work item: $($QueueItem.Endpoint) - $($QueueItem.TenantFilter)" + Write-Host "PowerShell queue trigger function processed work item: $($Item.Endpoint) - $($Item.TenantFilter)" - $TenantQueueName = '{0} - {1}' -f $QueueItem.QueueName, $QueueItem.TenantFilter - Update-CippQueueEntry -RowKey $QueueItem.QueueId -Status 'Processing' -Name $TenantQueueName + $TenantQueueName = '{0} - {1}' -f $Item.QueueName, $Item.TenantFilter + Update-CippQueueEntry -RowKey $Item.QueueId -Status 'Processing' -Name $TenantQueueName $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) - foreach ($Item in ($QueueItem.Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { - $ParamCollection.Add($Item.Key, $Item.Value) + foreach ($Param in ($Item.Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { + $ParamCollection.Add($Param.Key, $Param.Value) } - $PartitionKey = $QueueItem.PartitionKey + $PartitionKey = $Item.PartitionKey - $TableName = ('cache{0}' -f ($QueueItem.Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' - Write-Host $TableName + $TableName = ('cache{0}' -f ($Item.Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' + Write-Host "Queue Table: $TableName" $Table = Get-CIPPTable -TableName $TableName - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $QueueItem.TenantFilter - Write-Host $Filter + $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $Item.TenantFilter + Write-Host "Filter: $Filter" Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey | Remove-AzDataTableEntity @Table $GraphRequestParams = @{ - TenantFilter = $QueueItem.TenantFilter - Endpoint = $QueueItem.Endpoint - Parameters = $QueueItem.Parameters - NoPagination = $QueueItem.NoPagination - ReverseTenantLookupProperty = $QueueItem.ReverseTenantLookupProperty - ReverseTenantLookup = $QueueItem.ReverseTenantLookup + TenantFilter = $Item.TenantFilter + Endpoint = $Item.Endpoint + Parameters = $Item.Parameters + NoPagination = $Item.NoPagination + ReverseTenantLookupProperty = $Item.ReverseTenantLookupProperty + ReverseTenantLookup = $Item.ReverseTenantLookup SkipCache = $true } @@ -41,7 +41,7 @@ function Push-ListGraphRequestQueue { Get-GraphRequestList @GraphRequestParams } catch { [PSCustomObject]@{ - Tenant = $QueueItem.Tenant + Tenant = $Item.Tenant CippStatus = "Could not connect to tenant. $($_.Exception.message)" } } @@ -49,9 +49,9 @@ function Push-ListGraphRequestQueue { $GraphResults = foreach ($Request in $RawGraphRequest) { $Json = ConvertTo-Json -Depth 5 -Compress -InputObject $Request [PSCustomObject]@{ - TenantFilter = [string]$QueueItem.TenantFilter - QueueId = [string]$QueueItem.QueueId - QueueType = [string]$QueueItem.QueueType + TenantFilter = [string]$Item.TenantFilter + QueueId = [string]$Item.QueueId + QueueType = [string]$Item.QueueType RowKey = [string](New-Guid) PartitionKey = [string]$PartitionKey Data = [string]$Json @@ -59,9 +59,9 @@ function Push-ListGraphRequestQueue { } try { Add-CIPPAzDataTableEntity @Table -Entity $GraphResults -Force | Out-Null - Update-CippQueueEntry -RowKey $QueueItem.QueueId -Status 'Completed' + Update-CippQueueEntry -RowKey $Item.QueueId -Status 'Completed' } catch { Write-Host "Queue Error: $($_.Exception.Message)" - Update-CippQueueEntry -RowKey $QueueItem.QueueId -Status 'Failed' + Update-CippQueueEntry -RowKey $Item.QueueId -Status 'Failed' } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ListLicensesQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ListLicensesQueue.ps1 new file mode 100644 index 000000000000..f587fa65fe39 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ListLicensesQueue.ps1 @@ -0,0 +1,22 @@ +function Push-ListLicensesQueue { + # Input bindings are passed in via param block. + param($Item) + + # Write out the queue message and metadata to the information log. + Write-Host "PowerShell queue trigger function processed work item: $($Item.defaultDomainName)" + + $domainName = $Item.defaultDomainName + $GraphRequest = try { + Write-Host "Processing $domainName" + Get-CIPPLicenseOverview -TenantFilter $domainName + } catch { + [pscustomobject]@{ + Tenant = [string]$domainName + License = "Could not connect to client: $($_.Exception.Message)" + 'PartitionKey' = 'License' + 'RowKey' = "$($domainName)-$((New-Guid).Guid)" + } + } + $Table = Get-CIPPTable -TableName cachelicenses + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-ListMFAUsersQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ListMFAUsersQueue.ps1 new file mode 100644 index 000000000000..89e9d1dbd3bd --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ListMFAUsersQueue.ps1 @@ -0,0 +1,50 @@ +function Push-ListMFAUsersQueue { + # Input bindings are passed in via param block. + param($Item) + + # Write out the queue message and metadata to the information log. + Write-Host "PowerShell queue trigger function processed work item: $($Item.defaultDomainName)" + + try { + Update-CippQueueEntry -RowKey $Item.QueueId -Status 'Running' -Name $Item.displayName + $domainName = $Item.defaultDomainName + $Table = Get-CIPPTable -TableName cachemfa + Try { + $GraphRequest = Get-CIPPMFAState -TenantFilter $domainName -ErrorAction Stop + } catch { + $GraphRequest = $null + } + if (!$GraphRequest) { + $GraphRequest = @{ + Tenant = [string]$domainName + UPN = [string]$domainName + AccountEnabled = 'none' + PerUser = [string]'Could not connect to tenant' + MFARegistration = 'none' + CoveredByCA = [string]'Could not connect to tenant' + CoveredBySD = 'none' + RowKey = [string]"$domainName" + PartitionKey = 'users' + } + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + + } catch { + $Table = Get-CIPPTable -TableName cachemfa + $GraphRequest = @{ + Tenant = [string]$domainName + UPN = [string]$domainName + AccountEnabled = 'none' + PerUser = [string]'Could not connect to tenant' + MFARegistration = 'none' + CoveredByCA = [string]'Could not connect to tenant' + CoveredBySD = 'none' + RowKey = [string]"$domainName" + PartitionKey = 'users' + } + Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null + } finally { + Update-CippQueueEntry -RowKey $QueueItem -Status 'Completed' + } + +} \ No newline at end of file diff --git a/ListMailboxRulesAllTenants/run.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-ListMailboxRulesQueue.ps1 similarity index 77% rename from ListMailboxRulesAllTenants/run.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Push-ListMailboxRulesQueue.ps1 index 36b671ad11f6..5c7ba40b2f06 100644 --- a/ListMailboxRulesAllTenants/run.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-ListMailboxRulesQueue.ps1 @@ -1,20 +1,12 @@ -# Input bindings are passed in via param block. -param([string] $QueueItem, $TriggerMetadata) +function Push-ListMailboxRulesQueue { + # Input bindings are passed in via param block. + param($Item) -# Write out the queue message and metadata to the information log. -Write-Host "PowerShell queue trigger function processed work item: $QueueItem" + # Write out the queue message and metadata to the information log. + Write-Host "PowerShell queue trigger function processed work item: $($Item.defaultDomainName)" + + $domainName = $Item.defaultDomainName -$Tenants = if ($QueueItem -ne 'AllTenants') { - [PSCustomObject]@{ - defaultDomainName = $QueueItem - } -} else { - Get-Tenants -} -$Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module CippCore - Import-Module AzBobbyTables $Table = Get-CIPPTable -TableName cachembxrules try { $Rules = New-ExoRequest -tenantid $domainName -cmdlet 'Get-Mailbox' -Select 'userPrincipalName,GUID' | ForEach-Object -Parallel { diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-PublicWebhookProcess.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-PublicWebhookProcess.ps1 new file mode 100644 index 000000000000..4d321a825f4e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-PublicWebhookProcess.ps1 @@ -0,0 +1,17 @@ +function Push-PublicWebhookProcess { + param($Item) + + try { + if ($Item.Type -eq 'GraphSubscription') { + Invoke-CippGraphWebhookProcessing -Data ($Item.Data | ConvertFrom-Json) -CIPPID $Item.CIPPID -WebhookInfo ($Item.Webhookinfo | ConvertFrom-Json) + } elseif ($Item.Type -eq 'AuditLog') { + Invoke-CippWebhookProcessing -TenantFilter $Item.TenantFilter -Data ($Item.Data | ConvertFrom-Json) -CIPPPURL $Item.CIPPURL + } + } catch { + Write-Host "Webhook Exception: $($_.Exception.Message)" + } finally { + $WebhookIncoming = Get-CIPPTable -TableName WebhookIncoming + $Entity = $Item | Select-Object -Property RowKey, PartitionKey + Remove-AzDataTableEntity @WebhookIncoming -Entity $Entity + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 index 5b32b6fb3c51..40fb4f9c404f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1 @@ -1,41 +1,63 @@ function Push-SchedulerAlert { param ( - $QueueItem, $TriggerMetadata + $Item ) - $Tenant = $QueueItem + try { $Table = Get-CIPPTable -Table SchedulerConfig - if ($Tenant.tag -eq 'AllTenants') { + if ($Item.Tag -eq 'AllTenants') { $Filter = "RowKey eq 'AllTenants' and PartitionKey eq 'Alert'" } else { - $Filter = "RowKey eq '{0}' and PartitionKey eq 'Alert'" -f $Tenant.tenantid + $Filter = "RowKey eq '{0}' and PartitionKey eq 'Alert'" -f $Item.Tenantid } $Alerts = Get-CIPPAzDataTableEntity @Table -Filter $Filter - $IgnoreList = @('Etag', 'PartitionKey', 'Timestamp', 'RowKey', 'tenantid', 'tenant', 'type') - $alertList = $Alerts | Select-Object * -ExcludeProperty $IgnoreList - foreach ($task in ($AlertList.psobject.members | Where-Object { $_.MemberType -EQ 'NoteProperty' -and $_.value -eq $True }).name) { + $AlertList = $Alerts | Select-Object * -ExcludeProperty $IgnoreList + $Batch = foreach ($task in ($AlertList.psobject.members | Where-Object { $_.MemberType -EQ 'NoteProperty' -and $_.value -ne $false })) { $Table = Get-CIPPTable -TableName AlertRunCheck - $Filter = "PartitionKey eq '{0}' and RowKey eq '{1}' and Timestamp ge datetime'{2}'" -f $tenant.tenant, $task, (Get-Date).AddMinutes(-10).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss') + $Filter = "PartitionKey eq '{0}' and RowKey eq '{1}' and Timestamp ge datetime'{2}'" -f $Item.Tenant, $task.Name, (Get-Date).AddMinutes(-10).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss') $ExistingMessage = Get-CIPPAzDataTableEntity @Table -Filter $Filter if (!$ExistingMessage) { - $QueueItem = [pscustomobject]@{ - tenant = $tenant.tenant - tenantid = $tenant.tenantid - FunctionName = "CIPPAlert$($Task)" + [pscustomobject]@{ + Tenant = $Item.Tenant + Tenantid = $Item.Tenantid + FunctionName = "CIPPAlert$($Task.Name)" + value = $Task.value + } + #Push-OutputBinding -Name QueueItemOut -Value $Item + $Item | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value $task.Name -Force + $Item | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value $Item.Tenant -Force + + if ($null -eq $Item.Tenant) { + Write-Host ($Item | ConvertTo-Json) + } else { + try { + $null = Add-CIPPAzDataTableEntity @Table -Entity $Item -Force -ErrorAction Stop + } catch { + Write-Host "################### Error updating alert $($_.Exception.Message) - Task:$($Task.Name) PK:$($Item.PartitionKey)" + } } - Push-OutputBinding -Name QueueItemOut -Value $QueueItem - $QueueItem | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value $task -Force - $QueueItem | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value $tenant.tenant -Force - Add-CIPPAzDataTableEntity @Table -Entity $QueueItem -Force } else { - Write-Host ('ALERTS: Duplicate run found. Ignoring. Tenant: {0}, Task: {1}' -f $tenant.tenant, $task) + Write-Host ('ALERTS: Duplicate run found. Ignoring. Tenant: {0}, Task: {1}' -f $Item.Tenant, $task.Name) } } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'AlertsOrchestrator' + SkipLog = $true + Batch = @($Batch) + } + #Write-Host ($Batch | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started alert orchestration with ID = '$InstanceId'" + #$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId + } else { + Write-Host 'No alerts to process' + } } catch { $Message = 'Exception on line {0} - {1}' -f $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message - Write-LogMessage -message $Message -API 'Alerts' -tenant $tenant.tenant -sev Error + Write-LogMessage -message $Message -API 'Alerts' -tenant $Item.tenant -sev Error } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-UpdatePermissionsQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-UpdatePermissionsQueue.ps1 new file mode 100644 index 000000000000..e1d72b14e867 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Push-UpdatePermissionsQueue.ps1 @@ -0,0 +1,17 @@ +function Push-UpdatePermissionsQueue { + # Input bindings are passed in via param block. + param($Item) + Write-Host "Applying permissions for $($Item.defaultDomainName)" + $Table = Get-CIPPTable -TableName cpvtenants + $CPVRows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Tenant -EQ $Item.customerId + if (!$CPVRows -or $ENV:ApplicationID -notin $CPVRows.applicationId) { + Write-LogMessage -tenant $Item.defaultDomainName -tenantId $Item.customerId -message 'A New tenant has been added, or a new CIPP-SAM Application is in use' -Sev 'Warn' -API 'NewTenant' + Write-Host 'Adding CPV permissions' + Set-CIPPCPVConsent -Tenantfilter $Item.defaultDomainName + } + + Add-CIPPApplicationPermission -RequiredResourceAccess 'CippDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $Item.defaultDomainName + Add-CIPPDelegatedPermission -RequiredResourceAccess 'CippDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $Item.defaultDomainName + + Write-LogMessage -tenant $Item.defaultDomainName -tenantId $Item.customerId -message "Updated permissions for $($Item.defaultDomainName)" -Sev 'Info' -API 'UpdatePermissionsQueue' +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Get-CIPPLicenseOverview.ps1 b/Modules/CIPPCore/Public/Get-CIPPLicenseOverview.ps1 index 698d30653774..9668cd51b50e 100644 --- a/Modules/CIPPCore/Public/Get-CIPPLicenseOverview.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPLicenseOverview.ps1 @@ -3,19 +3,17 @@ function Get-CIPPLicenseOverview { [CmdletBinding()] param ( $TenantFilter, - $APIName = "Get License Overview", + $APIName = 'Get License Overview', $ExecutingUser ) $LicRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $TenantFilter - $LicOverviewRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/directory/subscriptions' -tenantid $TenantFilter | Where-Object -Property nextLifecycleDateTime -GT (Get-Date) | Select-Object *, - @{Name = 'consumedUnits'; Expression = { ($LicRequest | Where-Object -Property skuid -EQ $_.skuId).consumedUnits } }, - @{Name = 'prepaidUnits'; Expression = { ($LicRequest | Where-Object -Property skuid -EQ $_.skuId).prepaidUnits } } + $SkuIDs = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/directory/subscriptions' -tenantid $TenantFilter $RawGraphRequest = [PSCustomObject]@{ Tenant = $TenantFilter - Licenses = $LicOverviewRequest + Licenses = $LicRequest } Set-Location (Get-Item $PSScriptRoot).FullName $ConvertTable = Import-Csv Conversiontable.csv @@ -27,33 +25,42 @@ function Get-CIPPLicenseOverview { if ($sku.skuId -in $ExcludedSkuList.GUID) { continue } $PrettyName = ($ConvertTable | Where-Object { $_.guid -eq $sku.skuid }).'Product_Display_Name' | Select-Object -Last 1 if (!$PrettyName) { $PrettyName = $sku.skuPartNumber } - $diff = $sku.nextLifecycleDateTime - $sku.createdDateTime + # Initialize $Term with the default value - $Term = "Term unknown or non-NCE license" - if ($diff.Days -ge 360 -and $diff.Days -le 1089) { - $Term = "Yearly" + $TermInfo = foreach ($Subscription in $sku.subscriptionIds) { + $SubInfo = $SkuIDs | Where-Object { $_.id -eq $Subscription } + $diff = $SubInfo.nextLifecycleDateTime - $SubInfo.createdDateTime + $Term = 'Term unknown or non-NCE license' + if ($diff.Days -ge 360 -and $diff.Days -le 1089) { + $Term = 'Yearly' + } elseif ($diff.Days -ge 1090 -and $diff.Days -le 1100) { + $Term = '3 Year' + } elseif ($diff.Days -ge 25 -and $diff.Days -le 35) { + $Term = 'Monthly' + } + $TimeUntilRenew = ($subinfo.nextLifecycleDateTime - (Get-Date)).days + [PSCustomObject]@{ + Status = $SubInfo.status + Term = $Term + TotalLicenses = $SubInfo.totalLicenses + DaysUntilRenew = $TimeUntilRenew + NextLifecycle = $SubInfo.nextLifecycleDateTime + IsTrial = $SubInfo.isTrial + SubscriptionId = $subinfo.id + CSPSubscriptionId = $SubInfo.commerceSubscriptionId + OCPSubscriptionId = $SubInfo.ocpSubscriptionId + } } - elseif ($diff.Days -ge 1090 -and $diff.Days -le 1100) { - $Term = "3 Year" - } - elseif ($diff.Days -ge 25 -and $diff.Days -le 35) { - $Term = "Monthly" - } - $TimeUntilRenew = $sku.nextLifecycleDateTime - (Get-Date) [pscustomobject]@{ Tenant = [string]$singlereq.Tenant License = [string]$PrettyName CountUsed = [string]"$($sku.consumedUnits)" CountAvailable = [string]$sku.prepaidUnits.enabled - $sku.consumedUnits - TotalLicenses = [string]"$($sku.TotalLicenses)" + TotalLicenses = [string]"$($sku.prepaidUnits.enabled)" skuId = [string]$sku.skuId skuPartNumber = [string]$PrettyName availableUnits = [string]$sku.prepaidUnits.enabled - $sku.consumedUnits - EstTerm = [string]$Term - TimeUntilRenew = [string]"$($TimeUntilRenew.Days)" - Trial = [bool]$sku.isTrial - dateCreated = [string]$sku.createdDateTime - dateExpires = [string]$sku.nextLifecycleDateTime + TermInfo = [string]($TermInfo | ConvertTo-Json -Depth 10 -Compress) 'PartitionKey' = 'License' 'RowKey' = "$($singlereq.Tenant) - $($sku.skuid)" } diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 index cac4bf0a3173..91d7ce2cd4cc 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 @@ -15,21 +15,27 @@ function Write-CippFunctionStats { $RowKey = [string](New-Guid).Guid $TimeSpan = New-TimeSpan -Start $Start -End $End $Duration = [int]$TimeSpan.TotalSeconds - + $DurationMS = [int]$TimeSpan.TotalMilliseconds + + $StatEntity = @{} # Flatten data to json string - $Entity.PartitionKey = $FunctionType - $Entity.RowKey = $RowKey - $Entity.Start = $Start - $Entity.End = $End - $Entity.Duration = $Duration - $Entity.ErrorMsg = $ErrorMsg + $StatEntity.PartitionKey = $FunctionType + $StatEntity.RowKey = $RowKey + $StatEntity.Start = $Start + $StatEntity.End = $End + $StatEntity.Duration = $Duration + $StatEntity.DurationMS = $DurationMS + $StatEntity.ErrorMsg = $ErrorMsg $Entity = [PSCustomObject]$Entity foreach ($Property in $Entity.PSObject.Properties.Name) { if ($Entity.$Property.GetType().Name -in ('Hashtable', 'PSCustomObject')) { - $Entity.$Property = [string]($Entity.$Property | ConvertTo-Json -Compress) + $StatEntity.$Property = [string]($Entity.$Property | ConvertTo-Json -Compress) + } elseif ($Property -notin ('ETag', 'RowKey', 'PartitionKey', 'Timestamp', 'LastRefresh')) { + $StatEntity.$Property = $Entity.$Property } } - Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + $StatEntity = [PSCustomObject]$StatEntity + Add-CIPPAzDataTableEntity @Table -Entity $StatEntity -Force } catch { Write-Host "Exception logging stats $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index 3b3b4660a0bf..1117f95d196d 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -68,6 +68,7 @@ function Get-GraphRequestList { $TableName = ('cache{0}' -f ($Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' Write-Host "Table: $TableName" + $Endpoint = $Endpoint -replace '^/', '' $DisplayName = ($Endpoint -split '/')[0] if ($QueueNameOverride) { @@ -112,6 +113,17 @@ function Get-GraphRequestList { $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey $RunningQueue = Get-CippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } + if ($TenantFilter -ne 'AllTenants' -and $Endpoint -match '%tenantid%') { + $TenantId = (Get-Tenants -IncludeErrors | Where-Object { $_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter }).customerId + $Endpoint = $Endpoint -replace '%tenantid%', $TenantId + $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) + $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + foreach ($Item in ($Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { + $ParamCollection.Add($Item.Key, $Item.Value) + } + $GraphQuery.Query = $ParamCollection.ToString() + } + if (!$Rows) { switch ($TenantFilter) { 'AllTenants' { @@ -158,9 +170,9 @@ function Get-GraphRequestList { } Write-Host 'Pushing output bindings' try { - Get-Tenants -IncludeErrors | ForEach-Object { + $Batch = Get-Tenants -IncludeErrors | ForEach-Object { $TenantFilter = $_.defaultDomainName - $QueueTenant = [PSCustomObject]@{ + [PSCustomObject]@{ FunctionName = 'ListGraphRequestQueue' TenantFilter = $TenantFilter Endpoint = $Endpoint @@ -175,8 +187,15 @@ function Get-GraphRequestList { ReverseTenantLookup = $ReverseTenantLookup.IsPresent } - Push-OutputBinding -Name QueueItem -Value $QueueTenant + #Push-OutputBinding -Name QueueItem -Value $QueueTenant } + + $InputObject = @{ + OrchestratorName = 'GraphRequestOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json -Depth 5) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) } catch { Write-Host "QUEUE ERROR: $($_.Exception.Message)" } @@ -234,7 +253,13 @@ function Get-GraphRequestList { ReverseTenantLookup = $ReverseTenantLookup.IsPresent } - Push-OutputBinding -Name QueueItem -Value $QueueTenant + $InputObject = @{ + OrchestratorName = 'GraphRequestOrchestrator' + Batch = @($QueueTenant) + } + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + + #Push-OutputBinding -Name QueueItem -Value $QueueTenant [PSCustomObject]@{ QueueMessage = ('Loading {0} rows for {1}. Please check back after the job completes' -f $Count, $TenantFilter) diff --git a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 index 353551cdaadf..8dd8055c6c93 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 @@ -1,4 +1,4 @@ - + function Invoke-CIPPStandardsRun { [CmdletBinding()] param( @@ -20,7 +20,7 @@ function Invoke-CIPPStandardsRun { $OldStd = $_ $OldStd.standards.psobject.properties.name | ForEach-Object { if ($_ -eq 'MailContacts') { - $OldStd.Standards.$_ = [pscustomobject]@{ + $OldStd.Standards.$_ = [pscustomobject]@{ GeneralContact = $OldStd.Standards.MailContacts.GeneralContact.Mail SecurityContact = $OldStd.Standards.MailContacts.SecurityContact.Mail MarketingContact = $OldStd.Standards.MailContacts.MarketingContact.Mail @@ -28,16 +28,16 @@ function Invoke-CIPPStandardsRun { remediate = $true } } else { - if ($OldStd.Standards.$_ -eq $true -and $_ -ne 'v2.1') { - $OldStd.Standards.$_ = @{ remediate = $true } - } else { - $OldStd.Standards.$_ | Add-Member -NotePropertyName 'remediate' -NotePropertyValue $true -Force + if ($OldStd.Standards.$_ -eq $true -and $_ -ne 'v2.1') { + $OldStd.Standards.$_ = @{ remediate = $true } + } else { + $OldStd.Standards.$_ | Add-Member -NotePropertyName 'remediate' -NotePropertyValue $true -Force } - + } } $OldStd | Add-Member -NotePropertyName 'v2.1' -NotePropertyValue $true -PassThru -Force - $Entity = @{ + $Entity = @{ PartitionKey = 'standards' RowKey = "$($OldStd.Tenant)" JSON = "$($OldStd | ConvertTo-Json -Depth 10)" @@ -76,15 +76,23 @@ function Invoke-CIPPStandardsRun { } } - #For each item in our object, run the queue. + #For each item in our object, run the queue. - foreach ($task in $object | Where-Object -Property Standard -NotLike 'v2*') { - $QueueItem = [pscustomobject]@{ + $Batch = foreach ($task in $object | Where-Object { $_.Standard -NotLike 'v2*' -and ($_.Settings.remediate -eq $true -or $_.Settings.alert -eq $true -or $_.Settings.report -eq $true) }) { + [PSCustomObject]@{ Tenant = $task.Tenant Standard = $task.Standard Settings = $task.Settings FunctionName = 'CIPPStandard' } - Push-OutputBinding -Name QueueItem -Value $QueueItem } + + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'Standards' + Batch = @($Batch) + } + + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started orchestration with ID = '$InstanceId'" + #$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 index 77139f1ddaba..db62dae8b160 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 @@ -67,6 +67,7 @@ function Invoke-CippWebhookProcessing { 'OAuth2:Token' 'SAS:EndAuth' 'SAS:ProcessAuth' + 'Login:reprocess' ) if ($TableObj.RequestType -in $ExtendedPropertiesIgnoreList) { Write-Host 'No need to process this operation.' diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index 0ecfd722c6cf..1d749a69bf76 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -107,7 +107,7 @@ function New-CIPPCAPolicy { Write-Host $RawJSON try { Write-Host 'Checking' - $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies' -tenantid $TenantFilter + $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $TenantFilter if ($displayname -in $CheckExististing.displayName) { if ($Overwrite -ne $true) { Throw "Conditional Access Policy with Display Name $($Displayname) Already exists" diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 index 9567039fe8e4..54c6a33e1a9d 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPGroupMember.ps1 @@ -16,7 +16,7 @@ function Remove-CIPPGroupMember( } else { New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)/members/$($Member)/`$ref" -tenantid $TenantFilter -type DELETE -body '{}' -Verbose } - $Message = "Successfully removed user $($Member) from $GroupId." + $Message = "Successfully removed user $($Member) from $($GroupId)." Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' return $message } catch { diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index a253311fae29..55d7e9db9803 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -18,7 +18,7 @@ function Send-CIPPAlert { Write-Host "Trying to send email" try { if ($Config.email -like '*@*') { - $Recipients = $Config.email.split(",").trim() | ForEach-Object { if ($_ -like '*@*') { [pscustomobject]@{EmailAddress = @{Address = $_ } } } } + $Recipients = $Config.email.split($(if ($Config.email -like "*,*") { ',' } else { ';' })).trim() | ForEach-Object { if ($_ -like '*@*') { [pscustomobject]@{EmailAddress = @{Address = $_ } } } } $PowerShellBody = [PSCustomObject]@{ message = @{ subject = $Title diff --git a/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 b/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 index 407eccddc796..e2ae2dba708d 100644 --- a/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPGDAPInviteGroups.ps1 @@ -35,12 +35,23 @@ function Set-CIPPGDAPInviteGroups { if (($InviteList | Measure-Object).Count -gt 0) { $Activations = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships?`$filter=status eq 'active'" - foreach ($Activation in $Activations) { + $Batch = foreach ($Activation in $Activations) { if ($InviteList.RowKey -contains $Activation.id) { Write-Host "Mapping groups for GDAP relationship: $($Activation.customer.displayName) - $($Activation.id)" - Push-OutputBinding -Name gdapinvitequeue -Value $Activation + $Activation | Add-Member -NotePropertyName FunctionName -NotePropertyValue 'ExecGDAPInviteQueue' + $Activation } } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'GDAPInviteOrchestrator' + Batch = @($Batch) + SkipLog = $true + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started GDAP Invite orchestration with ID = '$InstanceId'" + } } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 index 1dcd16e89cdb..e3682928503c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 @@ -4,13 +4,13 @@ function Invoke-CIPPStandardAuditLog { Internal #> param($Tenant, $Settings) - - $AuditLogEnabled = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AdminAuditLogConfig').UnifiedAuditLogIngestionEnabled + Write-Host ($Settings | ConvertTo-Json) + $AuditLogEnabled = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AdminAuditLogConfig' -Select UnifiedAuditLogIngestionEnabled).UnifiedAuditLogIngestionEnabled If ($Settings.remediate) { Write-Host 'Time to remediate' - - $DehydratedTenant = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').IsDehydrated + + $DehydratedTenant = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' -Select IsDehydrated).IsDehydrated if ($DehydratedTenant) { try { New-ExoRequest -tenantid $Tenant -cmdlet 'Enable-OrganizationCustomization' @@ -20,7 +20,7 @@ function Invoke-CIPPStandardAuditLog { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable organization customization. Error: $ErrorMessage" -sev Debug } } - + try { if ($AuditLogEnabled) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Unified Audit Log already enabled.' -sev Info diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 new file mode 100644 index 000000000000..0d1d2d2a0af6 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 @@ -0,0 +1,37 @@ +function Invoke-CIPPStandardDisableAppCreation { + <# + .FUNCTIONALITY + Internal + #> + param($Tenant, $Settings) + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy?$select=defaultUserRolePermissions' -tenantid $Tenant + + If ($Settings.remediate) { + if ($CurrentInfo.defaultUserRolePermissions.allowedToCreateApps -eq $false) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Users are already not allowed to create App registrations.' -sev Info + } else { + try { + $body = '{"defaultUserRolePermissions":{"allowedToCreateApps":false}}' + $null = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -Type patch -Body $body -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Disabled users from creating App registrations.' -sev Info + $CurrentInfo.defaultUserRolePermissions.allowedToCreateApps = $false + } catch { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable users from creating App registrations: $($_.exception.message)" -sev Error + } + } + } + + if ($Settings.alert) { + + if ($CurrentInfo.defaultUserRolePermissions.allowedToCreateApps -eq $false) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Users are not allowed to create App registrations.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Users are allowed to create App registrations.' -sev Alert + } + } + + if ($Settings.report) { + $State = -not $CurrentInfo.defaultUserRolePermissions.allowedToCreateApps + Add-CIPPBPAField -FieldName 'UserAppCreationDisabled' -FieldValue [bool]$State -StoreAs bool -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 index 3a9e7ef1eacd..6d959f03d8d9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 @@ -21,7 +21,7 @@ function Invoke-CIPPStandardEnableMailboxAuditing { } # Check for mailbox audit on all mailboxes. Enable for all that it's not enabled for - $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{ResultSize = 'Unlimited' } | Where-Object { $_.AuditEnabled -ne $true } + $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{filter = "auditenabled -eq 'False'" } -useSystemMailbox $true -Select 'AuditEnabled,UserPrincipalName' $Mailboxes | ForEach-Object { try { New-ExoRequest -tenantid $Tenant -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $_.UserPrincipalName; AuditEnabled = $true } -Anchor $_.UserPrincipalName @@ -32,7 +32,8 @@ function Invoke-CIPPStandardEnableMailboxAuditing { } # Disable audit bypass for all mailboxes that have it enabled - $BypassMailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MailboxAuditBypassAssociation' -cmdParams @{ResultSize = 'Unlimited' } | Where-Object { $_.AuditBypassEnabled -eq $true } + + $BypassMailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MailboxAuditBypassAssociation' -select 'GUID, AuditBypassEnabled, Name' -useSystemMailbox $true | Where-Object { $_.AuditBypassEnabled -eq $true } $BypassMailboxes | ForEach-Object { try { New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MailboxAuditBypassAssociation' -cmdParams @{Identity = $_.Guid; AuditBypassEnabled = $false } -UseSystemMailbox $true diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index d6676fc437ec..8ab1793fec2f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -75,6 +75,7 @@ function Invoke-CIPPStandardIntuneTemplate { if ($Settings.AssignTo) { Write-Host "Assigning Policy to $($Settings.AssignTo) the create ID is $($CreateRequest)" + if ($Settings.AssignTo -eq 'customGroup') { $Settings.AssignTo = $Settings.customGroup } Set-CIPPAssignedPolicy -PolicyId $CreateRequest.id -TenantFilter $tenant -GroupName $Settings.AssignTo -Type $TemplateTypeURL } Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully added Intune Template policy for $($Tenant)" -sev 'Info' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 index e9182bb95717..47cdc60712c8 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 @@ -4,7 +4,7 @@ function Invoke-CIPPStandardPasswordExpireDisabled { Internal #> param($Tenant, $Settings) - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $Tenant + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/domains' -tenantid $Tenant $DomainswithoutPassExpire = $GraphRequest | Where-Object -Property passwordValidityPeriodInDays -NE '2147483647' If ($Settings.remediate) { @@ -12,7 +12,13 @@ function Invoke-CIPPStandardPasswordExpireDisabled { if ($DomainswithoutPassExpire) { $DomainswithoutPassExpire | ForEach-Object { try { - New-GraphPostRequest -type Patch -tenantid $Tenant -uri "https://graph.microsoft.com/beta/domains/$($_.id)" -body '{"passwordValidityPeriodInDays": 2147483647 }' + if ( $null -eq $_.passwordNotificationWindowInDays ) { + $Body = '{"passwordValidityPeriodInDays": 2147483647, "passwordNotificationWindowInDays": 14 }' + Write-Host "PasswordNotificationWindowInDays is null for $($_.id). Setting to the default of 14 days." + } else { + $Body = '{"passwordValidityPeriodInDays": 2147483647 }' + } + New-GraphPostRequest -type Patch -tenantid $Tenant -uri "https://graph.microsoft.com/v1.0/domains/$($_.id)" -body $Body Write-LogMessage -API 'Standards' -tenant $tenant -message "Disabled Password Expiration for $($_.id)." -sev Info } catch { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable Password Expiration for $($_.id). Error: $($_.exception.message)" -sev Error diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index d6d80cdcf143..837e63e18945 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -19,7 +19,7 @@ function Receive-CippHttpTrigger { function Receive-CippQueueTrigger { Param($QueueItem, $TriggerMetadata) - + $Start = (Get-Date).ToUniversalTime() $APIName = $TriggerMetadata.FunctionName Write-Host "#### Running $APINAME" @@ -48,5 +48,78 @@ function Receive-CippQueueTrigger { Write-CippFunctionStats @Stats } -Export-ModuleMember -Function @('Receive-CippHttpTrigger', 'Receive-CippQueueTrigger') +function Receive-CippOrchestrationTrigger { + param($Context) + + try { + if (Test-Json -Json $Context.Input) { + $OrchestratorInput = $Context.Input | ConvertFrom-Json + } else { + $OrchestratorInput = $Context.Input + } + + $DurableRetryOptions = @{ + FirstRetryInterval = (New-TimeSpan -Seconds 5) + MaxNumberOfAttempts = if ($OrchestratorInput.MaxAttempts) { $OrchestratorInput.MaxAttempts } else { 1 } + BackoffCoefficient = 2 + } + #Write-Host ($OrchestratorInput | ConvertTo-Json -Depth 10) + $RetryOptions = New-DurableRetryOptions @DurableRetryOptions + + if ($Context.IsReplaying -ne $true -and $OrchestratorInput.SkipLog -ne $true) { + Write-LogMessage -API $OrchestratorInput.OrchestratorName -tenant $OrchestratorInput.TenantFilter -message "Started $($OrchestratorInput.OrchestratorName)" -sev info + } + + if (!$OrchestratorInput.Batch -or ($OrchestratorInput.Batch | Measure-Object).Count -eq 0) { + $Batch = (Invoke-ActivityFunction -FunctionName 'CIPPActivityFunction' -Input $OrchestratorInput.QueueFunction -ErrorAction Stop) + } else { + $Batch = $OrchestratorInput.Batch + } + + if (($Batch | Measure-Object).Count -gt 0) { + foreach ($Item in $Batch) { + $null = Invoke-DurableActivity -FunctionName 'CIPPActivityFunction' -Input $Item -NoWait -RetryOptions $RetryOptions -ErrorAction Stop + } + } + + if ($Context.IsReplaying -ne $true -and $OrchestratorInput.SkipLog -ne $true) { + Write-LogMessage -API $OrchestratorInput.OrchestratorName -tenant $tenant -message "Finished $($OrchestratorInput.OrchestratorName)" -sev Info + } + } catch { + Write-Host "Orchestrator error $($_.Exception.Message)" + } +} + +function Receive-CippActivityTrigger { + Param($Item) + + $Start = (Get-Date).ToUniversalTime() + Set-Location (Get-Item $PSScriptRoot).Parent.Parent.FullName + + if ($Item.FunctionName) { + $FunctionName = 'Push-{0}' -f $Item.FunctionName + try { + & $FunctionName -Item $Item + } catch { + $ErrorMsg = $_.Exception.Message + } + } else { + $ErrorMsg = 'Function not provided' + } + + $End = (Get-Date).ToUniversalTime() + + $Stats = @{ + FunctionType = 'Durable' + Entity = $Item + Start = $Start + End = $End + ErrorMsg = $ErrorMsg + } + + #Write-Information '####### Adding stats' + Write-CippFunctionStats @Stats +} + +Export-ModuleMember -Function @('Receive-CippHttpTrigger', 'Receive-CippQueueTrigger', 'Receive-CippOrchestrationTrigger', 'Receive-CippActivityTrigger') diff --git a/Modules/CippExtensions/CippExtensions.psd1 b/Modules/CippExtensions/CippExtensions.psd1 index 437cc32f8661..8a30d23c6ef1 100644 Binary files a/Modules/CippExtensions/CippExtensions.psd1 and b/Modules/CippExtensions/CippExtensions.psd1 differ diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 new file mode 100644 index 000000000000..02ac73202eb6 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 @@ -0,0 +1,109 @@ +function Invoke-NinjaOneExtensionScheduler { + $Table = Get-CIPPTable -TableName NinjaOneSettings + $Settings = (Get-AzDataTableEntity @Table) + $TimeSetting = ($Settings | Where-Object { $_.RowKey -eq 'NinjaSyncTime' }).SettingValue + + + if (($TimeSetting | Measure-Object).count -ne 1) { + [int]$TimeSetting = Get-Random -Minimum 1 -Maximum 95 + $AddObject = @{ + PartitionKey = 'NinjaConfig' + RowKey = 'NinjaSyncTime' + 'SettingValue' = $TimeSetting + } + Add-AzDataTableEntity @Table -Entity $AddObject -Force + } + + Write-Host "Ninja Time Setting: $TimeSetting" + + $LastRunTime = Get-Date(($Settings | Where-Object { $_.RowKey -eq 'NinjaLastRunTime' }).SettingValue) + + Write-Host "Last Run: $LastRunTime" + + $CurrentTime = Get-Date + $CurrentInterval = ($CurrentTime.Hour * 4) + [math]::Floor($CurrentTime.Minute / 15) + + Write-Host "Current Interval: $CurrentInterval" + + $CIPPMapping = Get-CIPPTable -TableName CippMapping + $Filter = "PartitionKey eq 'NinjaOrgsMapping'" + $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } + + if ($Null -eq $LastRunTime -or $LastRunTime -le (Get-Date).addhours(-25) -or $TimeSetting -eq $CurrentInterval) { + Write-Host 'Executing' + $Batch = foreach ($Tenant in $TenantsToProcess | Sort-Object lastEndTime) { + <#Push-OutputBinding -Name NinjaProcess -Value @{ + 'NinjaAction' = 'SyncTenant' + 'MappedTenant' = $Tenant + } + Start-Sleep -Seconds 1#> + [PSCustomObject]@{ + 'NinjaAction' = 'SyncTenant' + 'MappedTenant' = $Tenant + 'FunctionName' = 'NinjaOneQueue' + } + } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + } + + $AddObject = @{ + PartitionKey = 'NinjaConfig' + RowKey = 'NinjaLastRunTime' + 'SettingValue' = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') + } + Add-AzDataTableEntity @Table -Entity $AddObject -Force + + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "NinjaOne Daily Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' + + } else { + if ($LastRunTime -lt (Get-Date).AddMinutes(-90)) { + $TenantsToProcess | ForEach-Object { + if ($Null -ne $_.lastEndTime -and $_.lastEndTime -ne '') { + $_.lastEndTime = (Get-Date($_.lastEndTime)) + } else { + $_ | Add-Member -NotePropertyName lastEndTime -NotePropertyValue $Null -Force + } + + if ($Null -ne $_.lastStartTime -and $_.lastStartTime -ne '') { + $_.lastStartTime = (Get-Date($_.lastStartTime)) + } else { + $_ | Add-Member -NotePropertyName lastStartTime -NotePropertyValue $Null -Force + } + } + $CatchupTenants = $TenantsToProcess | Where-Object { (((($_.lastEndTime -eq $Null) -or ($_.lastStartTime -gt $_.lastEndTime)) -and ($_.lastStartTime -lt (Get-Date).AddMinutes(-30)))) -or ($_.lastStartTime -lt $LastRunTime) } + $Batch = foreach ($Tenant in $CatchupTenants) { + #Push-OutputBinding -Name NinjaProcess -Value @{ + # 'NinjaAction' = 'SyncTenant' + # 'MappedTenant' = $Tenant + #} + [PSCustomObject]@{ + NinjaAction = 'SyncTenant' + MappedTenant = $Tenant + FunctionName = 'NinjaOneQueue' + } + } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + } + + if (($CatchupTenants | Measure-Object).count -gt 0) { + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "NinjaOne Synchronization Catchup Queued for $(($CatchupTenants | Measure-Object).count) Tenants" -Sev 'Info' + } + + } + + } +} \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 index 0590894a8fec..f351d43ee039 100644 --- a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 @@ -3,30 +3,30 @@ function Invoke-NinjaOneOrgMapping { [System.Collections.Generic.List[PSCustomObject]]$MatchedM365Tenants = @() [System.Collections.Generic.List[PSCustomObject]]$MatchedNinjaOrgs = @() - $ExcludeSerials = @("0", "SystemSerialNumber", "To Be Filled By O.E.M.", "System Serial Number", "0123456789", "123456789", "............") + $ExcludeSerials = @('0', 'SystemSerialNumber', 'To Be Filled By O.E.M.', 'System Serial Number', '0123456789', '123456789', '............') $CIPPMapping = Get-CIPPTable -TableName CippMapping - + #Get available mappings $Mappings = [pscustomobject]@{} $Filter = "PartitionKey eq 'NinjaOrgsMapping'" Get-AzDataTableEntity @CIPPMapping -Filter $Filter | ForEach-Object { $Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.NinjaOneName)"; value = "$($_.NinjaOne)" } } - + #Get Available Tenants $Tenants = Get-Tenants #Get available Ninja clients $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json).NinjaOne - + $Token = Get-NinjaOneToken -configuration $Configuration - + # Fetch Ninja Orgs $After = 0 $PageSize = 1000 $NinjaOrgs = do { - $Result = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/organizations?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + $Result = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/organizations?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -Depth 100 $Result $ResultCount = ($Result.id | Measure-Object -Maximum) $After = $ResultCount.maximum @@ -51,11 +51,11 @@ function Invoke-NinjaOneOrgMapping { $After = 0 $PageSize = 1000 $NinjaDevicesRaw = do { - $Result = (Invoke-WebRequest -uri "https://$($Configuration.Instance)/api/v2/devices-detailed?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -depth 100 + $Result = (Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/devices-detailed?pageSize=$PageSize&after=$After" -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json').content | ConvertFrom-Json -Depth 100 $Result $ResultCount = ($Result.id | Measure-Object -Maximum) $After = $ResultCount.maximum - + } while ($ResultCount.count -eq $PageSize) @@ -71,12 +71,12 @@ function Invoke-NinjaOneOrgMapping { } # Remove any devices with duplicate serials - $ParsedNinjaDevices = $NinjaDevices | Where-Object { $_.Serial -in (($NinjaDevices | Group-Object Serial | where-object { $_.count -eq 1 }).name) } + $ParsedNinjaDevices = $NinjaDevices | Where-Object { $_.Serial -in (($NinjaDevices | Group-Object Serial | Where-Object { $_.count -eq 1 }).name) } # First lets match on Org names foreach ($Tenant in $Tenants | Where-Object { $_.customerId -notin $MatchedM365Tenants.customerId }) { - $MatchedOrg = $NinjaOrgs | where-object { $_.name -eq $Tenant.displayName } + $MatchedOrg = $NinjaOrgs | Where-Object { $_.name -eq $Tenant.displayName } if (($MatchedOrg | Measure-Object).count -eq 1) { $MatchedM365Tenants.add($Tenant) $MatchedNinjaOrgs.add($MatchedOrg) @@ -87,23 +87,34 @@ function Invoke-NinjaOneOrgMapping { 'NinjaOneName' = "$($MatchedOrg.name)" } Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force - Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "Added mapping from Organization name match for $($Tenant.customerId). to $($($MatchedOrg.name))" -Sev 'Info' + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "Added mapping from Organization name match for $($Tenant.customerId). to $($($MatchedOrg.name))" -Sev 'Info' } } # Now Let match on remaining Tenants - Foreach ($Tenant in $Tenants | Where-Object { $_.customerId -notin $MatchedM365Tenants.customerId }) { - - Push-OutputBinding -Name NinjaProcess -Value @{ + $Batch = Foreach ($Tenant in $Tenants | Where-Object { $_.customerId -notin $MatchedM365Tenants.customerId }) { + <#Push-OutputBinding -Name NinjaProcess -Value @{ + 'NinjaAction' = 'AutoMapTenant' + 'M365Tenant' = $Tenant + 'NinjaOrgs' = $NinjaOrgs | Where-Object { $_.id -notin $MatchedNinjaOrgs } + 'NinjaDevices' = $ParsedNinjaDevices + }#> + [PSCustomObject]@{ 'NinjaAction' = 'AutoMapTenant' 'M365Tenant' = $Tenant 'NinjaOrgs' = $NinjaOrgs | Where-Object { $_.id -notin $MatchedNinjaOrgs } 'NinjaDevices' = $ParsedNinjaDevices + 'FunctionName' = 'NinjaOneQueue' } - - Start-Sleep -Seconds 1 - + } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" } } - \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneSync.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneSync.ps1 index a168d291575b..df7d6f67111a 100644 --- a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneSync.ps1 +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneSync.ps1 @@ -7,12 +7,26 @@ function Invoke-NinjaOneSync { $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } - foreach ($Tenant in $TenantsToProcess) { - Push-OutputBinding -Name NinjaProcess -Value @{ + $Batch = foreach ($Tenant in $TenantsToProcess) { + <#Push-OutputBinding -Name NinjaProcess -Value @{ 'NinjaAction' = 'SyncTenant' 'MappedTenant' = $Tenant } - Start-Sleep -Seconds 1 + Start-Sleep -Seconds 1#> + [PSCustomObject]@{ + 'NinjaAction' = 'SyncTenant' + 'MappedTenant' = $Tenant + 'FunctionName' = 'NinjaOneQueue' + } + } + if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'NinjaOneOrchestrator' + Batch = @($Batch) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" } $AddObject = @{ @@ -23,10 +37,9 @@ function Invoke-NinjaOneSync { Add-AzDataTableEntity @Table -Entity $AddObject -Force - Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' + Write-LogMessage -API 'NinjaOneAutoMap_Queue' -user 'CIPP' -message "NinjaOne Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' } catch { Write-LogMessage -API 'Scheduler_Billing' -tenant 'none' -message "Could not start NinjaOne Sync $($_.Exception.Message)" -sev Error } - + } - \ No newline at end of file diff --git a/Modules/CippExtensions/NinjaOne/Push-NinjaOneQueue.ps1 b/Modules/CippExtensions/NinjaOne/Push-NinjaOneQueue.ps1 new file mode 100644 index 000000000000..09fe668a97b4 --- /dev/null +++ b/Modules/CippExtensions/NinjaOne/Push-NinjaOneQueue.ps1 @@ -0,0 +1,15 @@ +function Push-NinjaOneQueue { + # Input bindings are passed in via param block. + param($Item) + + # Write out the queue message and metadata to the information log. + Write-Host "PowerShell NinjaOne queue trigger function processed work item: $($Item.NinjaAction)" + + Switch ($Item.NinjaAction) { + 'StartAutoMapping' { Invoke-NinjaOneOrgMapping } + 'AutoMapTenant' { Invoke-NinjaOneOrgMappingTenant -QueueItem $Item } + 'SyncTenant' { Invoke-NinjaOneTenantSync -QueueItem $Item } + 'SyncTenants' { Invoke-NinjaOneSync } + } + +} \ No newline at end of file diff --git a/PublicWebhooks/function.json b/PublicWebhooks/function.json deleted file mode 100644 index f59adac3eb84..000000000000 --- a/PublicWebhooks/function.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "anonymous", - "type": "httpTrigger", - "direction": "in", - "name": "Request", - "methods": ["get", "post"] - }, - { - "type": "http", - "direction": "out", - "name": "Response" - }, - { - "type": "queue", - "direction": "out", - "name": "QueueWebhook", - "queueName": "webhooksqueue" - } - ] -} diff --git a/PublicWebhooks/run.ps1 b/PublicWebhooks/run.ps1 deleted file mode 100644 index 2faa35804e05..000000000000 --- a/PublicWebhooks/run.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($Request, $TriggerMetadata) - -Set-Location (Get-Item $PSScriptRoot).Parent.FullName -$WebhookTable = Get-CIPPTable -TableName webhookTable -$Webhooks = Get-CIPPAzDataTableEntity @WebhookTable -Write-Host 'Received request' -Write-Host "CIPPID: $($request.Query.CIPPID)" -$url = ($request.headers.'x-ms-original-url').split('/API') | Select-Object -First 1 -Write-Host $url -if ($Request.Query.CIPPID -in $Webhooks.RowKey) { - Write-Host 'Found matching CIPPID' - if ($Webhooks.Resource -eq 'M365AuditLogs') { - Write-Host "Found M365AuditLogs - This is an old entry, we'll deny so Microsoft stops sending it." - $body = 'This webhook is not authorized, its an old entry.' - $StatusCode = [HttpStatusCode]::Forbidden - } - if ($Request.query.ValidationToken -or $Request.body.validationCode) { - Write-Host 'Validation token received' - $body = $request.query.ValidationToken - } else { - Push-OutputBinding -Name QueueWebhook -Value $Request - $Body = 'Webhook Recieved' - $StatusCode = [HttpStatusCode]::OK - } -} else { - $body = 'This webhook is not authorized.' - $StatusCode = [HttpStatusCode]::Forbidden -} - -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $body - }) diff --git a/PublicWebhooksProcess/function.json b/PublicWebhooksProcess/function.json deleted file mode 100644 index d358059b9e50..000000000000 --- a/PublicWebhooksProcess/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "webhooksqueue" - } - ] -} diff --git a/PublicWebhooksProcess/run.ps1 b/PublicWebhooksProcess/run.ps1 deleted file mode 100644 index 50bbde87cfb2..000000000000 --- a/PublicWebhooksProcess/run.ps1 +++ /dev/null @@ -1,79 +0,0 @@ -using namespace System.Net - -# Input bindings are passed in via param block. -param($QueueItem, $TriggerMetadata) - -$Request = $QueueItem - -$WebhookTable = Get-CIPPTable -TableName webhookTable -$Webhooks = Get-AzDataTableEntity @WebhookTable -Write-Host 'Received request' -Write-Host "CIPPID: $($request.Query.CIPPID)" -$url = ($request.headers.'x-ms-original-url').split('/API') | Select-Object -First 1 -Write-Host $url -if ($Request.query.CIPPID -in $Webhooks.RowKey) { - Write-Host 'Found matching CIPPID' - $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID - - if ($Request.Query.Type -eq 'GraphSubscription') { - # Graph Subscriptions - [pscustomobject]$ReceivedItem = $Request.Body.value - Invoke-CippGraphWebhookProcessing -Data $ReceivedItem -CIPPID $request.Query.CIPPID -WebhookInfo $Webhookinfo - - } else { - # Auditlog Subscriptions - try { - foreach ($ReceivedItem In ($Request.body)) { - $ReceivedItem = [pscustomobject]$ReceivedItem - Write-Host "Received Item: $($ReceivedItem | ConvertTo-Json -Depth 15 -Compress))" - $TenantFilter = (Get-Tenants | Where-Object -Property customerId -EQ $ReceivedItem.TenantId).defaultDomainName - Write-Host "Webhook TenantFilter: $TenantFilter" - $ConfigTable = get-cipptable -TableName 'SchedulerConfig' - $Alertconfig = Get-CIPPAzDataTableEntity @ConfigTable | Where-Object { $_.Tenant -eq $TenantFilter -or $_.Tenant -eq 'AllTenants' } - $Operations = ($AlertConfig.if | ConvertFrom-Json -ErrorAction SilentlyContinue).selection + 'UserLoggedIn' - $Webhookinfo = $Webhooks | Where-Object -Property RowKey -EQ $Request.query.CIPPID - #Increased download efficiency: only download the data we need for processing. Todo: Change this to load from table or dynamic source. - $MappingTable = [pscustomobject]@{ - 'UserLoggedIn' = 'Audit.AzureActiveDirectory' - 'Add member to role.' = 'Audit.AzureActiveDirectory' - 'Disable account.' = 'Audit.AzureActiveDirectory' - 'Update StsRefreshTokenValidFrom Timestamp.' = 'Audit.AzureActiveDirectory' - 'Enable account.' = 'Audit.AzureActiveDirectory' - 'Disable Strong Authentication.' = 'Audit.AzureActiveDirectory' - 'Reset user password.' = 'Audit.AzureActiveDirectory' - 'Add service principal.' = 'Audit.AzureActiveDirectory' - 'HostedIP' = 'Audit.AzureActiveDirectory' - 'badRepIP' = 'Audit.AzureActiveDirectory' - 'UserLoggedInFromUnknownLocation' = 'Audit.AzureActiveDirectory' - 'customfield' = 'AnyLog' - 'anyAlert' = 'AnyLog' - 'New-InboxRule' = 'Audit.Exchange' - 'Set-InboxRule' = 'Audit.Exchange' - } - #Compare $Operations to $MappingTable. If there is a match, we make a new variable called $LogsToDownload - #Example: $Operations = 'UserLoggedIn', 'Set-InboxRule' makes : $LogsToDownload = @('Audit.AzureActiveDirectory',Audit.Exchange) - $LogsToDownload = $Operations | Where-Object { $MappingTable.$_ } | ForEach-Object { $MappingTable.$_ } - Write-Host "Our operations: $Operations" - Write-Host "Logs to download: $LogsToDownload" - if ($ReceivedItem.ContentType -in $LogsToDownload -or 'AnyLog' -in $LogsToDownload) { - $Data = New-GraphPostRequest -type GET -uri "https://manage.office.com/api/v1.0/$($ReceivedItem.tenantId)/activity/feed/audit/$($ReceivedItem.contentid)" -tenantid $TenantFilter -scope 'https://manage.office.com/.default' - } else { - Write-Host "No data to download for $($ReceivedItem.ContentType)" - continue - } - Write-Host "Data found: $($data.count) items" - $DataToProcess = if ('anylog' -NotIn $LogsToDownload) { $Data | Where-Object -Property Operation -In $Operations } else { $Data } - Write-Host "Data to process found: $($DataToProcess.count) items" - foreach ($Item in $DataToProcess) { - Write-Host "Processing $($item.operation)" - Invoke-CippWebhookProcessing -TenantFilter $TenantFilter -Data $Item -CIPPPURL $url - } - } - } catch { - Write-Host "Webhook Failed: $($_.Exception.Message). Line number $($_.InvocationInfo.ScriptLineNumber)" - } - } - -} else { - Write-Host 'Unauthorised Webhook' -} diff --git a/Scheduler_Extensions/function.json b/Scheduler_Extensions/function.json index f3e5317f409a..7474f0f13334 100644 --- a/Scheduler_Extensions/function.json +++ b/Scheduler_Extensions/function.json @@ -11,6 +11,11 @@ "direction": "out", "name": "NinjaProcess", "queueName": "NinjaOneQueue" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" } ] } diff --git a/Scheduler_Extensions/run.ps1 b/Scheduler_Extensions/run.ps1 index 66af8649ebf7..58e228ebbe1d 100644 --- a/Scheduler_Extensions/run.ps1 +++ b/Scheduler_Extensions/run.ps1 @@ -10,85 +10,5 @@ Write-Host 'Started Scheduler for Extensions' # NinjaOne Extension if ($Configuration.NinjaOne.Enabled -eq $True) { - - $Table = Get-CIPPTable -TableName NinjaOneSettings - $Settings = (Get-AzDataTableEntity @Table) - $TimeSetting = ($Settings | Where-Object { $_.RowKey -eq 'NinjaSyncTime' }).SettingValue - - - if (($TimeSetting | Measure-Object).count -ne 1) { - [int]$TimeSetting = Get-Random -Minimum 1 -Maximum 95 - $AddObject = @{ - PartitionKey = 'NinjaConfig' - RowKey = 'NinjaSyncTime' - 'SettingValue' = $TimeSetting - } - Add-AzDataTableEntity @Table -Entity $AddObject -Force - } - - Write-Host "Ninja Time Setting: $TimeSetting" - - $LastRunTime = Get-Date(($Settings | Where-Object { $_.RowKey -eq 'NinjaLastRunTime' }).SettingValue) - - Write-Host "Last Run: $LastRunTime" - - $CurrentTime = Get-Date - $CurrentInterval = ($CurrentTime.Hour * 4) + [math]::Floor($CurrentTime.Minute / 15) - - Write-Host "Current Interval: $CurrentInterval" - - $CIPPMapping = Get-CIPPTable -TableName CippMapping - $Filter = "PartitionKey eq 'NinjaOrgsMapping'" - $TenantsToProcess = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | Where-Object { $Null -ne $_.NinjaOne -and $_.NinjaOne -ne '' } - - if ($Null -eq $LastRunTime -or $LastRunTime -le (Get-Date).addhours(-25) -or $TimeSetting -eq $CurrentInterval) { - Write-Host 'Executing' - foreach ($Tenant in $TenantsToProcess | Sort-Object lastEndTime) { - Push-OutputBinding -Name NinjaProcess -Value @{ - 'NinjaAction' = 'SyncTenant' - 'MappedTenant' = $Tenant - } - Start-Sleep -Seconds 1 - - } - - $AddObject = @{ - PartitionKey = 'NinjaConfig' - RowKey = 'NinjaLastRunTime' - 'SettingValue' = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') - } - Add-AzDataTableEntity @Table -Entity $AddObject -Force - - Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "NinjaOne Daily Synchronization Queued for $(($TenantsToProcess | Measure-Object).count) Tenants" -Sev 'Info' - - } else { - if ($LastRunTime -lt (Get-Date).AddMinutes(-90)) { - $TenantsToProcess | ForEach-Object { - if ($Null -ne $_.lastEndTime -and $_.lastEndTime -ne '') { - $_.lastEndTime = (Get-Date($_.lastEndTime)) - } else { - $_ | Add-Member -NotePropertyName lastEndTime -NotePropertyValue $Null -Force - } - - if ($Null -ne $_.lastStartTime -and $_.lastStartTime -ne '') { - $_.lastStartTime = (Get-Date($_.lastStartTime)) - } else { - $_ | Add-Member -NotePropertyName lastStartTime -NotePropertyValue $Null -Force - } - } - $CatchupTenants = $TenantsToProcess | Where-Object { (((($_.lastEndTime -eq $Null) -or ($_.lastStartTime -gt $_.lastEndTime)) -and ($_.lastStartTime -lt (Get-Date).AddMinutes(-30)))) -or ($_.lastStartTime -lt $LastRunTime) } - foreach ($Tenant in $CatchupTenants) { - Push-OutputBinding -Name NinjaProcess -Value @{ - 'NinjaAction' = 'SyncTenant' - 'MappedTenant' = $Tenant - } - Start-Sleep -Seconds 1 - } - if (($CatchupTenants | Measure-Object).count -gt 0) { - Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "NinjaOne Synchronization Catchup Queued for $(($CatchupTenants | Measure-Object).count) Tenants" -Sev 'Info' - } - - } - - } + Invoke-NinjaOneExtensionScheduler } \ No newline at end of file diff --git a/Scheduler_GetQueue/function.json b/Scheduler_GetQueue/function.json index d0f59a682e3c..56e4cf0cfda1 100644 --- a/Scheduler_GetQueue/function.json +++ b/Scheduler_GetQueue/function.json @@ -7,10 +7,9 @@ "type": "timerTrigger" }, { - "type": "queue", - "direction": "out", - "name": "QueueItem", - "queueName": "CIPPGenericQueue" + "name": "starter", + "type": "durableClient", + "direction": "in" } ] } diff --git a/Scheduler_GetQueue/run.ps1 b/Scheduler_GetQueue/run.ps1 index f14ccc274dd4..6d0553001e1e 100644 --- a/Scheduler_GetQueue/run.ps1 +++ b/Scheduler_GetQueue/run.ps1 @@ -5,7 +5,7 @@ $Tenants = Get-CIPPAzDataTableEntity @Table | Where-Object -Property PartitionKe $Tasks = foreach ($Tenant in $Tenants) { if ($Tenant.tenant -ne 'AllTenants') { - [pscustomobject]@{ + [pscustomobject]@{ Tenant = $Tenant.tenant Tag = 'SingleTenant' TenantID = $Tenant.tenantid @@ -15,7 +15,7 @@ $Tasks = foreach ($Tenant in $Tenants) { Write-Host 'All tenants, doing them all' $TenantList = Get-Tenants foreach ($t in $TenantList) { - [pscustomobject]@{ + [pscustomobject]@{ Tenant = $t.defaultDomainName Tag = 'AllTenants' TenantID = $t.customerId @@ -23,19 +23,22 @@ $Tasks = foreach ($Tenant in $Tenants) { } } } -} +} -foreach ($Task in $Tasks) { - $QueueItem = [pscustomobject]@{ +$Batch = foreach ($Task in $Tasks) { + [pscustomobject]@{ Tenant = $task.tenant Tenantid = $task.tenantid Tag = $task.tag Type = $task.type FunctionName = "Scheduler$($Task.Type)" } - try { - Push-OutputBinding -Name QueueItem -Value $QueueItem - } catch { - Write-Host "Could not launch queue item for $($Task.tenant): $($_.Exception.Message)" - } -} \ No newline at end of file +} +$InputObject = [PSCustomObject]@{ + OrchestratorName = 'SchedulerOrchestrator' + Batch = @($Batch) +} +#Write-Host ($InputObject | ConvertTo-Json) +$InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) +Write-Host "Started orchestration with ID = '$InstanceId'" +#$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId \ No newline at end of file diff --git a/Scheduler_GetWebhooks/function.json b/Scheduler_GetWebhooks/function.json new file mode 100644 index 000000000000..f30537d11b34 --- /dev/null +++ b/Scheduler_GetWebhooks/function.json @@ -0,0 +1,15 @@ +{ + "bindings": [ + { + "name": "Timer", + "schedule": "0 */15 * * * *", + "direction": "in", + "type": "timerTrigger" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" + } + ] +} diff --git a/Scheduler_GetWebhooks/run.ps1 b/Scheduler_GetWebhooks/run.ps1 new file mode 100644 index 000000000000..ca8c3a456566 --- /dev/null +++ b/Scheduler_GetWebhooks/run.ps1 @@ -0,0 +1,25 @@ +param($Timer) + +$Table = Get-CIPPTable -TableName WebhookIncoming +$Webhooks = Get-CIPPAzDataTableEntity @Table +$WebhookCount = ($Webhooks | Measure-Object).Count +$Message = 'Processing {0} webhooks' -f $WebhookCount +Write-LogMessage -API 'Webhooks' -message $Message -sev Info + +try { + for ($i = 0; $i -lt $WebhookCount; $i += 2500) { + $WebhookBatch = $Webhooks[$i..($i + 2499)] + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'WebhookOrchestrator' + Batch = @($WebhookBatch) + SkipLog = $true + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started orchestration with ID = '$InstanceId'" + } +} catch { + Write-LogMessage -API 'Webhooks' -message "Error processing webhooks - $($_.Exception.Message)" -sev Error +} finally { + Write-LogMessage -API 'Webhooks' -message 'Webhook processing completed' -sev Info +} diff --git a/Scheduler_Standards/function.json b/Scheduler_Standards/function.json index 35ec29f027f7..e071591357a0 100644 --- a/Scheduler_Standards/function.json +++ b/Scheduler_Standards/function.json @@ -7,10 +7,9 @@ "type": "timerTrigger" }, { - "type": "queue", - "direction": "out", - "name": "QueueItem", - "queueName": "CIPPGenericQueue" + "name": "starter", + "type": "durableClient", + "direction": "in" } ] } diff --git a/Scheduler_UserTasks/function.json b/Scheduler_UserTasks/function.json index de2a7380d759..f7af84092121 100644 --- a/Scheduler_UserTasks/function.json +++ b/Scheduler_UserTasks/function.json @@ -7,10 +7,9 @@ "type": "timerTrigger" }, { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "scheduledcommandprocessor" + "name": "starter", + "type": "durableClient", + "direction": "in" } ] } diff --git a/Scheduler_UserTasks/run.ps1 b/Scheduler_UserTasks/run.ps1 index 802d4624473f..8ad06065a2fa 100644 --- a/Scheduler_UserTasks/run.ps1 +++ b/Scheduler_UserTasks/run.ps1 @@ -3,12 +3,12 @@ param($Timer) $Table = Get-CippTable -tablename 'ScheduledTasks' $Filter = "TaskState eq 'Planned' or TaskState eq 'Failed - Planned'" $tasks = Get-CIPPAzDataTableEntity @Table -Filter $Filter -foreach ($task in $tasks) { +$Batch = foreach ($task in $tasks) { $tenant = $task.Tenant $currentUnixTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds if ($currentUnixTime -ge $task.ScheduledTime) { try { - Update-AzDataTableEntity @Table -Entity @{ + $null = Update-AzDataTableEntity @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey ExecutedTime = "$currentUnixTime" @@ -19,25 +19,27 @@ foreach ($task in $tasks) { if (!$task.Parameters) { $task.Parameters = @{} } $ScheduledCommand = [pscustomobject]@{ - Command = $task.Command - Parameters = $task.Parameters - TaskInfo = $task + Command = $task.Command + Parameters = $task.Parameters + TaskInfo = $task + FunctionName = 'ExecScheduledCommand' } if ($task.Tenant -eq 'AllTenants') { - $Results = Get-Tenants | ForEach-Object { + Get-Tenants | ForEach-Object { $ScheduledCommand.Parameters['TenantFilter'] = $_.defaultDomainName - Push-OutputBinding -Name Msg -Value $ScheduledCommand + $ScheduledCommand + #Push-OutputBinding -Name Msg -Value $ScheduledCommand } } else { $ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant - $Results = Push-OutputBinding -Name Msg -Value $ScheduledCommand + $ScheduledCommand + #$Results = Push-OutputBinding -Name Msg -Value $ScheduledCommand } - } catch { $errorMessage = $_.Exception.Message - Update-AzDataTableEntity @Table -Entity @{ + $null = Update-AzDataTableEntity @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey Results = "$errorMessage" @@ -47,4 +49,14 @@ foreach ($task in $tasks) { Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error } } +} +if (($Batch | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'UserTaskOrchestrator' + Batch = @($Batch) + SkipLog = $true + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started orchestration with ID = '$InstanceId'" } \ No newline at end of file diff --git a/Tools/Initialize-DevEnvironment.ps1 b/Tools/Initialize-DevEnvironment.ps1 index 4f4f8f55aa58..e8b67a373ae5 100644 --- a/Tools/Initialize-DevEnvironment.ps1 +++ b/Tools/Initialize-DevEnvironment.ps1 @@ -13,3 +13,4 @@ Import-Module "$CippRoot\Modules\AzBobbyTables" Import-Module "$CippRoot\Modules\DNSHealth" Import-Module "$CippRoot\Modules\CippQueue" Import-Module "$CippRoot\Modules\CippCore" +Get-CIPPAuthentication \ No newline at end of file diff --git a/UpdatePermissions/function.json b/UpdatePermissions/function.json index a7fdc6ca8da8..7e97fe568d29 100644 --- a/UpdatePermissions/function.json +++ b/UpdatePermissions/function.json @@ -7,10 +7,9 @@ "schedule": "0 0 0 * * *" }, { - "type": "queue", - "direction": "out", - "name": "Msg", - "queueName": "cpvqueue" + "name": "starter", + "type": "durableClient", + "direction": "in" } ] } diff --git a/UpdatePermissions/run.ps1 b/UpdatePermissions/run.ps1 index 5707bb45734a..03d3c0e1cc41 100644 --- a/UpdatePermissions/run.ps1 +++ b/UpdatePermissions/run.ps1 @@ -1,7 +1,16 @@ # Input bindings are passed in via param block. param($Timer) -$Tenants = get-tenants -IncludeErrors | Where-Object { $_.customerId -ne $env:TenantId } -foreach ($Row in $Tenants) { - Push-OutputBinding -Name Msg -Value $row -} \ No newline at end of file +try { + $Tenants = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -ne $env:TenantId } | ForEach-Object { $_ | Add-Member -NotePropertyName FunctionName -NotePropertyValue 'UpdatePermissionsQueue'; $_ } + + if (($Tenants | Measure-Object).Count -gt 0) { + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'UpdatePermissionsOrchestrator' + Batch = @($Tenants) + } + #Write-Host ($InputObject | ConvertTo-Json) + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5) + Write-Host "Started permissions orchestration with ID = '$InstanceId'" + } +} catch {} \ No newline at end of file diff --git a/UpdatePermissionsQueue/function.json b/UpdatePermissionsQueue/function.json deleted file mode 100644 index 7fc4f12cef56..000000000000 --- a/UpdatePermissionsQueue/function.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "bindings": [ - { - "name": "QueueItem", - "type": "queueTrigger", - "direction": "in", - "queueName": "cpvqueue" - } - ] -} diff --git a/UpdatePermissionsQueue/run.ps1 b/UpdatePermissionsQueue/run.ps1 deleted file mode 100644 index 9b147478e274..000000000000 --- a/UpdatePermissionsQueue/run.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -# Input bindings are passed in via param block. -param($QueueItem, $TriggerMetadata) -Write-Host "Applying permissions for $($QueueItem.defaultDomainName)" -$Table = Get-CIPPTable -TableName cpvtenants -$CPVRows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Tenant -EQ $QueueItem.customerId -if (!$CPVRows -or $ENV:ApplicationID -notin $CPVRows.applicationId) { - Write-LogMessage -tenant $queueitem.defaultDomainName -tenantId $queueitem.customerId -message "A New tenant has been added, or a new CIPP-SAM Application is in use" -Sev "Warn" -API "NewTenant" - Write-Host "Adding CPV permissions" - Set-CIPPCPVConsent -Tenantfilter $QueueItem.defaultDomainName -} - -Add-CIPPApplicationPermission -RequiredResourceAccess "CippDefaults" -ApplicationId $ENV:ApplicationID -tenantfilter $QueueItem.defaultDomainName -Add-CIPPDelegatedPermission -RequiredResourceAccess "CippDefaults" -ApplicationId $ENV:ApplicationID -tenantfilter $QueueItem.defaultDomainName - -Write-LogMessage -tenant $QueueItem.defaultDomainName -tenantId $queueitem.customerId -message "Updated permissions for $($QueueItem.defaultDomainName)" -Sev "Info" -API "UpdatePermissionsQueue" \ No newline at end of file diff --git a/Z_CIPPHttpTrigger/function.json b/Z_CIPPHttpTrigger/function.json index 90c8dc9ea6af..a77f42a0ea97 100644 --- a/Z_CIPPHttpTrigger/function.json +++ b/Z_CIPPHttpTrigger/function.json @@ -27,36 +27,12 @@ "name": "Subscription", "queueName": "AlertSubscriptions" }, - { - "type": "queue", - "direction": "out", - "name": "LicenseQueue", - "queueName": "licqueue" - }, - { - "type": "queue", - "direction": "out", - "name": "mbxrulequeue", - "queueName": "mbxrulequeue" - }, - { - "type": "queue", - "direction": "out", - "name": "mfaqueue", - "queueName": "mfaqueue" - }, { "type": "queue", "direction": "out", "name": "mailboxstats", "queueName": "generalAllTenantQueue" }, - { - "type": "queue", - "direction": "out", - "name": "listusers", - "queueName": "generalAllTenantQueue" - }, { "type": "queue", "direction": "out", @@ -75,12 +51,6 @@ "name": "alertqueue", "queueName": "alertqueue" }, - { - "type": "queue", - "direction": "out", - "name": "gdapinvitequeue", - "queueName": "gdapinvitequeue" - }, { "type": "queue", "direction": "out", @@ -99,12 +69,6 @@ "name": "offboardingmailbox", "queueName": "offboardingmailbox" }, - { - "type": "queue", - "direction": "out", - "name": "QueueWebhook", - "queueName": "webhooksqueue" - }, { "name": "starter", "type": "durableClient", diff --git a/version_latest.txt b/version_latest.txt index 804440660c71..84197c89467d 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.2.1 \ No newline at end of file +5.3.2