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/DomainAnalyser_All/run.ps1 b/DomainAnalyser_All/run.ps1
index 468962b0ec20..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 = ''
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 d0031f771c5c..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] -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' = $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-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-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-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-CIPPAlertApnCertExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1
index 9ef318273f8d..13a411f105e9 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertApnCertExpiry.ps1
@@ -4,26 +4,14 @@ function Push-CIPPAlertApnCertExpiry {
[Parameter(Mandatory = $true)]
$Item
)
- $LastRunTable = Get-CIPPTable -Table AlertLastRun
try {
- $Filter = "RowKey eq 'ApnCertExpiry' 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 {
- $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)
- }
- } 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 = $Item.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 06477e708ff7..7b1b8b12fd4f 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertAppSecretExpiry.ps1
@@ -4,36 +4,24 @@ function Push-CIPPAlertAppSecretExpiry {
[Parameter(Mandatory = $true)]
$Item
)
- $LastRunTable = Get-CIPPTable -Table AlertLastRun
-
try {
- $Filter = "RowKey eq 'AppSecretExpiry' 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)) {
- 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)
- }
+ 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 = $Item.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-CIPPAlertDepTokenExpiry.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1
index 4246a5364ef3..8d457fcb012a 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertDepTokenExpiry.ps1
@@ -26,6 +26,6 @@ function Push-CIPPAlertDepTokenExpiry {
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-CIPPAlertMFAAdmins.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1
index 66685982d956..6b933fbf64a0 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAdmins.ps1
@@ -13,7 +13,7 @@ function Push-CIPPAlertMFAAdmins {
}
if (!$DuoActive) {
$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) {
+ if ($users.UserPrincipalName) {
Write-AlertMessage -tenant $Item.tenant -message "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')"
}
} else {
diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1
index a02d2afcdc34..e6401a7b117f 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertMFAAlertUsers.ps1
@@ -7,7 +7,7 @@ function Push-CIPPAlertMFAAlertUsers {
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 $($Item.tenant)
- if ($users) {
+ if ($users.UserPrincipalName) {
Write-AlertMessage -tenant $Item.tenant -message "The following $($users.Count) users do not have MFA registered: $($users.UserPrincipalName -join ', ')"
}
diff --git a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1
index 9614e59d340c..58dedd4888a8 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-CIPPAlertSharepointQuota.ps1
@@ -11,7 +11,7 @@ function Push-CIPPAlertSharepointQuota {
$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) { $Value = $Item.value } else { $Value = 90 }
+ if ($Item.value -Is [Boolean]) { $Value = 90 } else { $Value = $Item.value }
$UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100)
if ($UsedStoragePercentage -gt $Value) {
Write-AlertMessage -tenant $($Item.tenant) -message "SharePoint Storage is at $($UsedStoragePercentage)%. Your alert threshold is $($Value)%"
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 48b5ac8f474b..40fb4f9c404f 100644
--- a/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1
+++ b/Modules/CIPPCore/Public/Entrypoints/Push-SchedulerAlert.ps1
@@ -29,19 +29,23 @@ function Push-SchedulerAlert {
$Item | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value $task.Name -Force
$Item | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value $Item.Tenant -Force
- try {
- $null = Add-CIPPAzDataTableEntity @Table -Entity $Item -Force -ErrorAction Stop
- } catch {
- Write-Host "################### Error updating alert $($_.Exception.Message) - $($Item | ConvertTo-Json)"
+ 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)"
+ }
}
} else {
- Write-Host ('ALERTS: Duplicate run found. Ignoring. Tenant: {0}, Task: {1}' -f $Item.tenant, $task.Name)
+ 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 = 'Alerts'
+ OrchestratorName = 'AlertsOrchestrator'
SkipLog = $true
Batch = @($Batch)
}
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 f302cfcfb306..91d7ce2cd4cc 100644
--- a/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1
+++ b/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1
@@ -15,6 +15,7 @@ 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
@@ -23,16 +24,18 @@ function Write-CippFunctionStats {
$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')) {
$StatEntity.$Property = [string]($Entity.$Property | ConvertTo-Json -Compress)
+ } elseif ($Property -notin ('ETag', 'RowKey', 'PartitionKey', 'Timestamp', 'LastRefresh')) {
+ $StatEntity.$Property = $Entity.$Property
}
}
- $StatsEntity = [PSCustomObject]$StatsEntity
- Write-Host ($StatEntity | ConvertTo-Json)
- Add-CIPPAzDataTableEntity @Table -Entity $StatsEntity -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 1c7e177e3555..8dd8055c6c93 100644
--- a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1
+++ b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1
@@ -78,7 +78,7 @@ function Invoke-CIPPStandardsRun {
#For each item in our object, run the queue.
- $Batch = foreach ($task in $object | Where-Object -Property Standard -NotLike 'v2*') {
+ $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
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/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-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-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/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1
index 67a480956b2d..837e63e18945 100644
--- a/Modules/CippEntrypoints/CippEntrypoints.psm1
+++ b/Modules/CippEntrypoints/CippEntrypoints.psm1
@@ -52,7 +52,6 @@ function Receive-CippOrchestrationTrigger {
param($Context)
try {
-
if (Test-Json -Json $Context.Input) {
$OrchestratorInput = $Context.Input | ConvertFrom-Json
} else {
@@ -61,13 +60,13 @@ function Receive-CippOrchestrationTrigger {
$DurableRetryOptions = @{
FirstRetryInterval = (New-TimeSpan -Seconds 5)
- MaxNumberOfAttempts = if ($OrchestratorInput.MaxAttempts) { $OrchestratorInput.MaxAttempts } else { 3 }
+ 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 -not $Context.Input.SkipLog) {
+ if ($Context.IsReplaying -ne $true -and $OrchestratorInput.SkipLog -ne $true) {
Write-LogMessage -API $OrchestratorInput.OrchestratorName -tenant $OrchestratorInput.TenantFilter -message "Started $($OrchestratorInput.OrchestratorName)" -sev info
}
@@ -83,7 +82,7 @@ function Receive-CippOrchestrationTrigger {
}
}
- if ($Context.IsReplaying -ne $true -and -not $Context.Input.SkipLog) {
+ if ($Context.IsReplaying -ne $true -and $OrchestratorInput.SkipLog -ne $true) {
Write-LogMessage -API $OrchestratorInput.OrchestratorName -tenant $tenant -message "Finished $($OrchestratorInput.OrchestratorName)" -sev Info
}
} catch {
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 122f86c71d70..56e4cf0cfda1 100644
--- a/Scheduler_GetQueue/function.json
+++ b/Scheduler_GetQueue/function.json
@@ -6,12 +6,6 @@
"direction": "in",
"type": "timerTrigger"
},
- {
- "type": "queue",
- "direction": "out",
- "name": "QueueItem",
- "queueName": "CIPPGenericQueue"
- },
{
"name": "starter",
"type": "durableClient",
diff --git a/Scheduler_GetQueue/run.ps1 b/Scheduler_GetQueue/run.ps1
index 2e80dfd588a1..6d0553001e1e 100644
--- a/Scheduler_GetQueue/run.ps1
+++ b/Scheduler_GetQueue/run.ps1
@@ -35,7 +35,7 @@ $Batch = foreach ($Task in $Tasks) {
}
}
$InputObject = [PSCustomObject]@{
- OrchestratorName = 'Scheduler'
+ OrchestratorName = 'SchedulerOrchestrator'
Batch = @($Batch)
}
#Write-Host ($InputObject | ConvertTo-Json)
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 81d53b9a1598..e071591357a0 100644
--- a/Scheduler_Standards/function.json
+++ b/Scheduler_Standards/function.json
@@ -6,12 +6,6 @@
"direction": "in",
"type": "timerTrigger"
},
- {
- "type": "queue",
- "direction": "out",
- "name": "QueueItem",
- "queueName": "CIPPGenericQueue"
- },
{
"name": "starter",
"type": "durableClient",
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 fb467b15735a..84197c89467d 100644
--- a/version_latest.txt
+++ b/version_latest.txt
@@ -1 +1 @@
-5.2.2
\ No newline at end of file
+5.3.2