From f97a15f4322466c11ba918bc2a71d35d7b36a542 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 18 Apr 2024 10:50:36 +0100 Subject: [PATCH 01/91] Add or update the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippvh5nk.yml | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/dev_cippvh5nk.yml diff --git a/.github/workflows/dev_cippvh5nk.yml b/.github/workflows/dev_cippvh5nk.yml new file mode 100644 index 000000000000..c7d375ed8294 --- /dev/null +++ b/.github/workflows/dev_cippvh5nk.yml @@ -0,0 +1,39 @@ +# 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 - cippvh5nk + +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 + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: 'Checkout GitHub Action' + uses: actions/checkout@v4 + + - name: Login to Azure + uses: azure/login@v1 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_ED1E0A192CC84FB39D2885D8FF29421B }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_A66877D40BDD4506847ED47322EDC20E }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_6CCE0805C50E49198BC0E3120CDD3D01 }} + + - name: 'Run Azure Functions Action' + uses: Azure/functions-action@v1 + id: fa + with: + app-name: 'cippvh5nk' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + \ No newline at end of file From a89d73771e7ff7e28a8885f6523c7f20059ed45b Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 18 Apr 2024 10:53:23 +0100 Subject: [PATCH 02/91] Remove the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippvh5nk.yml | 39 ----------------------------- 1 file changed, 39 deletions(-) delete mode 100644 .github/workflows/dev_cippvh5nk.yml diff --git a/.github/workflows/dev_cippvh5nk.yml b/.github/workflows/dev_cippvh5nk.yml deleted file mode 100644 index c7d375ed8294..000000000000 --- a/.github/workflows/dev_cippvh5nk.yml +++ /dev/null @@ -1,39 +0,0 @@ -# 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 - cippvh5nk - -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 - permissions: - id-token: write #This is required for requesting the JWT - - steps: - - name: 'Checkout GitHub Action' - uses: actions/checkout@v4 - - - name: Login to Azure - uses: azure/login@v1 - with: - client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_ED1E0A192CC84FB39D2885D8FF29421B }} - tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_A66877D40BDD4506847ED47322EDC20E }} - subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_6CCE0805C50E49198BC0E3120CDD3D01 }} - - - name: 'Run Azure Functions Action' - uses: Azure/functions-action@v1 - id: fa - with: - app-name: 'cippvh5nk' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - \ No newline at end of file From 204742cc523b5e84157961e90afab55a6c35ac01 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 18 Apr 2024 10:54:01 +0100 Subject: [PATCH 03/91] Add or update the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippvh5nk.yml | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/dev_cippvh5nk.yml diff --git a/.github/workflows/dev_cippvh5nk.yml b/.github/workflows/dev_cippvh5nk.yml new file mode 100644 index 000000000000..2b59c8daa0a4 --- /dev/null +++ b/.github/workflows/dev_cippvh5nk.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 - cippvh5nk + +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: 'cippvh5nk' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_F6B5A8FF1F8B4E8EB34F0C41340AFF45 }} \ No newline at end of file From d5c9398f4483b072ead25f3eca9b538230298d05 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Mon, 29 Apr 2024 10:04:05 +0100 Subject: [PATCH 04/91] Remove the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippvh5nk.yml | 30 ----------------------------- 1 file changed, 30 deletions(-) delete mode 100644 .github/workflows/dev_cippvh5nk.yml diff --git a/.github/workflows/dev_cippvh5nk.yml b/.github/workflows/dev_cippvh5nk.yml deleted file mode 100644 index 2b59c8daa0a4..000000000000 --- a/.github/workflows/dev_cippvh5nk.yml +++ /dev/null @@ -1,30 +0,0 @@ -# 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 - cippvh5nk - -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: 'cippvh5nk' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_F6B5A8FF1F8B4E8EB34F0C41340AFF45 }} \ No newline at end of file From c3e289531535734e2bc3b2888ed489f8e15846df Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Fri, 17 May 2024 07:56:40 +0100 Subject: [PATCH 05/91] Add or update the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippvh5nk.yml | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/dev_cippvh5nk.yml diff --git a/.github/workflows/dev_cippvh5nk.yml b/.github/workflows/dev_cippvh5nk.yml new file mode 100644 index 000000000000..dbe0410fb709 --- /dev/null +++ b/.github/workflows/dev_cippvh5nk.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 - cippvh5nk + +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: 'cippvh5nk' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_AF29E35A0BA344B1A163D7A38F78191D }} \ No newline at end of file From c375b6cd1c94070a4d2e4d5af8464e8cec6f051a Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Fri, 17 May 2024 08:26:16 +0100 Subject: [PATCH 06/91] Moved Tenant Name to beginning of subject Moved Tenant Name to beginning of subject --- .../Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index de573c156b7a..3659d68b8b2f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -61,7 +61,7 @@ function Push-ExecScheduledCommand { $TableDesign = '' $FinalResults = if ($results -is [array] -and $results[0] -is [string]) { $Results | ConvertTo-Html -Fragment -Property @{ l = 'Text'; e = { $_ } } } else { $Results | ConvertTo-Html -Fragment } $HTML = $FinalResults -replace '', "This alert is for tenant $tenant.

$TableDesign
" | Out-String - $title = "$TaskType - $($task.Name) - $tenant" + $title = "$TaskType - $tenant - $($task.Name)" Write-Host 'Scheduler: Sending the results to the target.' Write-Host "The content of results is: $Results" switch -wildcard ($task.PostExecution) { From 80a251a488c0ab92028e0dd42c1f168b7eaa61a2 Mon Sep 17 00:00:00 2001 From: Esco Date: Sat, 1 Jun 2024 01:38:12 +0200 Subject: [PATCH 07/91] Create .editorconfig --- .editorconfig | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000000..b0c2c5085172 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +insert_final_newline = true + +[*.{ps1, psd1, psm1}] +indent_size = 4 +end_of_line = crlf +trim_trailing_whitespace = true + +[*.json] +indent_size = 2 +end_of_line = crlf +trim_trailing_whitespace = true + +[*.{md, txt}] +end_of_line = crlf +max_line_length = off +trim_trailing_whitespace = false From 82efcb2c8d3fb9fe07e70897946fe609292f6b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Mon, 10 Jun 2024 17:44:30 +0200 Subject: [PATCH 08/91] Apparently there is 2 of these --- Cache_SAMSetup/SAMManifest.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index 82bab306ef89..b6b291da57b4 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -157,7 +157,9 @@ { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, { "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", "type": "Scope" }, - { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" } + { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, + { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" } ] }, { From ba878225693633e487f7f3aa4d9328460a065ad2 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Jun 2024 19:02:16 -0400 Subject: [PATCH 09/91] Custom Roles: Fix blocked tenants --- Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 | 4 +--- .../HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 1336247272bb..c10a38349d7b 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -47,7 +47,6 @@ function Test-CIPPAccess { $Permission.AllowedTenants | Where-Object { $Permission.BlockedTenants -notcontains $_ } } } - Write-Information ($LimitedTenantList | ConvertTo-Json) return $LimitedTenantList } @@ -77,11 +76,10 @@ function Test-CIPPAccess { } else { $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId if ($Role.AllowedTenants -contains 'AllTenants') { - $AllowedTenants = $Tenants + $AllowedTenants = $Tenants.customerId } else { $AllowedTenants = $Role.AllowedTenants } - if ($Tenant) { $TenantAllowed = $AllowedTenants -contains $Tenant -and $Role.BlockedTenants -notcontains $Tenant if (!$TenantAllowed) { continue } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 index dafe35d226f8..a1e92d2c3f89 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 @@ -43,12 +43,12 @@ function Invoke-ExecCustomRole { if ($Role.AllowedTenants) { $Role.AllowedTenants = @($Role.AllowedTenants | ConvertFrom-Json) } else { - $Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @() + $Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @() -Force } if ($Role.BlockedTenants) { $Role.BlockedTenants = @($Role.BlockedTenants | ConvertFrom-Json) } else { - $Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() + $Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() -Force } $Role } From 517a6b2ba7dda3c17d463c77970ad0a2980884d3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 11 Jun 2024 08:49:41 -0400 Subject: [PATCH 10/91] audit log polling functions --- .../GraphHelper/New-GraphGetRequest.ps1 | 33 ++++++- .../Webhooks/Get-CIPPAuditLogContent.ps1 | 24 +++++ .../Get-CIPPAuditLogContentBundles.ps1 | 98 +++++++++++++++++++ 3 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 create mode 100644 Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index 28e88e204d79..f6cd55dd5bdc 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -12,7 +12,8 @@ function New-GraphGetRequest { $NoAuthCheck, $skipTokenCache, [switch]$ComplexFilter, - [switch]$CountOnly + [switch]$CountOnly, + [switch]$IncludeResponseHeaders ) if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { @@ -43,13 +44,35 @@ function New-GraphGetRequest { $ReturnedData = do { try { - $Data = (Invoke-RestMethod -Uri $nextURL -Method GET -Headers $headers -ContentType 'application/json; charset=utf-8') + $GraphRequest = @{ + Uri = $nextURL + Method = 'GET' + Headers = $headers + ContentType = 'application/json; charset=utf-8' + } + if ($IncludeResponseHeaders) { + $GraphRequest.ResponseHeadersVariable = 'ResponseHeaders' + } + $Data = (Invoke-RestMethod @GraphRequest) if ($CountOnly) { $Data.'@odata.count' - $nextURL = $null + $NextURL = $null } else { if ($data.value) { $data.value } else { ($Data) } - if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' } + if ($noPagination) { + $nextURL = $null + } else { + $NextPageUriFound = $false + if ($IncludeResponseHeaders) { + if ($ResponseHeaders.NextPageUri) { + $NextURL = $ResponseHeaders.NextPageUri + $NextPageUriFound = $true + } + } + if (!$NextPageUriFound) { + $nextURL = $data.'@odata.nextLink' + } + } } } catch { $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message @@ -61,7 +84,7 @@ function New-GraphGetRequest { } throw $Message } - } until ($null -eq $NextURL -or ' ' -eq $NextURL) + } until ([string]::IsNullOrEmpty($NextURL) -or $NextURL -is [object[]] -or ' ' -eq $NextURL) $Tenant.LastGraphError = '' Update-AzDataTableEntity @TenantsTable -Entity $Tenant return $ReturnedData diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 new file mode 100644 index 000000000000..6cf1f63e4a27 --- /dev/null +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 @@ -0,0 +1,24 @@ +function Get-CIPPAuditLogContent { + <# + .SYNOPSIS + Get the content of an audit log. + .PARAMETER ContentUri + The URI of the content to get. + .PARAMETER TenantFilter + The tenant to filter on. + .EXAMPLE + Get-CIPPAuditLogContent -ContentUri 'https://manage.office.com/api/v1.0/contoso.com/activity/feed/subscriptions/content?contentType=Audit.General&PublisherIdentifier=00000000-0000-0000-0000-000000000000' -TenantFilter 'contoso.com' + .FUNCTIONALITY + Internal + #> + Param( + [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] + [string]$ContentUri, + [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] + [string]$TenantFilter + ) + + Process { + New-GraphPOSTRequest -type GET -uri $ContentUri -tenantid $TenantFilter -scope 'https://manage.office.com/.default' + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 new file mode 100644 index 000000000000..96998c65e902 --- /dev/null +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -0,0 +1,98 @@ +function Get-CIPPAuditLogContentBundles { + <# + .SYNOPSIS + Get the available audit log bundles + .DESCRIPTION + Query the Office 365 Activity Log API for available content bundles. + .PARAMETER TenantFilter + The tenant to filter on. + .PARAMETER ContentType + The type of content to get. + .PARAMETER StartTime + The start time to filter on. + .PARAMETER EndTime + The end time to filter on. + .PARAMETER ShowAll + Show all content, default is only show new content + .EXAMPLE + Get-CIPPAuditLogContentBundles -TenantFilter 'contoso.com' -ContentType 'Audit.AzureActiveDirectory' + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$TenantFilter, + [Parameter(Mandatory = $true)] + [ValidateSet('Audit.AzureActiveDirectory', 'Audit.Exchange')] + [string]$ContentType, + [datetime]$StartTime, + [datetime]$EndTime, + [switch]$ShowAll + ) + + if ($TenantFilter -eq 'AllTenants') { + throw 'AllTenants is not a valid tenant filter for webhooks' + } + + if (!($TenantFilter -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')) { + $DefaultDomainName = $TenantFilter + $TenantFilter = (Get-Tenants | Where-Object { $_.defaultDomainName -eq $TenantFilter }).customerId + } else { + $DefaultDomainName = (Get-Tenants | Where-Object { $_.customerId -eq $TenantFilter }).defaultDomainName + } + + $WebhookTable = Get-CippTable -TableName 'webhookTable' + $WebhookConfig = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq '$DefaultDomainName' and Version eq '3' and Resource eq '$ContentType'" + if (!$WebhookConfig) { + throw "No webhook config found for $DefaultDomainName - $ContentType" + } + + $Parameters = @{ + 'contentType' = $ContentType + 'PublisherIdentifier' = $env:TenantId + } + + if (!$ShowAll.IsPresent) { + if ($WebhookConfig.LastContentCreated) { + $StartTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime() + $EndTime = Get-Date + } + } + + if ($StartTime) { + $Parameters.Add('startTime', $StartTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss')) + if ($EndTime) { + $Parameters.Add('endTime', $EndTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss')) + } else { + $Parameters.Add('endTime', (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss')) + } + } + + $GraphQuery = [System.UriBuilder]('https://manage.office.com/api/v1.0/{0}/activity/feed/subscriptions/content' -f $TenantFilter) + $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + foreach ($Item in ($Parameters.GetEnumerator())) { + $ParamCollection.Add($Item.Key, $Item.Value) + } + $GraphQuery.Query = $ParamCollection.ToString() + + $LogBundles = New-GraphGetRequest -uri $GraphQuery.ToString() -tenantid $TenantFilter -scope 'https://manage.office.com/.default' -IncludeResponseHeaders + $AuditLogContents = $LogBundles | Select-Object contentUri, contentCreated, @{Name = 'TenantFilter'; Expression = { $TenantFilter } } + $LastContent = ($AuditLogContents | Sort-Object contentCreated -Descending | Select-Object -First 1 -ExpandProperty contentCreated) | Get-Date + + if (!$ShowAll.IsPresent) { + if ($WebhookConfig.LastContentCreated) { + $AuditLogContents = $AuditLogContents | Where-Object { ($_.contentCreated | Get-Date).ToLocalTime() -gt $StartTime } + } + if ($LastContent) { + if ($WebhookConfig.PSObject.Properties.Name -contains 'LastContentCreated') { + $WebhookConfig.LastContentCreated = [datetime]$LastContent + } else { + $WebhookConfig | Add-Member -MemberType NoteProperty -Name LastContentCreated -Value '' + $WebhookConfig.LastContentCreated = [datetime]$LastContent + } + $null = Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookConfig -Force + } + } + return $AuditLogContents +} \ No newline at end of file From f7a04f1587cccabb84d6cf7c36890a5255329281 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 11 Jun 2024 14:10:48 -0400 Subject: [PATCH 11/91] Audit Log Polling --- .../Public/CippQueue/Invoke-ListCippQueue.ps1 | 1 + .../Push-AuditLogBundleProcessing.ps1 | 48 +++++ .../Push-PublicWebhookProcess.ps1 | 0 .../Push-Schedulerwebhookcreation.ps1 | 7 +- .../Alerts/Invoke-PublicWebhooks.ps1 | 160 +---------------- .../CIPPCore/Public/Get-SlackAlertBlocks.ps1 | 7 +- .../GraphHelper/New-GraphGetRequest.ps1 | 2 +- Modules/CIPPCore/Public/Send-CIPPAlert.ps1 | 2 +- .../Webhooks/Get-CIPPAuditLogContent.ps1 | 1 + .../Get-CIPPAuditLogContentBundles.ps1 | 3 +- .../Invoke-CIPPGraphWebhookProcessing.ps1 | 0 .../Invoke-CIPPGraphWebhookRenewal.ps1 | 0 .../Invoke-CIPPPartnerWebhookProcessing.ps1 | 0 .../Invoke-CIPPWebhookProcessing.ps1 | 4 +- .../Invoke-RemoveWebhookAlert.ps1 | 0 .../New-CIPPGraphSubscription.ps1 | 30 +--- .../Remove-CIPPGraphSubscription.ps1 | 2 +- .../Webhooks/Test-CIPPAuditLogRules.ps1 | 168 ++++++++++++++++++ Scheduler_PollAuditLogs/function.json | 15 ++ Scheduler_PollAuditLogs/run.ps1 | 31 ++++ 20 files changed, 287 insertions(+), 194 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 rename Modules/CIPPCore/Public/Entrypoints/Activity Triggers/{ => Webhooks}/Push-PublicWebhookProcess.ps1 (100%) rename Modules/CIPPCore/Public/Entrypoints/Activity Triggers/{ => Webhooks}/Push-Schedulerwebhookcreation.ps1 (82%) rename Modules/CIPPCore/Public/{ => Webhooks}/Invoke-CIPPGraphWebhookProcessing.ps1 (100%) rename Modules/CIPPCore/Public/{ => Webhooks}/Invoke-CIPPGraphWebhookRenewal.ps1 (100%) rename Modules/CIPPCore/Public/{ => Webhooks}/Invoke-CIPPPartnerWebhookProcessing.ps1 (100%) rename Modules/CIPPCore/Public/{ => Webhooks}/Invoke-CIPPWebhookProcessing.ps1 (97%) rename Modules/CIPPCore/Public/{ => Webhooks}/Invoke-RemoveWebhookAlert.ps1 (100%) rename Modules/CIPPCore/Public/{ => Webhooks}/New-CIPPGraphSubscription.ps1 (86%) rename Modules/CIPPCore/Public/{ => Webhooks}/Remove-CIPPGraphSubscription.ps1 (99%) create mode 100644 Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 create mode 100644 Scheduler_PollAuditLogs/function.json create mode 100644 Scheduler_PollAuditLogs/run.ps1 diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 index ef4357efefd5..209432df45dd 100644 --- a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 +++ b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 @@ -41,6 +41,7 @@ function Invoke-ListCippQueue { $TotalCompleted = $TaskStatus.Completed ?? 0 $TotalFailed = $TaskStatus.Failed ?? 0 $TotalRunning = $TaskStatus.Running ?? 0 + if ($Queue.TotalTasks -eq 0) { $Queue.TotalTasks = 1 } [PSCustomObject]@{ PartitionKey = $Queue.PartitionKey diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 new file mode 100644 index 000000000000..38575541f03e --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 @@ -0,0 +1,48 @@ +function Push-AuditLogBundleProcessing { + Param($Item) + $TenantFilter = $Item.TenantFilter + Write-Information "Audit log tenant filter: $TenantFilter" + $ConfigTable = get-cipptable -TableName 'WebhookRules' + $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable + #$WebhookIncoming = Get-CIPPTable -TableName 'WebhookIncoming' + $SchedulerConfig = Get-CIPPTable -TableName 'SchedulerConfig' + $CIPPURL = Get-CIPPAzDataTableEntity @SchedulerConfig -Filter "PartitionKey eq 'webhookcreation'" | Select-Object -First 1 -ExpandProperty CIPPURL + + $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } | ForEach-Object { + [pscustomobject]@{ + Tenants = ($_.Tenants | ConvertFrom-Json).fullValue + Conditions = $_.Conditions + Actions = $_.Actions + LogType = $_.Type + } + } + + if (($Configuration | Measure-Object).Count -eq 0) { + Write-Information "No configuration found for tenant $TenantFilter" + return + } + + $LogTypes = $Configuration.LogType | Select-Object -Unique + foreach ($LogType in $LogTypes) { + Write-Information "Querying for log type: $LogType" + try { + $DataToProcess = Test-CIPPAuditLogRules -TenantFilter $TenantFilter -LogType $LogType + + Write-Information "Webhook: Data to process found: $($DataToProcess.count) items" + foreach ($AuditLog in $DataToProcess) { + Write-Information "Processing $($item.operation)" + $Webhook = @{ + Data = $AuditLog + CIPPURL = [string]$CIPPURL + TenantFilter = $TenantFilter + } + #Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity -Force + #Write-Information ($AuditLog | ConvertTo-Json -Depth 10) + Invoke-CippWebhookProcessing @Webhook + } + } catch { + #Write-LogMessage -API 'Webhooks' -message 'Error processing webhooks' -sev Error -LogData (Get-CippException -Exception $_) + Write-Host ( 'Audit log error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + } + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-PublicWebhookProcess.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-PublicWebhookProcess.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-PublicWebhookProcess.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-PublicWebhookProcess.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 similarity index 82% rename from Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 index 8c56ccb98971..f35aed68b46a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 @@ -23,7 +23,7 @@ function Push-Schedulerwebhookcreation { foreach ($Tenant in $Tenants) { Write-Host "Working on $Tenant - $($Row.tenantid)" #use the queueitem to see if we already have a webhook for this tenant + webhooktype. If we do, delete this row from SchedulerConfig. - $Webhook = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq '$Tenant' and Version eq '2' and Resource eq '$($Row.webhookType)'" + $Webhook = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq '$Tenant' and Version eq '3' and Resource eq '$($Row.webhookType)'" if ($Webhook) { Write-Host "Found existing webhook for $Tenant - $($Row.webhookType)" if ($Row.tenantid -ne 'AllTenants') { @@ -32,17 +32,14 @@ function Push-Schedulerwebhookcreation { } else { Write-Host "No existing webhook for $Tenant - $($Row.webhookType) - Time to create." try { - $NewSub = New-CIPPGraphSubscription -TenantFilter $Tenant -EventType $Row.webhookType -BaseURL $Row.CIPPURL -auditLogAPI $true + $NewSub = New-CIPPGraphSubscription -TenantFilter $Tenant -EventType $Row.webhookType -auditLogAPI $true -CIPPURL if ($NewSub.Success -and $Row.tenantid -ne 'AllTenants') { Remove-AzDataTableEntity @Table -Entity $Row } else { Write-Host "Failed to create webhook for $Tenant - $($Row.webhookType) - $($_.Exception.Message)" - Write-LogMessage -message "Failed to create webhook for $Tenant - $($Row.webhookType)" -Sev 'Error' -LogData $_.Exception } } catch { Write-Host "Failed to create webhook for $Tenant - $($Row.webhookType): $($_.Exception.Message)" - Write-LogMessage -message "Failed to create webhook for $Tenant - $($Row.webhookType)" -Sev 'Error' -LogData $_.Exception - } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1 index 78cded90ff19..3a4e60373847 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1 @@ -65,165 +65,7 @@ function Invoke-PublicWebhooks { } Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity } else { - if ($request.headers.'x-ms-original-url' -notlike '*version=2*') { - return "Not replying to this webhook or processing it, as it's not a version 2 webhook." - } else { - try { - foreach ($ReceivedItem In $Request.body) { - $ReceivedItem = [pscustomobject]$ReceivedItem - $TenantFilter = (Get-Tenants | Where-Object -Property customerId -EQ $ReceivedItem.TenantId).defaultDomainName - Write-Host "Webhook TenantFilter: $TenantFilter" - $ConfigTable = get-cipptable -TableName 'WebhookRules' - $Configuration = (Get-CIPPAzDataTableEntity @ConfigTable) | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') -and $_.Type -eq $ReceivedItem.ContentType } | ForEach-Object { - [pscustomobject]@{ - Tenants = ($_.Tenants | ConvertFrom-Json).fullValue - Conditions = $_.Conditions - Actions = $_.Actions - LogType = $_.Type - } - } - if (!$Configuration.Tenants) { - Write-Host 'No tenants found for this webhook, probably an old entry. Skipping.' - continue - } - Write-Host "Webhook: The received content-type for $($TenantFilter) is $($ReceivedItem.ContentType)" - if ($ReceivedItem.ContentType -in $Configuration.LogType) { - $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 - } - - $PreProccessedData = $Data | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties -ErrorAction SilentlyContinue - $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' - $ProcessedData = foreach ($Data in $PreProccessedData) { - if ($Data.ExtendedProperties) { - $Data.CIPPExtendedProperties = ($Data.ExtendedProperties | ConvertTo-Json) - $Data.ExtendedProperties | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } - } - if ($Data.DeviceProperties) { - $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json) - $Data.DeviceProperties | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } - } - if ($Data.parameters) { - $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json) - $Data.parameters | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } - } - if ($Data.ModifiedProperties) { - $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json) - $Data.ModifiedProperties | ForEach-Object { $data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue } - } - if ($Data.ModifiedProperties) { $Data.ModifiedProperties | ForEach-Object { $data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue } } - - if ($data.clientip) { - if ($data.clientip -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$') { - $data.clientip = $data.clientip -replace ':\d+$', '' # Remove the port number if present - } - $Location = Get-CIPPAzDataTableEntity @LocationTable -Filter "RowKey eq '$($data.clientIp)'" | Select-Object -Last 1 - if ($Location) { - Write-Host 'Webhook: Got IP from cache' - $Country = $Location.CountryOrRegion - $City = $Location.City - $Proxy = $Location.Proxy - $hosting = $Location.Hosting - $ASName = $Location.ASName - } else { - Write-Host 'Webhook: We have to do a lookup' - $Location = Get-CIPPGeoIPLocation -IP $data.clientip - $Country = if ($Location.CountryCode) { $Location.CountryCode } else { 'Unknown' } - $City = if ($Location.City) { $Location.City } else { 'Unknown' } - $Proxy = if ($Location.Proxy -ne $null) { $Location.Proxy } else { 'Unknown' } - $hosting = if ($Location.Hosting -ne $null) { $Location.Hosting } else { 'Unknown' } - $ASName = if ($Location.ASName) { $Location.ASName } else { 'Unknown' } - $IP = $data.ClientIP - $LocationInfo = @{ - RowKey = [string]$data.clientip - PartitionKey = [string]$data.id - Tenant = [string]$TenantFilter - CountryOrRegion = "$Country" - City = "$City" - Proxy = "$Proxy" - Hosting = "$hosting" - ASName = "$ASName" - } - try { - $null = Add-CIPPAzDataTableEntity @LocationTable -Entity $LocationInfo -Force - } catch { - Write-Host "Webhook: Failed to add location info for $($data.clientip) to cache: $($_.Exception.Message)" - - } - } - $Data.CIPPGeoLocation = $Country - $Data.CIPPBadRepIP = $Proxy - $Data.CIPPHostedIP = $hosting - $Data.CIPPIPDetected = $IP - $Data.CIPPLocationInfo = ($Location | ConvertTo-Json) - } - $Data | Select-Object * -ExcludeProperty ExtendedProperties, DeviceProperties, parameters - } - - #Filter data based on conditions. - $Where = $Configuration | ForEach-Object { - $conditions = $_.Conditions | ConvertFrom-Json | Where-Object { $_.Input.value -ne '' } - $actions = $_.Actions - $conditionStrings = [System.Collections.Generic.List[string]]::new() - $CIPPClause = [System.Collections.Generic.List[string]]::new() - foreach ($condition in $conditions) { - $value = if ($condition.Input.value -is [array]) { - $arrayAsString = $condition.Input.value | ForEach-Object { - "'$_'" - } - "@($($arrayAsString -join ', '))" - } else { "'$($condition.Input.value)'" } - - $conditionStrings.Add("`$(`$_.$($condition.Property.label)) -$($condition.Operator.value) $value") - $CIPPClause.Add("$($condition.Property.label) is $($condition.Operator.label) $value") - } - $finalCondition = $conditionStrings -join ' -AND ' - - [PSCustomObject]@{ - clause = $finalCondition - expectedAction = $actions - CIPPClause = $CIPPClause - } - - } - Write-Host "Webhook: The list of operations in the data are $($ProcessedData.operation -join ', ')" - - $DataToProcess = foreach ($clause in $Where) { - Write-Host "Webhook: Processing clause: $($clause.clause)" - Write-Host "Webhook: If this clause would be true, the action would be: $($clause.expectedAction)" - $ReturnedData = $ProcessedData | Where-Object { Invoke-Expression $clause.clause } - if ($ReturnedData) { - $ReturnedData = foreach ($item in $ReturnedData) { - $item.CIPPAction = $clause.expectedAction - $item.CIPPClause = $clause.CIPPClause -join ' and ' - $item - } - } - $ReturnedData - } - - Write-Host "Webhook: 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]$item.id - Type = 'AuditLog' - Data = [string]($Item | ConvertTo-Json -Depth 10) - CIPPURL = $CIPPURL - TenantFilter = $TenantFilter - FunctionName = 'PublicWebhookProcess' - } - Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity -Force - } - } - } catch { - Write-Host "Webhook Failed: $($_.Exception.Message). Line number $($_.InvocationInfo.ScriptLineNumber)" - } - } + return 'Not replying to this webhook or processing it' } $Body = 'Webhook Recieved' $StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 index b59ce99a3160..60e42aee5ced 100644 --- a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 +++ b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 @@ -151,7 +151,7 @@ function Get-SlackAlertBlocks { $Fields = [system.collections.generic.list[object]]::new() foreach ($Key in $Payload.RawData.PSObject.Properties.Name) { # if value is json continue to next property - if ($Payload.RawData.$Key -is [string] -and ![string]::IsNullOrEmpty($Payload.RawData.$Key)) { + if ($Payload.RawData.$Key -is [string] -and ([string]::IsNullOrEmpty($Payload.RawData.$Key) -or (Test-Json $Payload.RawData.$Key -ErrorAction SilentlyContinue))) { continue } # if value is date object @@ -187,13 +187,14 @@ function Get-SlackAlertBlocks { }) } elseif (Test-Json $Payload.RawData.$Key.$SubKey -ErrorAction SilentlyContinue) { # parse json and iterate through properties - $SubKeyData = $Payload.RawData.$Key.$SubKey | ConvertFrom-Json + continue + <#$SubKeyData = $Payload.RawData.$Key.$SubKey | ConvertFrom-Json foreach ($SubSubKey in $SubKeyData.PSObject.Properties.Name) { $Fields.Add(@{ type = 'mrkdwn' text = "*$($Key)/$($SubKey)/$($SubSubKey):*`n" + $SubKeyData.$SubSubKey }) - } + }#> } else { $Fields.Add(@{ type = 'mrkdwn' diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index f6cd55dd5bdc..7da26be50d62 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -58,7 +58,7 @@ function New-GraphGetRequest { $Data.'@odata.count' $NextURL = $null } else { - if ($data.value) { $data.value } else { ($Data) } + if ($Data.PSObject.Properties.Name -contains 'value') { $data.value } else { ($Data) } if ($noPagination) { $nextURL = $null } else { diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index 8fc9e31f7bdf..89bd2ade79d2 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -79,7 +79,7 @@ function Send-CIPPAlert { } catch { Write-Information "Could not send alerts to webhook: $($_.Exception.message)" - Write-LogMessage -API 'Webhook Alerts' -message "Could not send alerts to webhook: $($_.Exception.message)" -tenant $TenantFilter -sev info + Write-LogMessage -API 'Webhook Alerts' -message "Could not send alerts to webhook: $($_.Exception.message)" -tenant $TenantFilter -sev error -LogData (Get-CippException -Exception $_) } } Write-Information 'Trying to send to PSA' diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 index 6cf1f63e4a27..6c6424d56857 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 @@ -11,6 +11,7 @@ function Get-CIPPAuditLogContent { .FUNCTIONALITY Internal #> + [CmdletBinding()] Param( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [string]$ContentUri, diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index 96998c65e902..67b667b9e793 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -76,11 +76,12 @@ function Get-CIPPAuditLogContentBundles { } $GraphQuery.Query = $ParamCollection.ToString() + Write-Verbose "GET [ $($GraphQuery.ToString()) ]" $LogBundles = New-GraphGetRequest -uri $GraphQuery.ToString() -tenantid $TenantFilter -scope 'https://manage.office.com/.default' -IncludeResponseHeaders $AuditLogContents = $LogBundles | Select-Object contentUri, contentCreated, @{Name = 'TenantFilter'; Expression = { $TenantFilter } } - $LastContent = ($AuditLogContents | Sort-Object contentCreated -Descending | Select-Object -First 1 -ExpandProperty contentCreated) | Get-Date if (!$ShowAll.IsPresent) { + $LastContent = ($AuditLogContents | Sort-Object contentCreated -Descending | Select-Object -First 1 -ExpandProperty contentCreated) | Get-Date if ($WebhookConfig.LastContentCreated) { $AuditLogContents = $AuditLogContents | Where-Object { ($_.contentCreated | Get-Date).ToLocalTime() -gt $StartTime } } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookProcessing.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookProcessing.ps1 rename to Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookProcessing.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookRenewal.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-CIPPGraphWebhookRenewal.ps1 rename to Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-CIPPPartnerWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPPartnerWebhookProcessing.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-CIPPPartnerWebhookProcessing.ps1 rename to Modules/CIPPCore/Public/Webhooks/Invoke-CIPPPartnerWebhookProcessing.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 similarity index 97% rename from Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 rename to Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 index a1787ddbae34..d5db2cf47076 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPWebhookProcessing.ps1 @@ -43,7 +43,7 @@ function Invoke-CippWebhookProcessing { "No Inbox Rules found for $username. We have not disabled any rules." } "Completed BEC Remediate for $username" - Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $username" -sev 'Info' + Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $username" -sev 'Info' } 'cippcommand' { $CommandSplat = @{} @@ -85,7 +85,7 @@ function Invoke-CippWebhookProcessing { ActionsTaken = [string]($ActionResults | ConvertTo-Json -Depth 15 -Compress) } | ConvertTo-Json -Depth 15 -Compress Write-Host 'Sending Webhook Content' - + #Write-Host $JsonContent Send-CIPPAlert -Type 'webhook' -Title $GenerateJSON.Title -JSONContent $JsonContent -TenantFilter $TenantFilter } } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-RemoveWebhookAlert.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 rename to Modules/CIPPCore/Public/Webhooks/Invoke-RemoveWebhookAlert.ps1 diff --git a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 similarity index 86% rename from Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 rename to Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 index 535156115d0b..eebd1163d61f 100644 --- a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 @@ -21,42 +21,32 @@ function New-CIPPGraphSubscription { if ($auditLogAPI) { $CIPPID = (New-Guid).GUID $Resource = $EventType - $CIPPAuditURL = "$BaseURL/API/Publicwebhooks?EventType=$EventType&CIPPID=$CIPPID&version=2" - $AuditLogParams = @{ - webhook = @{ - 'address' = $CIPPAuditURL - } - } | ConvertTo-Json - #List existing webhook subscriptions in table - $WebhookFilter = "PartitionKey eq '$($TenantFilter)' and Resource eq '$Resource' and Version eq '2'" + $WebhookFilter = "PartitionKey eq '$($TenantFilter)' and Resource eq '$Resource' and Version eq '3'" $ExistingWebhooks = Get-CIPPAzDataTableEntity @WebhookTable -Filter $WebhookFilter $MatchedWebhook = $ExistingWebhooks try { if (!$MatchedWebhook) { $WebhookRow = @{ - PartitionKey = [string]$TenantFilter - RowKey = [string]$CIPPID - Resource = $Resource - Expiration = 'Does Not Expire' - WebhookNotificationUrl = [string]$CIPPAuditURL - Version = '2' + PartitionKey = [string]$TenantFilter + RowKey = [string]$CIPPID + Resource = [string]$Resource + Expiration = [string]'Does Not Expire' + Version = [string]'3' } Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookRow Write-Host "Creating webhook subscription for $EventType" - $AuditLog = New-GraphPOSTRequest -uri "https://manage.office.com/api/v1.0/$($TenantFilter)/activity/feed/subscriptions/start?contentType=$EventType&PublisherIdentifier=$($TenantFilter)" -tenantid $TenantFilter -type POST -scope 'https://manage.office.com/.default' -body $AuditLogparams -verbose + $AuditLog = New-GraphPOSTRequest -type POST -uri "https://manage.office.com/api/v1.0/$($TenantFilter)/activity/feed/subscriptions/start?contentType=$EventType&PublisherIdentifier=$($env:TenantId)" -tenantid $TenantFilter -scope 'https://manage.office.com/.default' -body '{}' -verbose Write-LogMessage -user $ExecutingUser -API $APIName -message "Created Webhook subscription for $($TenantFilter) for the log $($EventType)" -Sev 'Info' -tenant $TenantFilter - } else { - Write-LogMessage -user $ExecutingUser -API $APIName -message "No webhook creation required for $($TenantFilter). Already exists" -Sev 'Info' -tenant $TenantFilter } - return @{ success = $true; message = "Created Webhook subscription for $($TenantFilter) for the log $($EventType)" } + return @{ Success = $true; message = "Created Webhook subscription for $($TenantFilter) for the log $($EventType)" } } catch { if ($_.Exception.Message -like '*already exists*') { return @{ success = $true; message = "Webhook exists for $($TenantFilter) for the log $($EventType)" } Write-LogMessage -user $ExecutingUser -API $APIName -message "Webhook subscription for $($TenantFilter) already exists" -Sev 'Info' -tenant $TenantFilter } else { Remove-AzDataTableEntity @WebhookTable -Entity @{ PartitionKey = $TenantFilter; RowKey = [string]$CIPPID } | Out-Null - Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to create Webhook Subscription for $($TenantFilter): $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to create Webhook Subscription for $($TenantFilter): $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter -LogData (Get-CippException -Exception $_) return @{ success = $false; message = "Failed to create Webhook Subscription for $($TenantFilter): $($_.Exception.Message)" } } } @@ -95,11 +85,9 @@ function New-CIPPGraphSubscription { if ($Existing.WebhookUrl) { $Action = 'Updated' $Method = 'PUT' - Write-Host 'updating webhook' } else { $Action = 'Created' $Method = 'POST' - Write-Host 'creating webhook' } $Uri = 'https://api.partnercenter.microsoft.com/webhooks/v1/registration' diff --git a/Modules/CIPPCore/Public/Remove-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/Webhooks/Remove-CIPPGraphSubscription.ps1 similarity index 99% rename from Modules/CIPPCore/Public/Remove-CIPPGraphSubscription.ps1 rename to Modules/CIPPCore/Public/Webhooks/Remove-CIPPGraphSubscription.ps1 index 88138b99ccc3..e64f366d7830 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Remove-CIPPGraphSubscription.ps1 @@ -13,7 +13,7 @@ function Remove-CIPPGraphSubscription { if ($Cleanup) { #list all subscriptions on the management API $Subscriptions = New-GraphPOSTRequest -type GET -uri "https://manage.office.com/api/v1.0/$($TenantFilter)/activity/feed/subscriptions/list" -scope 'https://manage.office.com/.default' -tenantid $TenantFilter -verbose - foreach ($Sub in $Subscriptions | Where-Object { $_.webhook.address -like '*CIPP*' -and $_.webhook.address -notlike '*version=2*' }) { + foreach ($Sub in $Subscriptions | Where-Object { $_.webhook.address -like '*CIPP*' -and $_.webhook.address -notlike '*version=3*' }) { Try { $AuditLog = New-GraphPOSTRequest -uri "https://manage.office.com/api/v1.0/$($TenantFilter)/activity/feed/subscriptions/stop?contentType=$($sub.contentType)" -scope 'https://manage.office.com/.default' -tenantid $TenantFilter -type POST -body '{}' -verbose Try { diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 new file mode 100644 index 000000000000..1714544a6e6c --- /dev/null +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -0,0 +1,168 @@ +function Test-CIPPAuditLogRules { + [CmdletBinding()] + Param( + [Parameter(Mandatory = $true)] + $TenantFilter, + [Parameter(Mandatory = $true)] + [ValidateSet('Audit.AzureActiveDirectory', 'Audit.Exchange')] + $LogType, + [switch]$ShowAll + ) + + $ExtendedPropertiesIgnoreList = @( + 'OAuth2:Authorize' + 'OAuth2:Token' + 'SAS:EndAuth' + 'SAS:ProcessAuth' + ) + + $TrustedIPTable = Get-CIPPTable -TableName 'trustedIps' + $ConfigTable = Get-CIPPTable -TableName 'WebhookRules' + $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable + $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } | ForEach-Object { + [pscustomobject]@{ + Tenants = ($_.Tenants | ConvertFrom-Json).fullValue + Conditions = $_.Conditions + Actions = $_.Actions + LogType = $_.Type + } + } + $ContentBundleQuery = @{ + TenantFilter = $TenantFilter + ContentType = $LogType + ShowAll = $ShowAll.IsPresent + } + Write-Information 'Getting data from Office 365 Management Activity API' + $Data = Get-CIPPAuditLogContentBundles @ContentBundleQuery | Get-CIPPAuditLogContent + $LogCount = ($Data | Measure-Object).Count + Write-Information "Logs to process: $LogCount" + if ($LogCount -gt 0) { + $PreProccessedData = $Data | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties -ErrorAction SilentlyContinue + $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' + $ProcessedData = foreach ($Data in $PreProccessedData) { + if ($Data.ExtendedProperties) { + $Data.CIPPExtendedProperties = ($Data.ExtendedProperties | ConvertTo-Json) + if ($Data.CIPPExtendedProperties.RequestType -in $ExtendedPropertiesIgnoreList) { + Write-Information 'No need to process this operation as its in our ignore list' + continue + } + $Data.ExtendedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } + } + if ($Data.DeviceProperties) { + $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json) + $Data.DeviceProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } + } + if ($Data.parameters) { + $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json) + $Data.parameters | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } + } + if ($Data.ModifiedProperties) { + $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json) + try { + $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue } + } catch { + Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) + } + try { + $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue } + } catch { + Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) + } + } + + if ($Data.clientip) { + if ($Data.clientip -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$') { + $Data.clientip = $Data.clientip -replace ':\d+$', '' # Remove the port number if present + } + # Check if IP is on trusted IP list + $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Data.clientip)' and state eq 'Trusted'" + if ($TrustedIP) { + Write-Information "IP $($Data.clientip) is trusted" + continue + } + + $Location = Get-CIPPAzDataTableEntity @LocationTable -Filter "RowKey eq '$($Data.clientIp)'" | Select-Object -Last 1 + if ($Location) { + $Country = $Location.CountryOrRegion + $City = $Location.City + $Proxy = $Location.Proxy + $hosting = $Location.Hosting + $ASName = $Location.ASName + } else { + $Location = Get-CIPPGeoIPLocation -IP $Data.clientip + $Country = if ($Location.CountryCode) { $Location.CountryCode } else { 'Unknown' } + $City = if ($Location.City) { $Location.City } else { 'Unknown' } + $Proxy = if ($Location.Proxy -ne $null) { $Location.Proxy } else { 'Unknown' } + $hosting = if ($Location.Hosting -ne $null) { $Location.Hosting } else { 'Unknown' } + $ASName = if ($Location.ASName) { $Location.ASName } else { 'Unknown' } + $IP = $Data.ClientIP + $LocationInfo = @{ + RowKey = [string]$Data.clientip + PartitionKey = [string]$Data.id + Tenant = [string]$TenantFilter + CountryOrRegion = "$Country" + City = "$City" + Proxy = "$Proxy" + Hosting = "$hosting" + ASName = "$ASName" + } + try { + $null = Add-CIPPAzDataTableEntity @LocationTable -Entity $LocationInfo -Force + } catch { + Write-Information "Failed to add location info for $($Data.clientip) to cache: $($_.Exception.Message)" + + } + } + $Data.CIPPGeoLocation = $Country + $Data.CIPPBadRepIP = $Proxy + $Data.CIPPHostedIP = $hosting + $Data.CIPPIPDetected = $IP + $Data.CIPPLocationInfo = ($Location | ConvertTo-Json) + } + $Data | Select-Object * -ExcludeProperty ExtendedProperties, DeviceProperties, parameters + } + + #Filter data based on conditions. + $Where = $Configuration | Where-Object { $_.LogType -eq $LogType } | ForEach-Object { + $conditions = $_.Conditions | ConvertFrom-Json | Where-Object { $_.Input.value -ne '' } + $actions = $_.Actions + $conditionStrings = [System.Collections.Generic.List[string]]::new() + $CIPPClause = [System.Collections.Generic.List[string]]::new() + foreach ($condition in $conditions) { + $value = if ($condition.Input.value -is [array]) { + $arrayAsString = $condition.Input.value | ForEach-Object { + "'$_'" + } + "@($($arrayAsString -join ', '))" + } else { "'$($condition.Input.value)'" } + + $conditionStrings.Add("`$(`$_.$($condition.Property.label)) -$($condition.Operator.value) $value") + $CIPPClause.Add("$($condition.Property.label) is $($condition.Operator.label) $value") + } + $finalCondition = $conditionStrings -join ' -AND ' + + [PSCustomObject]@{ + clause = $finalCondition + expectedAction = $actions + CIPPClause = $CIPPClause + } + + } + Write-Information "Webhook: The list of operations in the data are $(($ProcessedData.operation | Select-Object -Unique) -join ', ')" + + $DataToProcess = foreach ($clause in $Where) { + Write-Information "Webhook: Processing clause: $($clause.clause)" + Write-Information "Webhook: If this clause would be true, the action would be: $($clause.expectedAction)" + $ReturnedData = $ProcessedData | Where-Object { Invoke-Expression $clause.clause } + if ($ReturnedData) { + $ReturnedData = foreach ($item in $ReturnedData) { + $item.CIPPAction = $clause.expectedAction + $item.CIPPClause = $clause.CIPPClause -join ' and ' + $item + } + } + $ReturnedData + } + $DataToProcess + } +} \ No newline at end of file diff --git a/Scheduler_PollAuditLogs/function.json b/Scheduler_PollAuditLogs/function.json new file mode 100644 index 000000000000..de05da024fc9 --- /dev/null +++ b/Scheduler_PollAuditLogs/function.json @@ -0,0 +1,15 @@ +{ + "bindings": [ + { + "name": "Timer", + "schedule": "0 */5 * * * *", + "direction": "in", + "type": "timerTrigger" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" + } + ] +} diff --git a/Scheduler_PollAuditLogs/run.ps1 b/Scheduler_PollAuditLogs/run.ps1 new file mode 100644 index 000000000000..4052f81d4c00 --- /dev/null +++ b/Scheduler_PollAuditLogs/run.ps1 @@ -0,0 +1,31 @@ +param($Timer) + +try { + $webhookTable = Get-CIPPTable -tablename webhookTable + $Webhooks = Get-CIPPAzDataTableEntity @webhookTable -Filter "Version eq '3'" | Where-Object { $_.Resource -match '^Audit' } + if (($Webhooks | Measure-Object).Count -eq 0) { + Write-Host 'No webhook subscriptions found. Exiting.' + return + } + + try { + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq 'AuditLogCollection' -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } + if ($RunningQueue) { + Write-Host 'Audit log collection already running' + return + } + } catch {} + + $Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($Webhooks | Sort-Object -Property PartitionKey -Unique | Measure-Object).Count + $Batch = $Webhooks | Sort-Object -Property PartitionKey -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.PartitionKey } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogBundleProcessing' } } + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'AuditLogs' + Batch = @($Batch) + SkipLog = $true + } + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) + Write-Host "Started orchestration with ID = '$InstanceId'" +} catch { + Write-LogMessage -API 'Webhooks' -message 'Error processing webhooks' -sev Error -LogData (Get-CippException -Exception $_) + Write-Host ( 'Webhook error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) +} From f0bc9dc85a06af4b1ff41b52600d57e1ccc9a6f5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 11 Jun 2024 15:20:29 -0400 Subject: [PATCH 12/91] Update Push-Schedulerwebhookcreation.ps1 --- .../Webhooks/Push-Schedulerwebhookcreation.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 index f35aed68b46a..47aa38b1a072 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-Schedulerwebhookcreation.ps1 @@ -32,7 +32,7 @@ function Push-Schedulerwebhookcreation { } else { Write-Host "No existing webhook for $Tenant - $($Row.webhookType) - Time to create." try { - $NewSub = New-CIPPGraphSubscription -TenantFilter $Tenant -EventType $Row.webhookType -auditLogAPI $true -CIPPURL + $NewSub = New-CIPPGraphSubscription -TenantFilter $Tenant -EventType $Row.webhookType -auditLogAPI $true if ($NewSub.Success -and $Row.tenantid -ne 'AllTenants') { Remove-AzDataTableEntity @Table -Entity $Row } else { From 0e50c54a24dee6627b9cf4c2a7bfcb2c01d3ab52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 12 Jun 2024 19:11:46 +0200 Subject: [PATCH 13/91] Add PeopleSettings.ReadWrite.All application permissions --- Cache_SAMSetup/SAMManifest.json | 3 ++- Modules/CIPPCore/Public/SAMManifest.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cache_SAMSetup/SAMManifest.json b/Cache_SAMSetup/SAMManifest.json index b6b291da57b4..b7ee864cd6f6 100644 --- a/Cache_SAMSetup/SAMManifest.json +++ b/Cache_SAMSetup/SAMManifest.json @@ -159,7 +159,8 @@ { "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", "type": "Scope" }, { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, - { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" } + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, + { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" } ] }, { diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index b6b291da57b4..b7ee864cd6f6 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -159,7 +159,8 @@ { "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", "type": "Scope" }, { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, - { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" } + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, + { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" } ] }, { From 9393fea7a4bc16676851f3f4565aea4260df6203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 12 Jun 2024 19:19:48 +0200 Subject: [PATCH 14/91] Update Invoke-ExecMailboxMobileDevices.ps1 to include Guid parameter --- .../Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 index 7b58b76afc7c..b633755f759b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 @@ -20,7 +20,7 @@ Function Invoke-ExecMailboxMobileDevices { # Interact with query parameters or the body of the request. Try { - $MobileResults = Set-CIPPMobileDevice -UserId $request.query.Userid -DeviceId $request.query.deviceid -Quarantine $request.query.Quarantine -tenantFilter $request.query.tenantfilter -APIName $APINAME -Delete $Request.query.Delete -ExecutingUser $request.headers.'x-ms-client-principal' + $MobileResults = Set-CIPPMobileDevice -UserId $request.query.Userid -Guid $request.query.guid -DeviceId $request.query.deviceid -Quarantine $request.query.Quarantine -tenantFilter $request.query.tenantfilter -APIName $APINAME -Delete $Request.query.Delete -ExecutingUser $request.headers.'x-ms-client-principal' $Results = [pscustomobject]@{'Results' = $MobileResults } } catch { $Results = [pscustomobject]@{'Results' = "Failed $($request.query.Userid): $($_.Exception.Message)" } From 73f13779deea2b9c49e7b9850f4ba119d038142b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 12 Jun 2024 19:35:55 +0200 Subject: [PATCH 15/91] Splat some parameters --- .../Standards/Invoke-CIPPStandardAPConfig.ps1 | 22 ++++++++++++++++--- .../Standards/Invoke-CIPPStandardAPESP.ps1 | 17 +++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 index b6ffea3946d5..4f168c0e6d2b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 @@ -7,15 +7,31 @@ function Invoke-CIPPStandardAPConfig { If ($Settings.remediate -eq $true) { - $APINAME = 'Standards' try { Write-Host $($settings | ConvertTo-Json -Depth 100) if ($settings.NotLocalAdmin -eq $true) { $usertype = 'Standard' } else { $usertype = 'Administrator' } $DeploymentMode = if ($settings.DeploymentMode -eq 'true') { 'shared' } else { 'singleUser' } - Set-CIPPDefaultAPDeploymentProfile -tenantFilter $tenant -displayname $settings.DisplayName -description $settings.Description -usertype $usertype -DeploymentMode $DeploymentMode -assignto $settings.Assignto -devicenameTemplate $Settings.DeviceNameTemplate -allowWhiteGlove $Settings.allowWhiteGlove -CollectHash $Settings.CollectHash -hideChangeAccount $Settings.HideChangeAccount -hidePrivacy $Settings.HidePrivacy -hideTerms $Settings.HideTerms -Autokeyboard $Settings.Autokeyboard -Language $Settings.languages.value + + $Parameters = @{ + tenantFilter = $tenant + displayname = $settings.DisplayName + description = $settings.Description + usertype = $usertype + DeploymentMode = $DeploymentMode + assignto = $settings.Assignto + devicenameTemplate = $Settings.DeviceNameTemplate + allowWhiteGlove = $Settings.allowWhiteGlove + CollectHash = $Settings.CollectHash + hideChangeAccount = $Settings.HideChangeAccount + hidePrivacy = $Settings.HidePrivacy + hideTerms = $Settings.HideTerms + Autokeyboard = $Settings.Autokeyboard + Language = $Settings.languages.value + } + Set-CIPPDefaultAPDeploymentProfile @Parameters } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - #Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Default Autopilot config: $ErrorMessage" -sev 'Error' + # Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Default Autopilot config: $ErrorMessage" -sev 'Error' throw $ErrorMessage } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 index 2749ec946573..478541ac8140 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 @@ -5,9 +5,20 @@ function Invoke-CIPPStandardAPESP { #> param($Tenant, $Settings) If ($Settings.remediate -eq $true) { - $APINAME = 'Standards' try { - Set-CIPPDefaultAPEnrollment -TenantFilter $Tenant -ShowProgress $Settings.ShowProgress -BlockDevice $Settings.blockDevice -AllowReset $Settings.AllowReset -EnableLog $Settings.EnableLog -ErrorMessage $Settings.ErrorMessage -TimeOutInMinutes $Settings.TimeOutInMinutes -AllowFail $Settings.AllowFail -OBEEOnly $Settings.OBEEOnly + $Parameters = @{ + TenantFilter = $Tenant + ShowProgress = $Settings.ShowProgress + BlockDevice = $Settings.blockDevice + AllowReset = $Settings.AllowReset + EnableLog = $Settings.EnableLog + ErrorMessage = $Settings.ErrorMessage + TimeOutInMinutes = $Settings.TimeOutInMinutes + AllowFail = $Settings.AllowFail + OBEEOnly = $Settings.OBEEOnly + } + + Set-CIPPDefaultAPEnrollment @Parameters } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message throw $ErrorMessage @@ -15,4 +26,4 @@ function Invoke-CIPPStandardAPESP { } -} \ No newline at end of file +} From 8d737546f13e1637d0e7b6b53f59be8d5d6f67a9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 12 Jun 2024 20:57:30 +0200 Subject: [PATCH 16/91] per user MFA --- .../CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 new file mode 100644 index 000000000000..74babb8fa860 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -0,0 +1,19 @@ +function Set-CIPPPerUserMFA { + [CmdletBinding()] + param( + $TenantFilter, + $userId, + [ValidateSet('enabled', 'disabled', 'enforced')] + $State = 'users', + $executingUser + ) + try { + $state = @{ 'perUserMfaState' = "$state" } | ConvertTo-Json + New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/users/$userId/authentication/requirements" -tenantid $tenantfilter -type PUT -body $state -ContentType $ContentType + "Successfully set Per user MFA State for $id" + Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State for $id" -Sev 'Info' -tenant $TenantFilter + } catch { + "Failed to set MFA State for $id : $_" + Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Failed to set MFA State for $id : $_" -Sev 'Error' -tenant $TenantFilter + } +} \ No newline at end of file From 32770b8acdcf73850ae009565cd2033219bba669 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 12 Jun 2024 20:59:30 +0200 Subject: [PATCH 17/91] fix per user patch --- Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index 74babb8fa860..e044fe6797a3 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -9,7 +9,7 @@ function Set-CIPPPerUserMFA { ) try { $state = @{ 'perUserMfaState' = "$state" } | ConvertTo-Json - New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/users/$userId/authentication/requirements" -tenantid $tenantfilter -type PUT -body $state -ContentType $ContentType + New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/users/$userId/authentication/requirements" -tenantid $tenantfilter -type PATCH -body $state "Successfully set Per user MFA State for $id" Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State for $id" -Sev 'Info' -tenant $TenantFilter } catch { From 171bd7b50d11fb34a1c691bf17c7f53d22c362f9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Jun 2024 15:43:02 -0400 Subject: [PATCH 18/91] Schema tweaks --- .../Public/Get-CIPPSchemaExtensions.ps1 | 11 ++++++++--- .../GraphHelper/New-GraphGetRequest.ps1 | 4 +++- .../Public/Set-CIPPUserSchemaProperties.ps1 | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 diff --git a/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 b/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 index 26794daffea7..b85edb06af86 100644 --- a/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 @@ -30,6 +30,10 @@ function Get-CIPPSchemaExtensions { name = 'autoExpandingArchiveEnabled' type = 'Boolean' } + @{ + name = 'perUserMfaState' + type = 'String' + } ) } ) @@ -40,8 +44,8 @@ function Get-CIPPSchemaExtensions { $SchemaFound = $true $Schema = $Schemas | Where-Object { $_.id -match $SchemaDefinition.id } $Patch = @{} - if (Compare-Object -ReferenceObject ($SchemaDefinition.properties | Select-Object name, type) -DifferenceObject $Schema.properties) { - $Patch.properties = $Properties + if (Compare-Object -ReferenceObject ($SchemaDefinition.properties | Select-Object name, type) -DifferenceObject ($Schema.properties | Select-Object name, type)) { + $Patch.properties = $SchemaDefinitions.Properties } if ($Schema.status -ne 'Available') { $Patch.status = 'Available' @@ -49,9 +53,10 @@ function Get-CIPPSchemaExtensions { if ($Schema.targetTypes -ne $SchemaDefinition.targetTypes) { $Patch.targetTypes = $SchemaDefinition.targetTypes } - if ($Patch.Keys.Count -gt 0) { + if ($Patch -and $Patch.Keys.Count -gt 0) { Write-Information "Updating $($Schema.id)" $Json = ConvertTo-Json -Depth 5 -InputObject $Patch + Write-Information $Json New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true } else { $Schema diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index 7da26be50d62..7c4eb8927b35 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -75,7 +75,9 @@ function New-GraphGetRequest { } } } catch { - $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message + try { + $Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message + } catch { $Message = $null } if ($Message -eq $null) { $Message = $($_.Exception.Message) } if ($Message -ne 'Request not applicable to target tenant.' -and $Tenant) { $Tenant.LastGraphError = $Message diff --git a/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 new file mode 100644 index 000000000000..0c6f1960ad0d --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 @@ -0,0 +1,19 @@ +function Set-CIPPUserSchemaProperties { + [CmdletBinding(SupportsShouldProcess = $true)] + Param( + [string]$TenantFilter, + [string]$UserId, + [hashtable]$Properties + ) + + $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } + + $Body = [PSCustomObject]@{ + "$($Schema.id)" = $Properties + } + + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + if ($PSCmdlet.ShouldProcess("User: $UserId", "Set Schema Properties to $($Properties|ConvertTo-Json -Compress)")) { + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter + } +} \ No newline at end of file From c6a8aaab978ee5c07926735e70096cae5db114e8 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Jun 2024 15:43:16 -0400 Subject: [PATCH 19/91] Fix casing on sam wizard --- .../CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 index 3818794ddbb0..9f38b50965a0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 @@ -11,7 +11,7 @@ Function Invoke-ExecSAMSetup { param($Request, $TriggerMetadata) $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) - if ($Request.query.error) { + if ($Request.Query.error) { Add-Type -AssemblyName System.Web Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ ContentType = 'text/html' @@ -61,25 +61,25 @@ Function Invoke-ExecSAMSetup { $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) try { - if ($Request.query.count -lt 1 ) { $Results = 'No authentication code found. Please go back to the wizard.' } + if ($Request.Query.count -lt 1 ) { $Results = 'No authentication code found. Please go back to the wizard.' } - if ($request.body.setkeys) { + if ($Request.Body.setkeys) { if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { - if ($request.body.TenantId) { $Secret.TenantId = $Request.body.tenantid } - if ($request.body.RefreshToken) { $Secret.RefreshToken = $Request.body.RefreshToken } - if ($request.body.applicationid) { $Secret.ApplicationId = $Request.body.ApplicationId } - if ($request.body.ApplicationSecret) { $Secret.ApplicationSecret = $Request.body.ApplicationSecret } + if ($Request.Body.TenantId) { $Secret.TenantId = $Request.Body.tenantid } + if ($Request.Body.RefreshToken) { $Secret.RefreshToken = $Request.Body.RefreshToken } + if ($Request.Body.applicationid) { $Secret.ApplicationId = $Request.Body.ApplicationId } + if ($Request.Body.ApplicationSecret) { $Secret.ApplicationSecret = $Request.Body.ApplicationSecret } Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { - if ($request.body.tenantid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $request.body.tenantid -AsPlainText -Force) } - if ($request.body.RefreshToken) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $request.body.RefreshToken -AsPlainText -Force) } - if ($request.body.applicationid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $request.body.applicationid -AsPlainText -Force) } - if ($request.body.applicationsecret) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $request.body.applicationsecret -AsPlainText -Force) } + if ($Request.Body.tenantid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $Request.Body.tenantid -AsPlainText -Force) } + if ($Request.Body.RefreshToken) { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Request.Body.RefreshToken -AsPlainText -Force) } + if ($Request.Body.applicationid) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Request.Body.applicationid -AsPlainText -Force) } + if ($Request.Body.applicationsecret) { Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $Request.Body.applicationsecret -AsPlainText -Force) } } $Results = @{ Results = 'The keys have been replaced. Please perform a permissions check.' } } - if ($Request.query.error -eq 'invalid_client') { $Results = 'Client ID was not found in Azure. Try waiting 10 seconds to try again, if you have gotten this error after 5 minutes, please restart the process.' } - if ($request.query.code) { + if ($Request.Query.error -eq 'invalid_client') { $Results = 'Client ID was not found in Azure. Try waiting 10 seconds to try again, if you have gotten this error after 5 minutes, please restart the process.' } + if ($Request.Query.code) { try { $TenantId = $Rows.tenantid if (!$TenantId) { $TenantId = $ENV:TenantId } @@ -89,11 +89,11 @@ Function Invoke-ExecSAMSetup { if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $clientsecret = $Secret.ApplicationSecret } else { - $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText + $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'ApplicationSecret' -AsPlainText } if (!$clientsecret) { $clientsecret = $ENV:ApplicationSecret } - Write-Host "client_id=$appid&scope=https://graph.microsoft.com/.default+offline_access+openid+profile&code=$($request.query.code)&grant_type=authorization_code&redirect_uri=$($url)&client_secret=$clientsecret" -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" - $RefreshToken = Invoke-RestMethod -Method POST -Body "client_id=$appid&scope=https://graph.microsoft.com/.default+offline_access+openid+profile&code=$($request.query.code)&grant_type=authorization_code&redirect_uri=$($url)&client_secret=$clientsecret" -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" + Write-Host "client_id=$appid&scope=https://graph.microsoft.com/.default+offline_access+openid+profile&code=$($Request.Query.code)&grant_type=authorization_code&redirect_uri=$($url)&client_secret=$clientsecret" -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" + $RefreshToken = Invoke-RestMethod -Method POST -Body "client_id=$appid&scope=https://graph.microsoft.com/.default+offline_access+openid+profile&code=$($Request.Query.code)&grant_type=authorization_code&redirect_uri=$($url)&client_secret=$clientsecret" -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -ContentType 'application/x-www-form-urlencoded' if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $Secret.RefreshToken = $RefreshToken.refresh_token @@ -113,7 +113,7 @@ Function Invoke-ExecSAMSetup { $Results = "Authentication failed. $($_.Exception.message)" } } - if ($request.query.CreateSAM) { + if ($Request.Query.CreateSAM) { $Rows = @{ RowKey = 'setup' PartitionKey = 'setup' @@ -126,7 +126,7 @@ Function Invoke-ExecSAMSetup { Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) - if ($Request.query.partnersetup) { + if ($Request.Query.partnersetup) { $SetupPhase = $Rows.partnersetup = $true Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null } @@ -136,46 +136,46 @@ Function Invoke-ExecSAMSetup { Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null $Results = @{ message = "Your code is $($DeviceLogon.user_code). Enter the code" ; step = $step; url = $DeviceLogon.verification_uri } } - if ($Request.query.CheckSetupProcess -and $request.query.step -eq 1) { + if ($Request.Query.CheckSetupProcess -and $Request.Query.step -eq 1) { $SAMSetup = $Rows.SamSetup | ConvertFrom-Json -ErrorAction SilentlyContinue $Token = (New-DeviceLogin -clientid '1b730954-1685-4b74-9bfd-dac224a7b894' -Scope 'https://graph.microsoft.com/.default' -device_code $SAMSetup.device_code) - if ($token.Access_Token) { + if ($Token.access_token) { $step = 2 $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 $PartnerSetup = $Rows.partnersetup - $TenantId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/organization' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method GET -ContentType 'application/json').value.id + $TenantId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/organization' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method GET -ContentType 'application/json').value.id $SetupPhase = $rows.tenantid = [string]($TenantId) Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null if ($PartnerSetup) { $app = Get-Content '.\Cache_SAMSetup\SAMManifest.json' | ConvertFrom-Json $App.web.redirectUris = @($App.web.redirectUris + $URL) $app = $app | ConvertTo-Json -Depth 15 - $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body $app -ContentType 'application/json') + $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body $app -ContentType 'application/json') $rows.appid = [string]($AppId.appId) Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null $attempt = 0 do { try { try { - $SPNDefender = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"fc780465-2017-40d4-a0c5-307022471b92`" }" -ContentType 'application/json') + $SPNDefender = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"fc780465-2017-40d4-a0c5-307022471b92`" }" -ContentType 'application/json') } catch { Write-Host "didn't deploy spn for defender, probably already there." } try { - $SPNTeams = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"48ac35b8-9aa8-4d74-927d-1f4a14a0b239`" }" -ContentType 'application/json') + $SPNTeams = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"48ac35b8-9aa8-4d74-927d-1f4a14a0b239`" }" -ContentType 'application/json') } catch { Write-Host "didn't deploy spn for Teams, probably already there." } try { - $SPNPartnerCenter = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd`" }" -ContentType 'application/json') + $SPNPartnerCenter = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd`" }" -ContentType 'application/json') } catch { Write-Host "didn't deploy spn for PartnerCenter, probably already there." } - $SPN = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"appId`": `"$($AppId.appId)`" }" -ContentType 'application/json') + $SPN = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"$($AppId.appId)`" }" -ContentType 'application/json') Start-Sleep 3 - $GroupID = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(displayName,'AdminAgents')" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method Get -ContentType 'application/json').value.id + $GroupID = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(displayName,'AdminAgents')" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method Get -ContentType 'application/json').value.id Write-Host "Id is $GroupID" - $AddingToAdminAgent = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups/$($GroupID)/members/`$ref" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body "{ `"@odata.id`": `"https://graph.microsoft.com/v1.0/directoryObjects/$($SPN.id)`"}" -ContentType 'application/json') + $AddingToAdminAgent = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups/$($GroupID)/members/`$ref" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"@odata.id`": `"https://graph.microsoft.com/v1.0/directoryObjects/$($SPN.id)`"}" -ContentType 'application/json') Write-Host 'Added to adminagents' $attempt ++ } catch { @@ -184,21 +184,22 @@ Function Invoke-ExecSAMSetup { } until ($attempt -gt 5) } else { $app = Get-Content '.\Cache_SAMSetup\SAMManifestNoPartner.json' - $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body $app -ContentType 'application/json') - $rows.appid = [string]($AppId.appId) + $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body $app -ContentType 'application/json') + $Rows.appid = [string]($AppId.appId) Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null } - $AppPassword = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppID.id)/addPassword" -Headers @{ authorization = "Bearer $($Token.Access_Token)" } -Method POST -Body '{"passwordCredential":{"displayName":"CIPPInstall"}}' -ContentType 'application/json').secretText + $AppPassword = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppId.id)/addPassword" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body '{"passwordCredential":{"displayName":"CIPPInstall"}}' -ContentType 'application/json').secretText if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { - $Secret.TenantId = $Request.body.tenantid - $Secret.ApplicationId = $Request.body.ApplicationId - $Secret.ApplicationSecret = $Request.body.ApplicationSecret + $Secret.TenantId = $TenantId + $Secret.ApplicationId = $AppId.appId + $Secret.ApplicationSecret = $AppPassword Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force + Write-Information ($Secret | ConvertTo-Json -Depth 5) } else { Set-AzKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) - Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appid -AsPlainText -Force) + Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) Set-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) } $Results = @{'message' = 'Created application. Waiting 30 seconds for Azure propagation'; step = $step } @@ -208,7 +209,7 @@ Function Invoke-ExecSAMSetup { } } - switch ($request.query.step) { + switch ($Request.Query.step) { 2 { $step = 2 $TenantId = $Rows.tenantid From 7511ce119ec5a3111c88feea77abf22feca29a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 12 Jun 2024 22:40:28 +0200 Subject: [PATCH 20/91] Formatting and add input validation to most standards --- .../Public/Invoke-RemoveSpamfilter.ps1 | 4 +- .../Public/Invoke-RemoveTransportRule.ps1 | 2 +- .../Public/Standards/Get-CIPPStandards.ps1 | 2 +- ...nvoke-CIPPStandardActivityBasedTimeout.ps1 | 19 +- .../Invoke-CIPPStandardAntiPhishPolicy.ps1 | 8 +- .../Invoke-CIPPStandardAtpPolicyForO365.ps1 | 2 +- .../Standards/Invoke-CIPPStandardAuditLog.ps1 | 2 +- .../Invoke-CIPPStandardAutoExpandArchive.ps1 | 2 +- .../Standards/Invoke-CIPPStandardBookings.ps1 | 2 +- .../Standards/Invoke-CIPPStandardBranding.ps1 | 26 +- .../Invoke-CIPPStandardCloudMessageRecall.ps1 | 2 +- .../Invoke-CIPPStandardConditionalAccess.ps1 | 32 +-- .../Invoke-CIPPStandardDelegateSentItems.ps1 | 8 +- ...voke-CIPPStandardDeletedUserRentention.ps1 | 2 +- ...ndardDisableAdditionalStorageProviders.ps1 | 2 +- ...nvoke-CIPPStandardDisableBasicAuthSMTP.ps1 | 4 +- ...StandardDisableExternalCalendarSharing.ps1 | 2 +- ...nvoke-CIPPStandardDisableOutlookAddins.ps1 | 4 +- ...CIPPStandardDisableSelfServiceLicenses.ps1 | 2 +- ...nvoke-CIPPStandardDisableSharedMailbox.ps1 | 1 + .../Invoke-CIPPStandardDisableTNEF.ps1 | 2 +- ...voke-CIPPStandardDisableUserSiteCreate.ps1 | 2 +- .../Invoke-CIPPStandardDisableViva.ps1 | 4 +- .../Invoke-CIPPStandardEnableMailTips.ps1 | 2 +- ...voke-CIPPStandardEnableMailboxAuditing.ps1 | 2 +- .../Invoke-CIPPStandardEnablePronouns.ps1 | 9 +- .../Invoke-CIPPStandardExConnector.ps1 | 48 ++-- .../Invoke-CIPPStandardExternalMFATrusted.ps1 | 8 +- .../Invoke-CIPPStandardFocusedInbox.ps1 | 8 +- ...PStandardGlobalQuarantineNotifications.ps1 | 6 +- .../Invoke-CIPPStandardGroupTemplate.ps1 | 110 ++++----- .../Invoke-CIPPStandardIntuneTemplate.ps1 | 222 +++++++++--------- .../Invoke-CIPPStandardMailContacts.ps1 | 1 - ...Invoke-CIPPStandardMalwareFilterPolicy.ps1 | 2 +- .../Standards/Invoke-CIPPStandardNudgeMFA.ps1 | 13 + .../Invoke-CIPPStandardOauthConsent.ps1 | 2 +- ...CIPPStandardPWcompanionAppAllowedState.ps1 | 7 + ...rdPWdisplayAppInformationRequiredState.ps1 | 2 +- ...oke-CIPPStandardPasswordExpireDisabled.ps1 | 2 +- .../Standards/Invoke-CIPPStandardSSPR.ps1 | 6 +- ...nvoke-CIPPStandardSafeAttachmentPolicy.ps1 | 12 +- .../Invoke-CIPPStandardSafeLinksPolicy.ps1 | 10 +- .../Invoke-CIPPStandardSecurityDefaults.ps1 | 1 + ...oke-CIPPStandardSendReceiveLimitTenant.ps1 | 14 ++ .../Invoke-CIPPStandardSpoofWarn.ps1 | 8 + .../Standards/Invoke-CIPPStandardTAP.ps1 | 7 + ...oke-CIPPStandardTeamsMeetingsByDefault.ps1 | 2 +- ...voke-CIPPStandardTenantDefaultTimezone.ps1 | 7 + ...voke-CIPPStandardTransportRuleTemplate.ps1 | 53 +++-- .../Invoke-CIPPStandardUserSubmissions.ps1 | 9 +- .../Invoke-CIPPStandardallowOAuthTokens.ps1 | 7 + .../Invoke-CIPPStandardallowOTPTokens.ps1 | 2 +- .../Invoke-CIPPStandardcalDefault.ps1 | 6 + .../Invoke-CIPPStandarddisableMacSync.ps1 | 2 +- ...CIPPStandardintuneDeviceRetirementDays.ps1 | 1 + .../Invoke-CIPPStandardsharingCapability.ps1 | 7 + 56 files changed, 412 insertions(+), 322 deletions(-) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 index 55f525aa36f2..d1d0160aaa34 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 @@ -20,9 +20,9 @@ Function Invoke-RemoveSpamfilter { try { $cmdlet = 'Remove-HostedContentFilterRule' - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true + $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true $cmdlet = 'Remove-HostedContentFilterPolicy' - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true + $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true $Result = "Deleted $($Request.query.name)" Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Deleted transport rule $($Request.query.name)" -sev Debug } catch { diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 index 3a86c418314d..aa358ad25202 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 @@ -21,7 +21,7 @@ Function Invoke-RemoveTransportRule { try { $cmdlet = 'Remove-TransportRule' - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true + $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true $Result = "Deleted $($Request.query.guid)" Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug } catch { diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 6e941c7608cd..13c3aa29b47b 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -86,4 +86,4 @@ function Get-CIPPStandards { } } } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 index 29d1862ecb01..e0c0ff5031a7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 @@ -4,15 +4,16 @@ function Invoke-CIPPStandardActivityBasedTimeout { Internal #> param($Tenant, $Settings) - - if ($Settings.timeout -eq 'Select a value') { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'No value selected for Activity Based Timeout' -sev Error + + # Input validation + if ([string]::isNullOrEmpty($Settings.timeout) -or $Settings.timeout -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'ActivityBasedTimeout: Invalid timeout parameter set' -sev Error Exit } - + # Backwards compatibility for v5.7.0 and older if ($null -eq $Settings.timeout ) { $Settings.timeout = '01:00:00' } - + $State = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' -tenantid $tenant $StateIsCorrect = $State.definition -like "*$($Settings.timeout)*" @@ -29,11 +30,11 @@ function Invoke-CIPPStandardActivityBasedTimeout { $body = ConvertTo-Json -InputObject $PolicyTemplate -Depth 10 -Compress # Switch between parameter sets if the policy already exists - if ($null -eq $State.id) { - $RequestType = 'POST' + if ($null -eq $State.id) { + $RequestType = 'POST' $URI = 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' - } else { - $RequestType = 'PATCH' + } else { + $RequestType = 'PATCH' $URI = "https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies/$($State.id)" } New-GraphPostRequest -tenantid $tenant -Uri $URI -Type $RequestType -Body $body -ContentType 'application/json' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index 1eeb304a0768..17eed3cd2d53 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -34,7 +34,7 @@ function Invoke-CIPPStandardAntiPhishPolicy { $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishRule' | Where-Object -Property Name -EQ "CIPP $PolicyName" | Select-Object Name, AntiPhishPolicy, Priority, RecipientDomainIs - + $RuleStateIsCorrect = ($RuleState.Name -eq "CIPP $PolicyName") -and ($RuleState.AntiPhishPolicy -eq $PolicyName) -and ($RuleState.Priority -eq 0) -and @@ -81,9 +81,9 @@ function Invoke-CIPPStandardAntiPhishPolicy { if ($RuleStateIsCorrect -eq $false) { $cmdparams = @{ - AntiPhishPolicy = $PolicyName - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name + AntiPhishPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name } try { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 index e969b5ae062d..1312fdb6089a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 @@ -47,4 +47,4 @@ function Invoke-CIPPStandardAtpPolicyForO365 { Add-CIPPBPAField -FieldName 'AtpPolicyForO365' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 index fb68e60d11c7..acb6bf9834a1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardAuditLog { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Unified Audit Log is not enabled' -sev Alert } } - + if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'AuditLog' -FieldValue $AuditLogEnabled -StoreAs bool -Tenant $tenant diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 index 1763b0f83171..53d29e442822 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardAutoExpandArchive { If ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' - + if ($CurrentState) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Auto Expanding Archive is already enabled.' -sev Info } else { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 index 24d4a7c0ee3b..4ba2c72e57cc 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -45,4 +45,4 @@ function Invoke-CIPPStandardBookings { Add-CIPPBPAField -FieldName 'BookingsState' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 index 0fa6ed4b3813..2f3841588d28 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 @@ -14,7 +14,7 @@ function Invoke-CIPPStandardBranding { Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the branding for $Tenant. This tenant might not have premium licenses available: $ErrorMessage" -Sev Error } - $StateIsCorrect = ($CurrentState.signInPageText -eq $Settings.signInPageText) -and + $StateIsCorrect = ($CurrentState.signInPageText -eq $Settings.signInPageText) -and ($CurrentState.usernameHintText -eq $Settings.usernameHintText) -and ($CurrentState.loginPageTextVisibilitySettings.hideAccountResetCredentials -eq $Settings.hideAccountResetCredentials) -and ($CurrentState.loginPageLayoutConfiguration.layoutTemplateType -eq $Settings.layoutTemplateType) -and @@ -23,30 +23,30 @@ function Invoke-CIPPStandardBranding { If ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Branding is already applied correctly." -Sev Info + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Branding is already applied correctly.' -Sev Info } else { try { $GraphRequest = @{ - tenantID = $Tenant - uri = "https://graph.microsoft.com/beta/organization/$($TenantId.customerId)/branding/localizations/0" - AsApp = $true - Type = 'PATCH' + tenantID = $Tenant + uri = "https://graph.microsoft.com/beta/organization/$($TenantId.customerId)/branding/localizations/0" + AsApp = $true + Type = 'PATCH' ContentType = 'application/json; charset=utf-8' - Body = [pscustomobject]@{ - signInPageText = $Settings.signInPageText - usernameHintText = $Settings.usernameHintText + Body = [pscustomobject]@{ + signInPageText = $Settings.signInPageText + usernameHintText = $Settings.usernameHintText loginPageTextVisibilitySettings = [pscustomobject]@{ hideAccountResetCredentials = $Settings.hideAccountResetCredentials } - loginPageLayoutConfiguration = [pscustomobject]@{ + loginPageLayoutConfiguration = [pscustomobject]@{ layoutTemplateType = $Settings.layoutTemplateType - isHeaderShown = $Settings.isHeaderShown - isFooterShown = $Settings.isFooterShown + isHeaderShown = $Settings.isHeaderShown + isFooterShown = $Settings.isFooterShown } } | ConvertTo-Json -Compress } New-GraphPostRequest @GraphRequest - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Successfully updated branding." -Sev Info + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully updated branding.' -Sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update branding. Error: $($ErrorMessage)" -Sev Error diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 index 4994b6cf91c1..b09f91554f3b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -45,4 +45,4 @@ function Invoke-CIPPStandardCloudMessageRecall { Add-CIPPBPAField -FieldName 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 index 4e7a3b0b34e0..c3c047f35421 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 @@ -1,26 +1,26 @@ function Invoke-CIPPStandardConditionalAccess { - <# + <# .FUNCTIONALITY Internal #> - param($Tenant, $Settings) - If ($Settings.remediate -eq $true) { + param($Tenant, $Settings) + If ($Settings.remediate -eq $true) { - $APINAME = 'Standards' + $APINAME = 'Standards' - foreach ($Template in $Settings.TemplateList) { - try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$($Template.value)'" - $JSONObj = (Get-AzDataTableEntity @Table -Filter $Filter).JSON - $CAPolicy = New-CIPPCAPolicy -TenantFilter $tenant -state $request.body.NewState -RawJSON $JSONObj -Overwrite $true -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' -ReplacePattern 'displayName' - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName). Error: $ErrorMessage" -sev 'Error' - } - } + foreach ($Template in $Settings.TemplateList) { + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$($Template.value)'" + $JSONObj = (Get-AzDataTableEntity @Table -Filter $Filter).JSON + $null = New-CIPPCAPolicy -TenantFilter $tenant -state $request.body.NewState -RawJSON $JSONObj -Overwrite $true -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' -ReplacePattern 'displayName' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName). Error: $ErrorMessage" -sev 'Error' + } + } - } + } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 index b8ee94aafe9b..81cbdc6e5167 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 @@ -4,7 +4,7 @@ function Invoke-CIPPStandardDelegateSentItems { Internal #> param($Tenant, $Settings) - $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{ RecipientTypeDetails = @('UserMailbox', 'SharedMailbox') } | + $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{ RecipientTypeDetails = @('UserMailbox', 'SharedMailbox') } | Where-Object { $_.MessageCopyForSendOnBehalfEnabled -eq $false -or $_.MessageCopyForSentAsEnabled -eq $false } Write-Host "Mailboxes: $($Mailboxes.count)" If ($Settings.remediate -eq $true) { @@ -39,10 +39,10 @@ function Invoke-CIPPStandardDelegateSentItems { } } if ($Settings.alert -eq $true) { - if ($Mailboxes) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Delegate Sent Items Style is not enabled for $($Mailboxes.count) mailboxes" -sev Alert + if ($null -eq $Mailboxes) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Delegate Sent Items Style is enabled for all mailboxes' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Delegate Sent Items Style is enabled' -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Delegate Sent Items Style is not enabled for $($Mailboxes.count) mailboxes" -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 index 902e545d8a30..157bf5fbf690 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 @@ -9,7 +9,7 @@ function Invoke-CIPPStandardDeletedUserRentention { If ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' - + if ($StateSetCorrectly -eq $false) { try { $body = '{"deletedUserPersonalSiteRetentionPeriodInDays": 365}' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 index c6bbb8932cb7..6612d7090240 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 @@ -34,4 +34,4 @@ function Invoke-CIPPStandardDisableAdditionalStorageProviders { if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'AdditionalStorageProvidersEnabled' -FieldValue $AdditionalStorageProvidersState.AdditionalStorageProvidersEnabled -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 index edcba0f5ff1b..ed8a7b256ff7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 @@ -57,9 +57,9 @@ function Invoke-CIPPStandardDisableBasicAuthSMTP { Write-LogMessage -API 'Standards' -tenant $tenant -message $LogMessage -sev Alert } } - + if ($Settings.report -eq $true) { - + if ($CurrentInfo.SmtpClientAuthenticationDisabled -and $SMTPusers.Count -eq 0) { Add-CIPPBPAField -FieldName 'DisableBasicAuthSMTP' -FieldValue $CurrentInfo.SmtpClientAuthenticationDisabled -StoreAs bool -Tenant $tenant } else { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 index 85d66408b501..2393e7c3994d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 @@ -36,4 +36,4 @@ function Invoke-CIPPStandardDisableExternalCalendarSharing { $CurrentInfo.Enabled = -not $CurrentInfo.Enabled Add-CIPPBPAField -FieldName 'ExternalCalendarSharingDisabled' -FieldValue $CurrentInfo.Enabled -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 index 63da951024d9..230920781a6a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 @@ -49,7 +49,7 @@ function Invoke-CIPPStandardDisableOutlookAddins { } } if ($Settings.report -eq $true) { - if ($RolesToRemove) { $State = $false } else { $State = $true } + $State = if ($RolesToRemove) { $false } else { $true } Add-CIPPBPAField -FieldName 'DisabledOutlookAddins' -FieldValue $State -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 index c90b55962a58..6431f6053dc5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 @@ -3,7 +3,7 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { .FUNCTIONALITY Internal #> - param($Tenant, $Settings) + param($Tenant, $Settings) Write-LogMessage -API 'Standards' -tenant $tenant -message 'Self Service Licenses cannot be disabled' -sev Error diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 index 96ac8e55a51b..31955cc04c72 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 @@ -7,6 +7,7 @@ function Invoke-CIPPStandardDisableSharedMailbox { $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($Tenant)/Mailbox?`$filter=ExchangeUserAccountControl ne 'accountdisabled'" -Tenantid $tenant -scope ExchangeOnline | Where-Object { $_.RecipientTypeDetails -EQ 'SharedMailbox' -or $_.RecipientTypeDetails -eq 'SchedulingMailbox' }) If ($Settings.remediate -eq $true) { + if ($SharedMailboxList) { $SharedMailboxList | ForEach-Object { try { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 index edf707f9fc76..022f21807864 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 @@ -36,4 +36,4 @@ function Invoke-CIPPStandardDisableTNEF { Add-CIPPBPAField -FieldName 'TNEFDisabled' -FieldValue $State -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 index 46a01eb94b90..97bac09d7668 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 @@ -35,4 +35,4 @@ function Invoke-CIPPStandardDisableUserSiteCreate { if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'DisableUserSiteCreate' -FieldValue $CurrentInfo.isSiteCreationEnabled -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 index fe61f3fb3968..0b790cfd9581 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 @@ -12,10 +12,10 @@ function Invoke-CIPPStandardDisableViva { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to get Viva insights settings. Error: $ErrorMessage" -sev Error Exit } - + If ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' - + if ($CurrentSetting.isEnabledInOrganization -eq $false) { Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Viva is already disabled.' -sev Info } else { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 index 05ab9cfbd117..52d3e3294c18 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 @@ -37,4 +37,4 @@ function Invoke-CIPPStandardEnableMailTips { Add-CIPPBPAField -FieldName 'MailTipsEnabled' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 index 9181ae888e66..2374206fc6d0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 @@ -90,4 +90,4 @@ function Invoke-CIPPStandardEnableMailboxAuditing { Add-CIPPBPAField -FieldName 'MailboxAuditingEnabled' -FieldValue $AuditState -StoreAs bool -Tenant $Tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 index 56d5c8a1815e..873d52976ff7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 @@ -34,19 +34,16 @@ function Invoke-CIPPStandardEnablePronouns { } if ($Settings.alert -eq $true) { - + if ($CurrentState.isEnabledInOrganization -eq $true) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Pronouns are enabled.' -sev Info } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Pronouns are not enabled.' -sev Alert } - } if ($Settings.report -eq $true) { - + Add-CIPPBPAField -FieldName 'PronounsEnabled' -FieldValue $CurrentState.isEnabledInOrganization -StoreAs bool -Tenant $tenant - } - -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExConnector.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExConnector.ps1 index 275cda358879..84a3258ad940 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExConnector.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExConnector.ps1 @@ -1,35 +1,35 @@ function Invoke-CIPPStandardExConnector { - <# + <# .FUNCTIONALITY Internal #> - param($Tenant, $Settings) - If ($Settings.remediate -eq $true) { + param($Tenant, $Settings) + If ($Settings.remediate -eq $true) { + + $APINAME = 'Standards' + foreach ($Template in $Settings.TemplateList) { + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'ExConnectorTemplate' and RowKey eq '$($Template.value)'" + $connectorType = (Get-AzDataTableEntity @Table -Filter $Filter).direction + $RequestParams = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json + $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $Tenant -cmdlet "Get-$($ConnectorType)connector" | Where-Object -Property Identity -EQ $RequestParams.name + if ($Existing) { + $RequestParams | Add-Member -NotePropertyValue $Existing.Identity -NotePropertyName Identity -Force + $null = New-ExoRequest -tenantid $Tenant -cmdlet "Set-$($ConnectorType)connector" -cmdParams $RequestParams -useSystemMailbox $true + Write-LogMessage -API $APINAME -tenant $Tenant -message "Updated transport rule for $($Tenant, $Settings)" -sev info + } else { + $null = New-ExoRequest -tenantid $Tenant -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams -useSystemMailbox $true + Write-LogMessage -API $APINAME -tenant $Tenant -message "Created transport rule for $($Tenant, $Settings)" -sev info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Exchange Connector Rule: $ErrorMessage" -sev 'Error' + } - $APINAME = 'Standards' - foreach ($Template in $Settings.TemplateList) { - try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'ExConnectorTemplate' and RowKey eq '$($Template.value)'" - $connectorType = (Get-AzDataTableEntity @Table -Filter $Filter).direction - $RequestParams = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json - $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $Tenant -cmdlet "Get-$($ConnectorType)connector" | Where-Object -Property Identity -EQ $RequestParams.name - if ($Existing) { - $RequestParams | Add-Member -NotePropertyValue $Existing.Identity -NotePropertyName Identity -Force - $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet "Set-$($ConnectorType)connector" -cmdParams $RequestParams -useSystemMailbox $true - Write-LogMessage -API $APINAME -tenant $Tenant -message "Updated transport rule for $($Tenant, $Settings)" -sev info - } else { - $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams -useSystemMailbox $true - Write-LogMessage -API $APINAME -tenant $Tenant -message "Created transport rule for $($Tenant, $Settings)" -sev info } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Exchange Connector Rule: $ErrorMessage" -sev 'Error' - } } - } - } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 index 56b2338a6b8c..2ae91ffae326 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 @@ -5,6 +5,12 @@ function Invoke-CIPPStandardExternalMFATrusted { #> param($Tenant, $Settings) + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error + Exit + } + $ExternalMFATrusted = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default?$select=inboundTrust' -tenantid $Tenant) $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } $StateMessage = if ($WantedState) { 'enabled' } else { 'disabled' } @@ -42,4 +48,4 @@ function Invoke-CIPPStandardExternalMFATrusted { Add-CIPPBPAField -FieldName 'ExternalMFATrusted' -FieldValue $ExternalMFATrusted.inboundTrust.isMfaAccepted -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index 0da2ddbedc03..b14040073120 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 @@ -5,9 +5,9 @@ function Invoke-CIPPStandardFocusedInbox { #> param($Tenant, $Settings) - # Exit if the wanted state is not valid - if ($Settings.state -ne 'enabled' -and $Settings.state -ne 'disabled') { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Invalid state for Focused Inbox. Please select either "enabled" or "disabled".' -sev Error + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error Exit } @@ -44,4 +44,4 @@ function Invoke-CIPPStandardFocusedInbox { if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'FocusedInboxCorrectState' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 index 3f8d24cf35b8..4d2bb6e9b039 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-QuarantinePolicy' -cmdParams @{ QuarantinePolicyType = 'GlobalQuarantinePolicy' } - # This might take the cake on ugly hacky stuff i've done, + # This might take the cake on ugly hacky stuff i've done, # but i just cant understand why the API returns the values it does and not a timespan like the equivalent powershell command does # If you know why, please let me know -Bobby $CurrentState.EndUserSpamNotificationFrequency = switch ($CurrentState.EndUserSpamNotificationFrequency) { @@ -43,7 +43,7 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { } if ($Settings.alert -eq $true) { - + if ($CurrentState.EndUserSpamNotificationFrequency -eq $WantedState) { Write-LogMessage -API 'Standards' -tenant $tenant -message "Global Quarantine Notifications are set to the desired value of $WantedState" -sev Info } else { @@ -55,4 +55,4 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { Add-CIPPBPAField -FieldName 'GlobalQuarantineNotificationsSet' -FieldValue [string]$CurrentState.EndUserSpamNotificationFrequency -StoreAs string -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 index 0249bc747b42..4c1aeeebc2de 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 @@ -1,68 +1,68 @@ function Invoke-CIPPStandardGroupTemplate { - <# + <# .FUNCTIONALITY Internal #> - param($Tenant, $Settings) - If ($Settings.remediate -eq $true) { + param($Tenant, $Settings) + If ($Settings.remediate -eq $true) { - foreach ($Template in $Settings.TemplateList) { - try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'GroupTemplate' and RowKey eq '$($Template.value)'" - $groupobj = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json - $email = if ($groupobj.domain) { "$($groupobj.username)@$($groupobj.domain)" } else { "$($groupobj.username)@$($Tenant)" } - $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenant | Where-Object -Property displayName -EQ $groupobj.displayname - if (!$CheckExististing) { - if ($groupobj.groupType -in 'Generic', 'azurerole', 'dynamic') { + foreach ($Template in $Settings.TemplateList) { + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'GroupTemplate' and RowKey eq '$($Template.value)'" + $groupobj = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json + $email = if ($groupobj.domain) { "$($groupobj.username)@$($groupobj.domain)" } else { "$($groupobj.username)@$($Tenant)" } + $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenant | Where-Object -Property displayName -EQ $groupobj.displayname + if (!$CheckExististing) { + if ($groupobj.groupType -in 'Generic', 'azurerole', 'dynamic') { - $BodyToship = [pscustomobject] @{ - 'displayName' = $groupobj.Displayname - 'description' = $groupobj.Description - 'mailNickname' = $groupobj.username - mailEnabled = [bool]$false - securityEnabled = [bool]$true - isAssignableToRole = [bool]($groupobj | Where-Object -Property groupType -EQ 'AzureRole') + $BodyToship = [pscustomobject] @{ + 'displayName' = $groupobj.Displayname + 'description' = $groupobj.Description + 'mailNickname' = $groupobj.username + mailEnabled = [bool]$false + securityEnabled = [bool]$true + isAssignableToRole = [bool]($groupobj | Where-Object -Property groupType -EQ 'AzureRole') - } - if ($groupobj.membershipRules) { - $BodyToship | Add-Member -NotePropertyName 'membershipRule' -NotePropertyValue ($groupobj.membershipRules) - $BodyToship | Add-Member -NotePropertyName 'groupTypes' -NotePropertyValue @('DynamicMembership') - $BodyToship | Add-Member -NotePropertyName 'membershipRuleProcessingState' -NotePropertyValue 'On' - } - $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenant -type POST -body (ConvertTo-Json -InputObject $BodyToship -Depth 10) -verbose - } else { - if ($groupobj.groupType -eq 'dynamicdistribution') { - $Params = @{ - Name = $groupobj.Displayname - RecipientFilter = $groupobj.membershipRules - PrimarySmtpAddress = $email - } - $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DynamicDistributionGroup' -cmdParams $params - } else { - $Params = @{ - Name = $groupobj.Displayname - Alias = $groupobj.username - Description = $groupobj.Description - PrimarySmtpAddress = $email - Type = $groupobj.groupType - RequireSenderAuthenticationEnabled = [bool]!$groupobj.AllowExternal - } - $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params - } - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Standards' -tenant $tenant -message "Created group $($groupobj.displayname) with id $($GraphRequest.id) " -Sev 'Info' + } + if ($groupobj.membershipRules) { + $BodyToship | Add-Member -NotePropertyName 'membershipRule' -NotePropertyValue ($groupobj.membershipRules) + $BodyToship | Add-Member -NotePropertyName 'groupTypes' -NotePropertyValue @('DynamicMembership') + $BodyToship | Add-Member -NotePropertyName 'membershipRuleProcessingState' -NotePropertyValue 'On' + } + $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenant -type POST -body (ConvertTo-Json -InputObject $BodyToship -Depth 10) -verbose + } else { + if ($groupobj.groupType -eq 'dynamicdistribution') { + $Params = @{ + Name = $groupobj.Displayname + RecipientFilter = $groupobj.membershipRules + PrimarySmtpAddress = $email + } + $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DynamicDistributionGroup' -cmdParams $params + } else { + $Params = @{ + Name = $groupobj.Displayname + Alias = $groupobj.username + Description = $groupobj.Description + PrimarySmtpAddress = $email + Type = $groupobj.groupType + RequireSenderAuthenticationEnabled = [bool]!$groupobj.AllowExternal + } + $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params + } + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Standards' -tenant $tenant -message "Created group $($groupobj.displayname) with id $($GraphRequest.id) " -Sev 'Info' - } else { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Standards' -tenant $tenant -message "Group exists $($groupobj.displayname). Did not create" -Sev 'Info' + } else { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Standards' -tenant $tenant -message "Group exists $($groupobj.displayname). Did not create" -Sev 'Info' + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create group: $ErrorMessage" -sev 'Error' + } } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create group: $ErrorMessage" -sev 'Error' - } - } - } + } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index 9263b386bb23..66f253ef721c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -1,129 +1,129 @@ function Invoke-CIPPStandardIntuneTemplate { - <# + <# .FUNCTIONALITY Internal #> - param($Tenant, $Settings) - If ($Settings.remediate -eq $true) { + param($Tenant, $Settings) + If ($Settings.remediate -eq $true) { - Write-Host 'starting template deploy' - $APINAME = 'Standards' - foreach ($Template in $Settings.TemplateList) { - Write-Host 'working on template deploy' - try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'IntuneTemplate'" - $Request = @{body = $null } - $Request.body = (Get-AzDataTableEntity @Table -Filter $Filter | Where-Object -Property RowKey -Like "$($template.value)*").JSON | ConvertFrom-Json - $displayname = $request.body.Displayname - $description = $request.body.Description - $RawJSON = $Request.body.RawJSON + Write-Host 'starting template deploy' + $APINAME = 'Standards' + foreach ($Template in $Settings.TemplateList) { + Write-Host 'working on template deploy' + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'IntuneTemplate'" + $Request = @{body = $null } + $Request.body = (Get-AzDataTableEntity @Table -Filter $Filter | Where-Object -Property RowKey -Like "$($template.value)*").JSON | ConvertFrom-Json + $displayname = $request.body.Displayname + $description = $request.body.Description + $RawJSON = $Request.body.RawJSON - switch ($Request.body.Type) { - 'AppProtection' { - $TemplateType = ($RawJSON | ConvertFrom-Json).'@odata.type' -replace '#microsoft.graph.', '' - $TemplateTypeURL = "$($TemplateType)s" - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenant - if ($displayname -in $CheckExististing.displayName) { - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PATCH -body $RawJSON - } else { - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON - } - } - 'deviceCompliancePolicies' { - $TemplateTypeURL = 'deviceCompliancePolicies' - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant + switch ($Request.body.Type) { + 'AppProtection' { + $TemplateType = ($RawJSON | ConvertFrom-Json).'@odata.type' -replace '#microsoft.graph.', '' + $TemplateTypeURL = "$($TemplateType)s" + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenant + if ($displayname -in $CheckExististing.displayName) { + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PATCH -body $RawJSON + } else { + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON + } + } + 'deviceCompliancePolicies' { + $TemplateTypeURL = 'deviceCompliancePolicies' + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant - $JSON = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty id, createdDateTime, lastModifiedDateTime, version, 'scheduledActionsForRule@odata.context', '@odata.context' - $JSON.scheduledActionsForRule = @($JSON.scheduledActionsForRule | Select-Object * -ExcludeProperty 'scheduledActionConfigurations@odata.context') - $RawJSON = ConvertTo-Json -InputObject $JSON -Depth 20 -Compress - Write-Host $RawJSON - if ($displayname -in $CheckExististing.displayName) { - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PATCH -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated policy $($PolicyName) to template defaults" -Sev 'info' - } else { - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' - } - } - 'Admin' { - $TemplateTypeURL = 'groupPolicyConfigurations' - $CreateBody = '{"description":"' + $description + '","displayName":"' + $displayname + '","roleScopeTagIds":["0"]}' - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant - if ($displayname -in $CheckExististing.displayName) { - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname - $ExistingData = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/definitionValues" -tenantid $tenant - $DeleteJson = $RawJSON | ConvertFrom-Json -Depth 10 - $DeleteJson.deletedIds = @($ExistingData.id) - $DeleteJson.added = @() - $DeleteJson = ConvertTo-Json -Depth 10 -InputObject $DeleteJson - $DeleteRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $DeleteJson - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated policy $($Displayname) to template defaults" -Sev 'info' + $JSON = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty id, createdDateTime, lastModifiedDateTime, version, 'scheduledActionsForRule@odata.context', '@odata.context' + $JSON.scheduledActionsForRule = @($JSON.scheduledActionsForRule | Select-Object * -ExcludeProperty 'scheduledActionConfigurations@odata.context') + $RawJSON = ConvertTo-Json -InputObject $JSON -Depth 20 -Compress + Write-Host $RawJSON + if ($displayname -in $CheckExististing.displayName) { + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PATCH -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated policy $($PolicyName) to template defaults" -Sev 'info' + } else { + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' + } + } + 'Admin' { + $TemplateTypeURL = 'groupPolicyConfigurations' + $CreateBody = '{"description":"' + $description + '","displayName":"' + $displayname + '","roleScopeTagIds":["0"]}' + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant + if ($displayname -in $CheckExististing.displayName) { + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname + $ExistingData = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/definitionValues" -tenantid $tenant + $DeleteJson = $RawJSON | ConvertFrom-Json -Depth 10 + $DeleteJson.deletedIds = @($ExistingData.id) + $DeleteJson.added = @() + $DeleteJson = ConvertTo-Json -Depth 10 -InputObject $DeleteJson + $DeleteRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $DeleteJson + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated policy $($Displayname) to template defaults" -Sev 'info' - } else { - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $CreateBody - $UpdateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($CreateRequest.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($Displayname) to template defaults" -Sev 'info' + } else { + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $CreateBody + $UpdateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($CreateRequest.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($Displayname) to template defaults" -Sev 'info' - } - } - 'Device' { - $TemplateTypeURL = 'deviceConfigurations' - $PolicyName = ($RawJSON | ConvertFrom-Json).displayName - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant - if ($PolicyName -in $CheckExististing.displayName) { - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PATCH -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated policy $($PolicyName) to template defaults" -Sev 'info' + } + } + 'Device' { + $TemplateTypeURL = 'deviceConfigurations' + $PolicyName = ($RawJSON | ConvertFrom-Json).displayName + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant + if ($PolicyName -in $CheckExististing.displayName) { + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PATCH -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Updated policy $($PolicyName) to template defaults" -Sev 'info' - } else { - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' + } else { + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' - } - } - 'Catalog' { - $TemplateTypeURL = 'configurationPolicies' - $PolicyName = ($RawJSON | ConvertFrom-Json).Name - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant - if ($PolicyName -in $CheckExististing.name) { - $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $PolicyName - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PUT -body $RawJSON + } + } + 'Catalog' { + $TemplateTypeURL = 'configurationPolicies' + $PolicyName = ($RawJSON | ConvertFrom-Json).Name + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant + if ($PolicyName -in $CheckExististing.name) { + $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $PolicyName + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PUT -body $RawJSON - } else { - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' - } - } - 'windowsDriverUpdateProfiles' { - $TemplateTypeURL = 'windowsDriverUpdateProfiles' - $PolicyName = ($RawJSON | ConvertFrom-Json).Name - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant - if ($PolicyName -in $CheckExististing.name) { - $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $PolicyName - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PUT -body $RawJSON + } else { + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' + } + } + 'windowsDriverUpdateProfiles' { + $TemplateTypeURL = 'windowsDriverUpdateProfiles' + $PolicyName = ($RawJSON | ConvertFrom-Json).Name + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant + if ($PolicyName -in $CheckExististing.name) { + $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $PolicyName + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenant -type PUT -body $RawJSON - } else { - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' - } - } + } else { + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($PolicyName) via template" -Sev 'info' + } + } - } + } - 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 + 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' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template: $ErrorMessage" -sev 'Error' + } } - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully added Intune Template policy for $($Tenant)" -sev 'Info' - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template: $ErrorMessage" -sev 'Error' - } } - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 index 563e76cdc4ff..8cc14082f3a3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 @@ -11,7 +11,6 @@ function Invoke-CIPPStandardMailContacts { If ($Settings.remediate -eq $true) { - # TODO: Make this smaller if possible if ($CurrentInfo.marketingNotificationEmails -eq $Contacts.MarketingContact -and ` ($CurrentInfo.securityComplianceNotificationMails -in $TechAndSecurityContacts -or $CurrentInfo.technicalNotificationMails -in $TechAndSecurityContacts) -and ` diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index d9ae65ac222f..5a3e99aa57ad 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -27,7 +27,7 @@ function Invoke-CIPPStandardMalwareFilterPolicy { $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterRule' | Where-Object -Property Name -EQ "CIPP $PolicyName" | Select-Object Name, MalwareFilterPolicy, Priority, RecipientDomainIs - + $RuleStateIsCorrect = ($RuleState.Name -eq "CIPP $PolicyName") -and ($RuleState.MalwareFilterPolicy -eq $PolicyName) -and ($RuleState.Priority -eq 0) -and diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index e3c7d190e072..2263412053ee 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -4,10 +4,23 @@ function Invoke-CIPPStandardNudgeMFA { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid state parameter set' -sev Error + Exit + } + # Input validation + if ($Settings.snoozeDurationInDays -lt 0 -or $Settings.snoozeDurationInDays -gt 15) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid snoozeDurationInDays parameter set' -sev Error + Exit + } + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $Tenant $State = if ($CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq 'enabled') { $true } else { $false } If ($Settings.remediate -eq $true) { + $StateName = $Settings.state.Substring(0, 1).ToUpper() + $Settings.state.Substring(1) if ($Settings.state -ne $CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -or $Settings.snoozeDurationInDays -ne $CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays) { try { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 index d62e02a3a223..38d2b41dfce3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 @@ -27,7 +27,7 @@ function Invoke-CIPPStandardOauthConsent { } New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -Type PATCH -Body '{"permissionGrantPolicyIdsAssignedToDefaultUserRole":["managePermissionGrantsForSelf.cipp-consent-policy"]}' -ContentType 'application/json' } - + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode has been enabled.' -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 index 22a46a14a2e4..3a2175f65c2d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 @@ -4,6 +4,13 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'PWcompanionAppAllowedState: Invalid state parameter set' -sev Error + Exit + } + $authenticatorFeaturesState = (New-GraphGetRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type GET) $authstate = if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq 'enabled') { $true } else { $false } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 index 5c23a6763f8f..2f85c01bf859 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 @@ -26,4 +26,4 @@ function Invoke-CIPPStandardPWdisplayAppInformationRequiredState { if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'PWdisplayAppInformationRequiredState' -FieldValue $State -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 index 1e0daba708c2..5cf8dac138a1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 @@ -42,4 +42,4 @@ function Invoke-CIPPStandardPasswordExpireDisabled { if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'PasswordExpireDisabled' -FieldValue $DomainswithoutPassExpire -StoreAs json -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSSPR.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSSPR.ps1 index e6fbdd3181f6..ff39c3b17c39 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSSPR.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSSPR.ps1 @@ -1,10 +1,10 @@ function Invoke-CIPPStandardSSPR { - <# + <# .FUNCTIONALITY Internal #> - param($Tenant, $Settings) + param($Tenant, $Settings) - Write-LogMessage -API 'Standards' -tenant $tenant -message 'SSPR standard is no longer available' -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SSPR standard is no longer available' -sev Error } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index 1973cb4efc10..78a49086fbd6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -22,7 +22,7 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | Where-Object -Property Name -EQ "CIPP $PolicyName" | Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs - + $RuleStateIsCorrect = ($RuleState.Name -eq "CIPP $PolicyName") -and ($RuleState.SafeAttachmentPolicy -eq $PolicyName) -and ($RuleState.Priority -eq 0) -and @@ -55,12 +55,12 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Safe Attachment Policy. Error: $ErrorMessage" -sev Error } } - + if ($RuleStateIsCorrect -eq $false) { $cmdparams = @{ - SafeAttachmentPolicy = $PolicyName - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name + SafeAttachmentPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name } try { @@ -93,4 +93,4 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { Add-CIPPBPAField -FieldName 'SafeAttachmentPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 index bd353b32e485..cea984a20a4f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -28,7 +28,7 @@ function Invoke-CIPPStandardSafeLinksPolicy { $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksRule' | Where-Object -Property Name -EQ "CIPP $PolicyName" | Select-Object Name, SafeLinksPolicy, Priority, RecipientDomainIs - + $RuleStateIsCorrect = ($RuleState.Name -eq "CIPP $PolicyName") -and ($RuleState.SafeLinksPolicy -eq $PolicyName) -and ($RuleState.Priority -eq 0) -and @@ -70,9 +70,9 @@ function Invoke-CIPPStandardSafeLinksPolicy { if ($RuleStateIsCorrect -eq $false) { $cmdparams = @{ - SafeLinksPolicy = $PolicyName - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name + SafeLinksPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name } try { @@ -105,4 +105,4 @@ function Invoke-CIPPStandardSafeLinksPolicy { Add-CIPPBPAField -FieldName 'SafeLinksPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 index 10b41322367d..07bc25df5021 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 @@ -7,6 +7,7 @@ function Invoke-CIPPStandardSecurityDefaults { $SecureDefaultsState = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $tenant) If ($Settings.remediate -eq $true) { + if ($SecureDefaultsState.IsEnabled -ne $true) { try { Write-Host "Secure Defaults is disabled. Enabling for $tenant" -ForegroundColor Yellow diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 index ef65fb0b9c56..822471d17466 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 @@ -4,6 +4,20 @@ function Invoke-CIPPStandardSendReceiveLimitTenant { Internal #> param($Tenant, $Settings) + + # Input validation + if ($Settings.SendLimit -lt 1 -or $Settings.SendLimit -gt 150) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SendReceiveLimitTenant: Invalid SendLimit parameter set' -sev Error + Exit + } + + # Input validation + if ($Settings.ReceiveLimit -lt 1 -or $Settings.ReceiveLimit -gt 150) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SendReceiveLimitTenant: Invalid ReceiveLimit parameter set' -sev Error + Exit + } + + $AllMailBoxPlans = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MailboxPlan' | Select-Object DisplayName, MaxSendSize, MaxReceiveSize, GUID $MaxSendSize = [int64]"$($Settings.SendLimit)MB" $MaxReceiveSize = [int64]"$($Settings.ReceiveLimit)MB" diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index 54acd8ffed62..9f10326925af 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 @@ -4,10 +4,18 @@ function Invoke-CIPPStandardSpoofWarn { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SpoofWarn: Invalid state parameter set' -sev Error + Exit + } + $CurrentInfo = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ExternalInOutlook') If ($Settings.remediate -eq $true) { $status = if ($Settings.enable -and $Settings.disable) { + # Handle legacy settings when this was 2 separate standards Write-LogMessage -API 'Standards' -tenant $tenant -message 'You cannot both enable and disable the Spoof Warnings setting' -sev Error Exit } elseif ($Settings.state -eq 'enabled' -or $Settings.enable) { $true } else { $false } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 index 72a851a8154e..c627e055f36b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 @@ -4,6 +4,13 @@ function Invoke-CIPPStandardTAP { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'TAP: Invalid state parameter set' -sev Error + Exit + } + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass' -tenantid $Tenant $State = if ($CurrentInfo.state -eq 'enabled') { $true } else { $false } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 86509c52564b..676db45e78ff 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -45,4 +45,4 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { Add-CIPPBPAField -FieldName 'TeamsMeetingsByDefault' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 index a9bb46c8f53e..e26119fca311 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 @@ -5,6 +5,13 @@ function Invoke-CIPPStandardTenantDefaultTimezone { #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.Timezone) -or $Settings.Timezone -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'TenantDefaultTimezone: Invalid Timezone parameter set' -sev Error + Exit + } + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true $ExpectedTimezone = $Settings.Timezone.value $StateIsCorrect = $CurrentState.tenantDefaultTimezone -eq $ExpectedTimezone diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 index c0c6e0d17db3..ad65a91db297 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 @@ -1,36 +1,37 @@ function Invoke-CIPPStandardTransportRuleTemplate { - <# + <# .FUNCTIONALITY Internal #> - param($Tenant, $Settings) - If ($Settings.remediate -eq $true) { + param($Tenant, $Settings) - foreach ($Template in $Settings.TemplateList) { - Write-Host "working on $($Template.value)" - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'TransportTemplate' and RowKey eq '$($Template.value)'" - $RequestParams = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json - $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $Tenant -cmdlet 'Get-TransportRule' -useSystemMailbox $true | Where-Object -Property Identity -EQ $RequestParams.name + If ($Settings.remediate -eq $true) { + foreach ($Template in $Settings.TemplateList) { + Write-Host "working on $($Template.value)" + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'TransportTemplate' and RowKey eq '$($Template.value)'" + $RequestParams = (Get-AzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json + $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $Tenant -cmdlet 'Get-TransportRule' -useSystemMailbox $true | Where-Object -Property Identity -EQ $RequestParams.name - try { - if ($Existing) { - Write-Host 'Found existing' - $RequestParams | Add-Member -NotePropertyValue $RequestParams.name -NotePropertyName Identity - $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-TransportRule' -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications, UseLegacyRegex) -useSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set transport rule for $tenant" -sev 'Info' - } else { - Write-Host 'Creating new' - $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'New-TransportRule' -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications, UseLegacyRegex) -useSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully created transport rule for $tenant" -sev 'Info' - } - Write-LogMessage -API $APINAME -tenant $Tenant -message "Created transport rule for $($tenantfilter)" -sev 'Debug' - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Could not create transport rule for $($tenantfilter): $ErrorMessage" -sev 'Error' - } + try { + if ($Existing) { + Write-Host 'Found existing' + $RequestParams | Add-Member -NotePropertyValue $RequestParams.name -NotePropertyName Identity + $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-TransportRule' -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications, UseLegacyRegex) -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set transport rule for $tenant" -sev 'Info' + } else { + Write-Host 'Creating new' + $GraphRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'New-TransportRule' -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications, UseLegacyRegex) -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully created transport rule for $tenant" -sev 'Info' + } + + Write-LogMessage -API $APINAME -tenant $Tenant -message "Created transport rule for $($tenantfilter)" -sev 'Debug' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Could not create transport rule for $($tenantfilter): $ErrorMessage" -sev 'Error' + } + } } - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index c4c15c525441..b4e66edb49dd 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -4,6 +4,13 @@ function Invoke-CIPPStandardUserSubmissions { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'UserSubmissions: Invalid state parameter set' -sev Error + Exit + } + $Policy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ReportSubmissionPolicy' If ($Settings.remediate -eq $true) { @@ -64,4 +71,4 @@ function Invoke-CIPPStandardUserSubmissions { Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $Policy.EnableReportToMicrosoft -StoreAs bool -Tenant $tenant } } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 index c8fd2f64b9de..e9498ee706ac 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 @@ -4,6 +4,13 @@ function Invoke-CIPPStandardallowOAuthTokens { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'allowOAuthTokens: Invalid state parameter set' -sev Error + Exit + } + $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/softwareOath' -tenantid $Tenant $State = if ($CurrentInfo.state -eq 'enabled') { $true } else { $false } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 index 6f956358c711..8459fce1aadc 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 @@ -26,4 +26,4 @@ function Invoke-CIPPStandardallowOTPTokens { Add-CIPPBPAField -FieldName 'MSAuthenticator' -FieldValue $CurrentInfo.isSoftwareOathEnabled -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 index 6c94488a32d8..9b6782f5ad30 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 @@ -5,6 +5,12 @@ function Invoke-CIPPStandardcalDefault { #> param($Tenant, $Settings, $QueueItem) + # Input validation + if ([string]::isNullOrEmpty($Settings.permissionlevel) -or $Settings.permissionlevel -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'calDefault: Invalid permissionlevel parameter set' -sev Error + Exit + } + If ($Settings.remediate -eq $true) { $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' | Sort-Object UserPrincipalName $TotalMailboxes = $Mailboxes.Count diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 index 8b1203113522..b096ade25384 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 @@ -35,4 +35,4 @@ function Invoke-CIPPStandarddisableMacSync { $CurrentInfo.isMacSyncAppEnabled = -not $CurrentInfo.isMacSyncAppEnabled Add-CIPPBPAField -FieldName 'MacSync' -FieldValue $CurrentInfo.isMacSyncAppEnabled -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 index 8f5a1dc0ef46..b150c84e2f0a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 @@ -4,6 +4,7 @@ function Invoke-CIPPStandardintuneDeviceRetirementDays { Internal #> param($Tenant, $Settings) + $CurrentInfo = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/managedDeviceCleanupSettings' -tenantid $Tenant) $StateIsCorrect = if ($PreviousSetting.DeviceInactivityBeforeRetirementInDays -eq $Settings.days) { $true } else { $false } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index cbe6519ce66f..effaf7743996 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -4,6 +4,13 @@ function Invoke-CIPPStandardsharingCapability { Internal #> param($Tenant, $Settings) + + # Input validation + if ([string]::isNullOrEmpty($Settings.sharingCapability) -or $Settings.sharingCapability -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'sharingCapability: Invalid sharingCapability parameter set' -sev Error + Exit + } + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true # $CurrentInfo.sharingCapability.GetType() $Settings.Level From 0c6789eed6fa67fdcd2d40e123fe3845ec8fe31f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 00:04:13 +0200 Subject: [PATCH 21/91] Get per user MFA --- Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 diff --git a/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 new file mode 100644 index 000000000000..86acfc501082 --- /dev/null +++ b/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 @@ -0,0 +1,17 @@ +function Get-CIPPPerUserMFA { + [CmdletBinding()] + param( + $TenantFilter, + $userId, + $executingUser + ) + try { + $MFAState = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users/$($userId)/authentication/requirements" -tenantid $tenantfilter + return [PSCustomObject]@{ + user = $userId + PerUserMFA = $MFAState.perUserMfaState + } + } catch { + "Failed to get MFA State for $id : $_" + } +} \ No newline at end of file From 274b134099cbf0f377eb933d34350a6d55aef2bb Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 01:36:30 +0200 Subject: [PATCH 22/91] bulk request support --- .../GraphHelper/New-GraphBulkRequest.ps1 | 3 +- .../CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 20 ++++++++--- .../Invoke-CIPPStandardPerUserMFA.ps1 | 33 +++++++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 index ebe6af9675b9..f37be378e39d 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 @@ -33,7 +33,8 @@ function New-GraphBulkRequest { $req = @{} # Use select to create hashtables of id, method and url for each call $req['requests'] = ($Requests[$i..($i + 19)]) - Invoke-RestMethod -Uri $URL -Method POST -Headers $headers -ContentType 'application/json; charset=utf-8' -Body ($req | ConvertTo-Json -Depth 10) + $ReqBody = ($req | ConvertTo-Json -Depth 10) + Invoke-RestMethod -Uri $URL -Method POST -Headers $headers -ContentType 'application/json; charset=utf-8' -Body $ReqBody } foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) { diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index e044fe6797a3..74c3ecbb5d66 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -4,13 +4,25 @@ function Set-CIPPPerUserMFA { $TenantFilter, $userId, [ValidateSet('enabled', 'disabled', 'enforced')] - $State = 'users', + $State = 'enabled', $executingUser ) try { - $state = @{ 'perUserMfaState' = "$state" } | ConvertTo-Json - New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/users/$userId/authentication/requirements" -tenantid $tenantfilter -type PATCH -body $state - "Successfully set Per user MFA State for $id" + $int = 0 + $Requests = foreach ($id in $userId) { + @{ + id = $int++ + method = 'PATCH' + url = "users/$id/authentication/requirements" + body = @{ 'perUserMfaState' = "$state" } + 'headers' = @{ + 'Content-Type' = 'application/json' + } + } + } + #Split the requests by batches of 20, we can have anywhere from 1 to 1000 batches and execute New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests $batch + $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests $Requests -asapp $true + "Successfully set Per user MFA State for $userId" Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State for $id" -Sev 'Info' -tenant $TenantFilter } catch { "Failed to set MFA State for $id : $_" diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 new file mode 100644 index 000000000000..c651e9171a28 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 @@ -0,0 +1,33 @@ +function Invoke-CIPPStandardPerUserMFA { + <# + .FUNCTIONALITY + Internal + #> + param($Tenant, $Settings) + + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=UserPrincipalName,accountEnabled" -scope 'https://graph.microsoft.com/.default' -tenantid $Tenant | Where-Object { $_.AccountEnabled -EQ $true } + + If ($Settings.remediate -eq $true) { + if ($GraphRequest) { + try { + Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $GraphRequest.UserPrincipalName -State 'Enforced' + Write-LogMessage -API 'Standards' -tenant $tenant -message '' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable guest $($guest.UserPrincipalName) ($($guest.id)): $ErrorMessage" -sev Error + } + } + } + if ($Settings.alert -eq $true) { + + if ($GraphRequest) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Guests accounts with a login longer than 90 days ago: $($GraphRequest.count)" -sev Alert + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'No guests accounts with a login longer than 90 days ago.' -sev Info + } + } + if ($Settings.report -eq $true) { + $filtered = $GraphRequest | Select-Object -Property UserPrincipalName, id, signInActivity, mail, userType, accountEnabled + Add-CIPPBPAField -FieldName 'DisableGuests' -FieldValue $filtered -StoreAs json -Tenant $tenant + } +} From 6a4e8a9cf6c8a18b0b0a0dbffc0f90f54ca83b07 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 01:38:16 +0200 Subject: [PATCH 23/91] batching single item fix --- Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index 74c3ecbb5d66..9675b104bc82 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -21,7 +21,7 @@ function Set-CIPPPerUserMFA { } } #Split the requests by batches of 20, we can have anywhere from 1 to 1000 batches and execute New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests $batch - $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests $Requests -asapp $true + $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true "Successfully set Per user MFA State for $userId" Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State for $id" -Sev 'Info' -tenant $TenantFilter } catch { From c6d5945c32377e225b8f722d42ed2e1fab611c40 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 02:20:40 +0200 Subject: [PATCH 24/91] add more bulk features --- Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 1 - .../Invoke-CIPPStandardPerUserMFA.ps1 | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index 9675b104bc82..eedab329061c 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -20,7 +20,6 @@ function Set-CIPPPerUserMFA { } } } - #Split the requests by batches of 20, we can have anywhere from 1 to 1000 batches and execute New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests $batch $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true "Successfully set Per user MFA State for $userId" Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State for $id" -Sev 'Info' -tenant $TenantFilter diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 index c651e9171a28..16b0c037f223 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 @@ -6,15 +6,23 @@ function Invoke-CIPPStandardPerUserMFA { param($Tenant, $Settings) $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=UserPrincipalName,accountEnabled" -scope 'https://graph.microsoft.com/.default' -tenantid $Tenant | Where-Object { $_.AccountEnabled -EQ $true } - + $int = 0 + $Requests = foreach ($id in $GraphRequest.userPrincipalName) { + @{ + id = $int++ + method = 'GET' + url = "/users/$id/authentication/requirements" + } + } + $UsersWithoutMFA = (New-GraphBulkRequest -tenantid $tenant -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true).body | Where-Object { $_.perUserMfaState -ne 'enforced' } | Select-Object peruserMFAState, @{Name = 'UserPrincipalName'; Expression = { [System.Web.HttpUtility]::UrlDecode($_.'@odata.context'.split("'")[1]) } } If ($Settings.remediate -eq $true) { - if ($GraphRequest) { + if ($UsersWithoutMFA) { try { - Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $GraphRequest.UserPrincipalName -State 'Enforced' - Write-LogMessage -API 'Standards' -tenant $tenant -message '' -sev Info + $MFAMessage = Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $GraphRequest.UserPrincipalName -State 'Enforced' + Write-LogMessage -API 'Standards' -tenant $tenant -message $MFAMessage -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to disable guest $($guest.UserPrincipalName) ($($guest.id)): $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enforce MFA for all users: $ErrorMessage" -sev Error } } } From 3a5b49f854cc12525e5dd70c6a9424d42cd7bf41 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Jun 2024 23:53:01 -0400 Subject: [PATCH 25/91] Per user mfa tweaks --- .../Users/Invoke-ExecPerUserMFA.ps1 | 28 +++++++++++ .../CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 50 ++++++++++++++++--- .../Public/Set-CIPPUserSchemaProperties.ps1 | 43 +++++++++++++--- 3 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 new file mode 100644 index 000000000000..b52a1595f513 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 @@ -0,0 +1,28 @@ +function Invoke-ExecPerUserMFA { + <# + .FUNCTIONALITY + Entrypoint + + .ROLE + Identity.User.ReadWrite + #> + Param( + $Request, + $TriggerMetadata + ) + + $Request = @{ + userId = $Request.Body.userId + TenantFilter = $Request.Body.TenantFilter + State = $Request.Body.State + executingUser = $Request.Headers.'x-ms-client-principal' + } + $Result = Set-CIPPPerUserMFA @Request + $Body = @{ + Results = @($Result) + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index 9675b104bc82..c15258d01143 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -1,31 +1,69 @@ function Set-CIPPPerUserMFA { + <# + .SYNOPSIS + Change Per-User MFA State for a User + + .DESCRIPTION + Change the Per-User MFA State for a user via the /users/{id}/authentication/requirements endpoint + + .PARAMETER TenantFilter + Tenant where the user resides + + .PARAMETER userId + One or more User IDs to set the MFA state for (GUID or UserPrincipalName) + + .PARAMETER State + State to set the user to (enabled, disabled, enforced) + + .PARAMETER executingUser + User executing the command + + .EXAMPLE + Set-CIPPPerUserMFA -TenantFilter 'contoso.onmicrosoft.com' -userId user@contoso.onmicrosoft.com -State 'disabled' -executingUser 'mspuser@partner.com' + #> [CmdletBinding()] param( - $TenantFilter, - $userId, + [Parameter(Mandatory = $true)] + [string]$TenantFilter, + [Parameter(Mandatory = $true)] + [string[]]$userId, [ValidateSet('enabled', 'disabled', 'enforced')] $State = 'enabled', - $executingUser + [string]$executingUser = 'CIPP' ) try { $int = 0 + $Body = @{ + state = $State + } $Requests = foreach ($id in $userId) { @{ id = $int++ method = 'PATCH' url = "users/$id/authentication/requirements" - body = @{ 'perUserMfaState' = "$state" } + body = $Body 'headers' = @{ 'Content-Type' = 'application/json' } } } + #Split the requests by batches of 20, we can have anywhere from 1 to 1000 batches and execute New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests $batch $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true "Successfully set Per user MFA State for $userId" - Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State for $id" -Sev 'Info' -tenant $TenantFilter + + $Users = foreach ($id in $userId) { + @{ + userId = $id + Properties = @{ + perUserMfaState = $State + } + } + } + Set-CIPPUserSchemaProperties -TenantFilter $TenantFilter -Users $Users + Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State to $State for $id" -Sev 'Info' -tenant $TenantFilter } catch { "Failed to set MFA State for $id : $_" - Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Failed to set MFA State for $id : $_" -Sev 'Error' -tenant $TenantFilter + Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Failed to set MFA State to $State for $id : $_" -Sev 'Error' -tenant $TenantFilter } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 index 0c6f1960ad0d..b006a27069ef 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1 @@ -1,19 +1,46 @@ function Set-CIPPUserSchemaProperties { + <# + .SYNOPSIS + Set Schema Properties for a user + + .DESCRIPTION + Uses scheam extensions to set properties for a user + + .PARAMETER TenantFilter + Tenant for user + + .PARAMETER UserId + One or more user ids to set properties for + + .PARAMETER Properties + Hashtable of properties to set + + #> [CmdletBinding(SupportsShouldProcess = $true)] Param( + [Parameter(Mandatory = $true)] [string]$TenantFilter, - [string]$UserId, - [hashtable]$Properties + [Parameter(Mandatory = $true)] + [object]$Users ) $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } - - $Body = [PSCustomObject]@{ - "$($Schema.id)" = $Properties + $int = 0 + $Requests = foreach ($User in $Users) { + @{ + id = $int++ + method = 'PATCH' + url = "users/$($User.userId)" + body = @{ + "$($Schema.id)" = $User.Properties + } + 'headers' = @{ + 'Content-Type' = 'application/json' + } + } } - $Json = ConvertTo-Json -Depth 5 -InputObject $Body - if ($PSCmdlet.ShouldProcess("User: $UserId", "Set Schema Properties to $($Properties|ConvertTo-Json -Compress)")) { - New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter + if ($PSCmdlet.ShouldProcess("User: $($Users.userId -join ', ')", 'Set Schema Properties')) { + $Requests = New-GraphBulkRequest -tenantid $tenantfilter -Requests @($Requests) } } \ No newline at end of file From 1df3a0bf56090c63d56c1ff0e15175e563622161 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 12:22:04 +0200 Subject: [PATCH 26/91] added per user MFA standard --- .../Standards/Invoke-CIPPStandardPerUserMFA.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 index 16b0c037f223..9ecd363c44a3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 @@ -15,10 +15,11 @@ function Invoke-CIPPStandardPerUserMFA { } } $UsersWithoutMFA = (New-GraphBulkRequest -tenantid $tenant -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true).body | Where-Object { $_.perUserMfaState -ne 'enforced' } | Select-Object peruserMFAState, @{Name = 'UserPrincipalName'; Expression = { [System.Web.HttpUtility]::UrlDecode($_.'@odata.context'.split("'")[1]) } } + If ($Settings.remediate -eq $true) { if ($UsersWithoutMFA) { try { - $MFAMessage = Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $GraphRequest.UserPrincipalName -State 'Enforced' + $MFAMessage = Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $UsersWithoutMFA.UserPrincipalName -State 'Enforced' Write-LogMessage -API 'Standards' -tenant $tenant -message $MFAMessage -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message @@ -28,14 +29,13 @@ function Invoke-CIPPStandardPerUserMFA { } if ($Settings.alert -eq $true) { - if ($GraphRequest) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Guests accounts with a login longer than 90 days ago: $($GraphRequest.count)" -sev Alert + if ($UsersWithoutMFA) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The following accounts do not have Legacy MFA Enforced: $($UsersWithoutMFA.UserPrincipalName -join ', ')" -sev Alert } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'No guests accounts with a login longer than 90 days ago.' -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message 'No accounts do not have legacy per user MFA Enforced' -sev Info } } if ($Settings.report -eq $true) { - $filtered = $GraphRequest | Select-Object -Property UserPrincipalName, id, signInActivity, mail, userType, accountEnabled - Add-CIPPBPAField -FieldName 'DisableGuests' -FieldValue $filtered -StoreAs json -Tenant $tenant + Add-CIPPBPAField -FieldName 'LegacyMFAUsers' -FieldValue $UsersWithoutMFA -StoreAs json -Tenant $tenant } } From 2c160c9b5bc6357b7fa79d12905edf217641ac59 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 12:48:07 +0200 Subject: [PATCH 27/91] Add All Tenants to per user MFA --- .../CIPPCore/Public/Get-CIPPPerUserMFA.ps1 | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 index 86acfc501082..05e879a83496 100644 --- a/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 @@ -3,13 +3,30 @@ function Get-CIPPPerUserMFA { param( $TenantFilter, $userId, - $executingUser + $executingUser, + $AllUsers = $false ) try { - $MFAState = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users/$($userId)/authentication/requirements" -tenantid $tenantfilter - return [PSCustomObject]@{ - user = $userId - PerUserMFA = $MFAState.perUserMfaState + if ($AllUsers -eq $true) { + $AllUsers = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=UserPrincipalName,Id" -tenantid $tenantfilter + $Requests = foreach ($id in $AllUsers.userPrincipalName) { + @{ + id = $int++ + method = 'GET' + url = "users/$id/authentication/requirements" + } + } + $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true + if ($Requests.body) { + $UsersWithoutMFA = $Requests.body | Select-Object peruserMFAState, @{Name = 'UserPrincipalName'; Expression = { [System.Web.HttpUtility]::UrlDecode($_.'@odata.context'.split("'")[1]) } } + return $UsersWithoutMFA + } + } else { + $MFAState = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users/$($userId)/authentication/requirements" -tenantid $tenantfilter + return [PSCustomObject]@{ + UserPrincipalName = $userId + PerUserMFAState = $MFAState.perUserMfaState + } } } catch { "Failed to get MFA State for $id : $_" From 57ab90aae84c3276d9c172337fa1955b46827647 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 13:56:56 +0200 Subject: [PATCH 28/91] updated MFA REport --- Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 | 20 +++++++++---------- .../CIPPCore/Public/Get-CIPPPerUserMFA.ps1 | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 b/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 index 319f9a81e726..28d526a9944d 100644 --- a/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 @@ -6,18 +6,17 @@ function Get-CIPPMFAState { $APIName = 'Get MFA Status', $ExecutingUser ) - - $users = foreach ($user in (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$select=id,UserPrincipalName,DisplayName,accountEnabled,assignedLicenses' -tenantid $TenantFilter)) { + $PerUserMFAState = Get-CIPPPerUserMFA -TenantFilter $TenantFilter -AllUsers $true + $users = foreach ($user in (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$top=999&$select=id,UserPrincipalName,DisplayName,accountEnabled,assignedLicenses' -tenantid $TenantFilter)) { [PSCustomObject]@{ - UserPrincipalName = $user.UserPrincipalName - isLicensed = [boolean]$user.assignedLicenses.skuid - accountEnabled = $user.accountEnabled - DisplayName = $user.DisplayName - ObjectId = $user.id - StrongAuthenticationRequirements = @{StrongAuthenticationRequirement = @{state = 'See Documentation' } } + UserPrincipalName = $user.UserPrincipalName + isLicensed = [boolean]$user.assignedLicenses.skuid + accountEnabled = $user.accountEnabled + DisplayName = $user.DisplayName + ObjectId = $user.id } } - + $SecureDefaultsState = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $TenantFilter ).IsEnabled $CAState = New-Object System.Collections.ArrayList @@ -62,7 +61,6 @@ function Get-CIPPMFAState { Write-Host 'Processing users' $UserCAState = New-Object System.Collections.ArrayList foreach ($CA in $CAState) { - Write-Host 'Looping CAState' if ($CA -like '*All Users*') { if ($ExcludeAllUsers -contains $_.ObjectId) { $UserCAState.Add("Excluded from $($policy.displayName) - All Users") | Out-Null } else { $UserCAState.Add($CA) | Out-Null } @@ -75,7 +73,7 @@ function Get-CIPPMFAState { } } - $PerUser = if ($_.StrongAuthenticationRequirements.StrongAuthenticationRequirement.state -ne $null) { $_.StrongAuthenticationRequirements.StrongAuthenticationRequirement.state } else { 'Disabled' } + $PerUser = if ($PerUserMFAState -eq $null) { $null } else { ($PerUserMFAState | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).PerUserMFAState } $MFARegUser = if (($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).IsMFARegistered -eq $null) { $false } else { ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName) } diff --git a/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 index 05e879a83496..5c525962009f 100644 --- a/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1 @@ -24,8 +24,8 @@ function Get-CIPPPerUserMFA { } else { $MFAState = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users/$($userId)/authentication/requirements" -tenantid $tenantfilter return [PSCustomObject]@{ - UserPrincipalName = $userId PerUserMFAState = $MFAState.perUserMfaState + UserPrincipalName = $userId } } } catch { From 5e1a87d7084297dcbb644df0695c7e55d8b9c522 Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 13 Jun 2024 12:50:24 +0200 Subject: [PATCH 29/91] Added sharingDomainRestrictionMode Standard --- ...e-CIPPStandardsharingDomainRestriction.ps1 | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 new file mode 100644 index 000000000000..9c7e7d11f555 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 @@ -0,0 +1,63 @@ +function Invoke-CIPPStandardsharingDomainRestriction { + <# + .FUNCTIONALITY + Internal + #> + + param($Tenant, $Settings) + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true + + if ($Settings.Mode -eq 'none' -or $null -eq $Settings.Mode) { + $StateIsCorrect = $CurrentState.sharingDomainRestrictionMode -eq 'none' + } else { + $SelectedDomains = [String[]]$Settings.Domains.Split(',').Trim() + $StateIsCorrect = ($CurrentState.sharingDomainRestrictionMode -eq $Settings.Mode) -and + ($Settings.Mode -eq 'allowList' -and (!(Compare-Object -ReferenceObject $CurrentState.sharingAllowedDomainList -DifferenceObject $SelectedDomains))) -or + ($Settings.Mode -eq 'blockList' -and (!(Compare-Object -ReferenceObject $CurrentState.sharingBlockedDomainList -DifferenceObject $SelectedDomains))) + } + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is already correctly configured' -sev Info + } else { + $Body = @{ + sharingDomainRestrictionMode = $Settings.Mode + } + + if ($Settings.Mode -eq 'AllowList') { + $Body.Add('sharingAllowedDomainList', $SelectedDomains) + } elseif ($Settings.Mode -eq 'BlockList') { + $Body.Add('sharingBlockedDomainList', $SelectedDomains) + } + + $cmdparams = @{ + tenantid = $tenant + uri = 'https://graph.microsoft.com/beta/admin/sharepoint/settings' + AsApp = $true + Type = 'PATCH' + Body = ($Body | ConvertTo-Json) + ContentType = 'application/json' + } + + try { + New-GraphPostRequest @cmdparams + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully updated Sharing Domain Restriction settings' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to update Sharing Domain Restriction settings. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is correctly configured' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is not correctly configured' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'sharingDomainRestriction' -FieldValue [bool]$StateIsCorrect -StoreAs bool -Tenant $tenant + } +} From a7a8599759058847cc7c4f0accfb9ee3d7b760df Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 10:41:26 -0400 Subject: [PATCH 30/91] Add exception handling for parsing audit logs --- .../Webhooks/Test-CIPPAuditLogRules.ps1 | 145 +++++++++--------- 1 file changed, 75 insertions(+), 70 deletions(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 index 1714544a6e6c..11ddd5bd7919 100644 --- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -40,86 +40,91 @@ function Test-CIPPAuditLogRules { $PreProccessedData = $Data | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties -ErrorAction SilentlyContinue $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' $ProcessedData = foreach ($Data in $PreProccessedData) { - if ($Data.ExtendedProperties) { - $Data.CIPPExtendedProperties = ($Data.ExtendedProperties | ConvertTo-Json) - if ($Data.CIPPExtendedProperties.RequestType -in $ExtendedPropertiesIgnoreList) { - Write-Information 'No need to process this operation as its in our ignore list' - continue - } - $Data.ExtendedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } - } - if ($Data.DeviceProperties) { - $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json) - $Data.DeviceProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } - } - if ($Data.parameters) { - $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json) - $Data.parameters | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } - } - if ($Data.ModifiedProperties) { - $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json) - try { - $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue } - } catch { - Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) - } - try { - $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue } - } catch { - Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) + try { + if ($Data.ExtendedProperties) { + $Data.CIPPExtendedProperties = ($Data.ExtendedProperties | ConvertTo-Json) + if ($Data.CIPPExtendedProperties.RequestType -in $ExtendedPropertiesIgnoreList) { + Write-Information 'No need to process this operation as its in our ignore list' + continue + } + $Data.ExtendedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } } - } - - if ($Data.clientip) { - if ($Data.clientip -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$') { - $Data.clientip = $Data.clientip -replace ':\d+$', '' # Remove the port number if present + if ($Data.DeviceProperties) { + $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json) + $Data.DeviceProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } } - # Check if IP is on trusted IP list - $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Data.clientip)' and state eq 'Trusted'" - if ($TrustedIP) { - Write-Information "IP $($Data.clientip) is trusted" - continue + if ($Data.parameters) { + $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json) + $Data.parameters | ForEach-Object { $Data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } } - - $Location = Get-CIPPAzDataTableEntity @LocationTable -Filter "RowKey eq '$($Data.clientIp)'" | Select-Object -Last 1 - if ($Location) { - $Country = $Location.CountryOrRegion - $City = $Location.City - $Proxy = $Location.Proxy - $hosting = $Location.Hosting - $ASName = $Location.ASName - } else { - $Location = Get-CIPPGeoIPLocation -IP $Data.clientip - $Country = if ($Location.CountryCode) { $Location.CountryCode } else { 'Unknown' } - $City = if ($Location.City) { $Location.City } else { 'Unknown' } - $Proxy = if ($Location.Proxy -ne $null) { $Location.Proxy } else { 'Unknown' } - $hosting = if ($Location.Hosting -ne $null) { $Location.Hosting } else { 'Unknown' } - $ASName = if ($Location.ASName) { $Location.ASName } else { 'Unknown' } - $IP = $Data.ClientIP - $LocationInfo = @{ - RowKey = [string]$Data.clientip - PartitionKey = [string]$Data.id - Tenant = [string]$TenantFilter - CountryOrRegion = "$Country" - City = "$City" - Proxy = "$Proxy" - Hosting = "$hosting" - ASName = "$ASName" + if ($Data.ModifiedProperties) { + $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json) + try { + $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue } + } catch { + Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) } try { - $null = Add-CIPPAzDataTableEntity @LocationTable -Entity $LocationInfo -Force + $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue } } catch { - Write-Information "Failed to add location info for $($Data.clientip) to cache: $($_.Exception.Message)" + Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) + } + } + + if ($Data.clientip) { + if ($Data.clientip -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$') { + $Data.clientip = $Data.clientip -replace ':\d+$', '' # Remove the port number if present + } + # Check if IP is on trusted IP list + $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Data.clientip)' and state eq 'Trusted'" + if ($TrustedIP) { + Write-Information "IP $($Data.clientip) is trusted" + continue + } + + $Location = Get-CIPPAzDataTableEntity @LocationTable -Filter "RowKey eq '$($Data.clientIp)'" | Select-Object -Last 1 + if ($Location) { + $Country = $Location.CountryOrRegion + $City = $Location.City + $Proxy = $Location.Proxy + $hosting = $Location.Hosting + $ASName = $Location.ASName + } else { + $Location = Get-CIPPGeoIPLocation -IP $Data.clientip + $Country = if ($Location.CountryCode) { $Location.CountryCode } else { 'Unknown' } + $City = if ($Location.City) { $Location.City } else { 'Unknown' } + $Proxy = if ($Location.Proxy -ne $null) { $Location.Proxy } else { 'Unknown' } + $hosting = if ($Location.Hosting -ne $null) { $Location.Hosting } else { 'Unknown' } + $ASName = if ($Location.ASName) { $Location.ASName } else { 'Unknown' } + $IP = $Data.ClientIP + $LocationInfo = @{ + RowKey = [string]$Data.clientip + PartitionKey = [string]$Data.id + Tenant = [string]$TenantFilter + CountryOrRegion = "$Country" + City = "$City" + Proxy = "$Proxy" + Hosting = "$hosting" + ASName = "$ASName" + } + try { + $null = Add-CIPPAzDataTableEntity @LocationTable -Entity $LocationInfo -Force + } catch { + Write-Information "Failed to add location info for $($Data.clientip) to cache: $($_.Exception.Message)" + } } + $Data.CIPPGeoLocation = $Country + $Data.CIPPBadRepIP = $Proxy + $Data.CIPPHostedIP = $hosting + $Data.CIPPIPDetected = $IP + $Data.CIPPLocationInfo = ($Location | ConvertTo-Json) } - $Data.CIPPGeoLocation = $Country - $Data.CIPPBadRepIP = $Proxy - $Data.CIPPHostedIP = $hosting - $Data.CIPPIPDetected = $IP - $Data.CIPPLocationInfo = ($Location | ConvertTo-Json) + $Data | Select-Object * -ExcludeProperty ExtendedProperties, DeviceProperties, parameters + } catch { + Write-Information "Audit log: Error processing data: $($_.Exception.Message)`r`n$($_.InvocationInfo.PositionMessage)" + Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit Log Data' -LogData (Get-CippException -Exception $_) } - $Data | Select-Object * -ExcludeProperty ExtendedProperties, DeviceProperties, parameters } #Filter data based on conditions. From e683e4af7a8bc5b0fcc4d262c7cff26a3fa65609 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 10:53:33 -0400 Subject: [PATCH 31/91] Update Get-CIPPAuditLogContentBundles.ps1 --- .../CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index 67b667b9e793..f1c12bb17086 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -65,7 +65,7 @@ function Get-CIPPAuditLogContentBundles { if ($EndTime) { $Parameters.Add('endTime', $EndTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss')) } else { - $Parameters.Add('endTime', (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss')) + $Parameters.Add('endTime', ($StartTime).AddHours(24).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss')) } } From b69d2c49160c26dab494a5a7f33ebe179d4e0863 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 11:25:28 -0400 Subject: [PATCH 32/91] Update Get-CIPPAuditLogContentBundles.ps1 --- .../CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index f1c12bb17086..e5c199e738d1 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -56,7 +56,7 @@ function Get-CIPPAuditLogContentBundles { if (!$ShowAll.IsPresent) { if ($WebhookConfig.LastContentCreated) { $StartTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime() - $EndTime = Get-Date + $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddHours(24) } } From 97a05669f368f86a14e9f04f60ac45d72df66a56 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 11:39:04 -0400 Subject: [PATCH 33/91] Update Get-CIPPAuditLogContentBundles.ps1 --- .../Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index e5c199e738d1..cf4d91be52a9 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -54,9 +54,9 @@ function Get-CIPPAuditLogContentBundles { } if (!$ShowAll.IsPresent) { - if ($WebhookConfig.LastContentCreated) { + if ($null -ne $WebhookConfig.LastContentCreated) { $StartTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime() - $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddHours(24) + $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddHours(12) } } From 87c235ef0ca00a2db865593c424970614292dfe8 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 11:55:00 -0400 Subject: [PATCH 34/91] Update Test-CIPPAuditLogRules.ps1 --- .../Public/Webhooks/Test-CIPPAuditLogRules.ps1 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 index 11ddd5bd7919..ddffea0fff1f 100644 --- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -62,12 +62,12 @@ function Test-CIPPAuditLogRules { try { $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue } } catch { - Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) + #Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) } try { $Data.ModifiedProperties | ForEach-Object { $Data | Add-Member -NotePropertyName $("Previous_Value_$($_.Name)") -NotePropertyValue "$($_.OldValue)" -Force -ErrorAction SilentlyContinue } } catch { - Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) + #Write-Information ($Data.ModifiedProperties | ConvertTo-Json -Depth 10) } } @@ -90,7 +90,11 @@ function Test-CIPPAuditLogRules { $hosting = $Location.Hosting $ASName = $Location.ASName } else { - $Location = Get-CIPPGeoIPLocation -IP $Data.clientip + try { + $Location = Get-CIPPGeoIPLocation -IP $Data.clientip + } catch { + Write-Information "Unable to get IP location for $($Data.clientip): $($_.Exception.Messge)" + } $Country = if ($Location.CountryCode) { $Location.CountryCode } else { 'Unknown' } $City = if ($Location.City) { $Location.City } else { 'Unknown' } $Proxy = if ($Location.Proxy -ne $null) { $Location.Proxy } else { 'Unknown' } @@ -123,7 +127,7 @@ function Test-CIPPAuditLogRules { $Data | Select-Object * -ExcludeProperty ExtendedProperties, DeviceProperties, parameters } catch { Write-Information "Audit log: Error processing data: $($_.Exception.Message)`r`n$($_.InvocationInfo.PositionMessage)" - Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit Log Data' -LogData (Get-CippException -Exception $_) + Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit Log Data' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter } } From cee929d225265b02a9da7822ba16a3cd219db82e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 14:50:02 -0400 Subject: [PATCH 35/91] audit log polling --- .../CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 | 2 +- Scheduler_PollAuditLogs/run.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index cf4d91be52a9..363c31402feb 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -56,7 +56,7 @@ function Get-CIPPAuditLogContentBundles { if (!$ShowAll.IsPresent) { if ($null -ne $WebhookConfig.LastContentCreated) { $StartTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime() - $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddHours(12) + $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddHours(4) } } diff --git a/Scheduler_PollAuditLogs/run.ps1 b/Scheduler_PollAuditLogs/run.ps1 index 4052f81d4c00..9fb8105f809e 100644 --- a/Scheduler_PollAuditLogs/run.ps1 +++ b/Scheduler_PollAuditLogs/run.ps1 @@ -9,7 +9,7 @@ try { } try { - $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq 'AuditLogCollection' -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq 'AuditLogCollection' -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' -and $_.Timestamp.DateTime.ToLocalTime() -lt (Get-Date).AddMinutes(-10) } if ($RunningQueue) { Write-Host 'Audit log collection already running' return From cd54b1b22acc3b8082eb59211e31580a190ede98 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 15:01:52 -0400 Subject: [PATCH 36/91] Add test endpoint --- .../Alerts/Invoke-ListAuditLogTest.ps1 | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 new file mode 100644 index 000000000000..a3f7481c2507 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 @@ -0,0 +1,25 @@ +function Invoke-ListAuditLogTest { + <# + .FUNCTIONALITY + Entrypoint + + .ROLE + Tenant.Alert.Read + #> + Param($Request, $TriggerMetadata) + + $AuditLogQuery = @{ + TenantFilter = $Request.Query.TenantFilter + LogType = $Request.Query.LogType + ShowAll = $true + } + $Results = Test-CIPPAuditLogRules @AuditLogQuery + $Body = @{ + Results = @($Results) + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) + +} \ No newline at end of file From 02775bd2a62efa30916e2cf6569dfa76042a3067 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 15:20:39 -0400 Subject: [PATCH 37/91] Add audit log metadata --- .../Webhooks/Push-AuditLogBundleProcessing.ps1 | 2 +- .../Alerts/Invoke-ListAuditLogTest.ps1 | 11 +++++++++-- .../Public/Webhooks/Test-CIPPAuditLogRules.ps1 | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 index 38575541f03e..d8bf577eac0d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 @@ -26,7 +26,7 @@ function Push-AuditLogBundleProcessing { foreach ($LogType in $LogTypes) { Write-Information "Querying for log type: $LogType" try { - $DataToProcess = Test-CIPPAuditLogRules -TenantFilter $TenantFilter -LogType $LogType + $DataToProcess = (Test-CIPPAuditLogRules -TenantFilter $TenantFilter -LogType $LogType).DataToProcess Write-Information "Webhook: Data to process found: $($DataToProcess.count) items" foreach ($AuditLog in $DataToProcess) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 index a3f7481c2507..c83484ec17e7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 @@ -13,9 +13,16 @@ function Invoke-ListAuditLogTest { LogType = $Request.Query.LogType ShowAll = $true } - $Results = Test-CIPPAuditLogRules @AuditLogQuery + $TestResults = Test-CIPPAuditLogRules @AuditLogQuery $Body = @{ - Results = @($Results) + Results = @($TestResults.DataToProcess) + Metadata = @{ + TenantFilter = $AuditLogQuery.TenantFilter + LogType = $AuditLogQuery.LogType + TotalLogs = $TestResults.TotalLogs + MatchedLogs = $TestResults.MatchedLogs + MatchedRules = $TestResults.MatchedRules + } } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 index ddffea0fff1f..763efa62656b 100644 --- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -9,6 +9,13 @@ function Test-CIPPAuditLogRules { [switch]$ShowAll ) + $Results = [PSCustomObject]@{ + TotalLogs = 0 + MatchedLogs = 0 + MatchedRules = @() + DataToProcess = @() + } + $ExtendedPropertiesIgnoreList = @( 'OAuth2:Authorize' 'OAuth2:Token' @@ -36,6 +43,7 @@ function Test-CIPPAuditLogRules { $Data = Get-CIPPAuditLogContentBundles @ContentBundleQuery | Get-CIPPAuditLogContent $LogCount = ($Data | Measure-Object).Count Write-Information "Logs to process: $LogCount" + $Results.TotalLogs = $LogCount if ($LogCount -gt 0) { $PreProccessedData = $Data | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties -ErrorAction SilentlyContinue $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' @@ -159,6 +167,7 @@ function Test-CIPPAuditLogRules { } Write-Information "Webhook: The list of operations in the data are $(($ProcessedData.operation | Select-Object -Unique) -join ', ')" + $MatchedRules = [System.Collections.Generic.List[string]]::new() $DataToProcess = foreach ($clause in $Where) { Write-Information "Webhook: Processing clause: $($clause.clause)" Write-Information "Webhook: If this clause would be true, the action would be: $($clause.expectedAction)" @@ -167,11 +176,15 @@ function Test-CIPPAuditLogRules { $ReturnedData = foreach ($item in $ReturnedData) { $item.CIPPAction = $clause.expectedAction $item.CIPPClause = $clause.CIPPClause -join ' and ' + $MatchedRules.Add($clause.CIPPClause -join ' and ') $item } } $ReturnedData } - $DataToProcess + $Results.MatchedRules = $MatchedRules | Select-Object -Unique + $Results.MatchedLogs = ($DataToProcess | Measure-Object).Count + $Results.DataToProcess = $DataToProcess } + $Results } \ No newline at end of file From 78e826d3478a8c461d8c7e202c4bbb0831466de3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 16:46:15 -0400 Subject: [PATCH 38/91] Tweak polling interval --- Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 | 2 +- Scheduler_PollAuditLogs/function.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 index 6c6424d56857..38311e1d5c70 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 @@ -14,7 +14,7 @@ function Get-CIPPAuditLogContent { [CmdletBinding()] Param( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] - [string]$ContentUri, + [string[]]$ContentUri, [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [string]$TenantFilter ) diff --git a/Scheduler_PollAuditLogs/function.json b/Scheduler_PollAuditLogs/function.json index de05da024fc9..f30537d11b34 100644 --- a/Scheduler_PollAuditLogs/function.json +++ b/Scheduler_PollAuditLogs/function.json @@ -2,7 +2,7 @@ "bindings": [ { "name": "Timer", - "schedule": "0 */5 * * * *", + "schedule": "0 */15 * * * *", "direction": "in", "type": "timerTrigger" }, From c7e0e02ccd75a71a601d15d74042819b9fe98db6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 16:57:48 -0400 Subject: [PATCH 39/91] Update Get-CIPPAuditLogContent.ps1 --- Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 index 38311e1d5c70..7a751bda4aef 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContent.ps1 @@ -20,6 +20,8 @@ function Get-CIPPAuditLogContent { ) Process { - New-GraphPOSTRequest -type GET -uri $ContentUri -tenantid $TenantFilter -scope 'https://manage.office.com/.default' + foreach ($Uri in $ContentUri) { + New-GraphPOSTRequest -type GET -uri $Uri -tenantid $TenantFilter -scope 'https://manage.office.com/.default' + } } } \ No newline at end of file From bbbc1611660e9966cafc6a221fa9840036ce4012 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 13 Jun 2024 17:32:17 -0400 Subject: [PATCH 40/91] Update Invoke-ListAuditLogTest.ps1 --- .../Administration/Alerts/Invoke-ListAuditLogTest.ps1 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 index c83484ec17e7..34576f5b5811 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogTest.ps1 @@ -13,7 +13,16 @@ function Invoke-ListAuditLogTest { LogType = $Request.Query.LogType ShowAll = $true } - $TestResults = Test-CIPPAuditLogRules @AuditLogQuery + try { + $TestResults = Test-CIPPAuditLogRules @AuditLogQuery + } catch { + $Body = Get-CippException -Exception $_ + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = $Body + }) + return + } $Body = @{ Results = @($TestResults.DataToProcess) Metadata = @{ From ed9c41c43636b49658d7c64434f634f001706f2d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:56:05 +0200 Subject: [PATCH 41/91] Add or update the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippacnqv.yml | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/dev_cippacnqv.yml diff --git a/.github/workflows/dev_cippacnqv.yml b/.github/workflows/dev_cippacnqv.yml new file mode 100644 index 000000000000..67a58b70c7ff --- /dev/null +++ b/.github/workflows/dev_cippacnqv.yml @@ -0,0 +1,39 @@ +# 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 - cippacnqv + +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 + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: 'Checkout GitHub Action' + uses: actions/checkout@v4 + + - name: Login to Azure + uses: azure/login@v1 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_6085081ED1124B799258E9FF743FF4B9 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_9BDB2DDBFAFA4BC19C20A58B204BFAF3 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_02B5224812794971B05EDD557AF2B867 }} + + - name: 'Run Azure Functions Action' + uses: Azure/functions-action@v1 + id: fa + with: + app-name: 'cippacnqv' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + \ No newline at end of file From 7b977652303123886ee04857d3609ab96bb6a97f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 00:14:15 +0200 Subject: [PATCH 42/91] add instant allow for sam setup --- Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index c10a38349d7b..acdaba4e0cee 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -3,7 +3,7 @@ function Test-CIPPAccess { $Request, [switch]$TenantList ) - + if ($Request.Params.CIPPEndpoint -eq 'ExecSAMSetup') { return $true } if (!$Request.Headers.'x-ms-client-principal') { # Direct API Access $CustomRoles = @('CIPP-API') From 8fbc4c150848cda0a20873e81199c93e07928f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Bentsen=20Kj=C3=A6rg=C3=A5rd=20=28KBK=29?= Date: Fri, 14 Jun 2024 09:49:32 +0200 Subject: [PATCH 43/91] Generalized error handling for adding shared mailbox --- .../Email-Exchange/Invoke-AddSharedMailbox.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 index 20af9ebdd475..28e868cee9a4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 @@ -35,8 +35,9 @@ Function Invoke-AddSharedMailbox { Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Created shared mailbox $($groupobj.displayname) with email $Email" -Sev 'Info' } catch { - Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to create shared mailbox. Error: $($_.Exception.Message)" -Sev 'Error' - $Body = $Results.add("Failed to create Shared Mailbox. $($_.Exception.Message)") + $ErrorMessage = Get-NormalizedError -message $_.Exception.Message + Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to create shared mailbox. Error: $ErrorMessage" -Sev 'Error' + $Body = $Results.add("Failed to create Shared Mailbox: $ErrorMessage") } @@ -54,8 +55,9 @@ Function Invoke-AddSharedMailbox { $Body = $results.add("Added Aliases to $Email : $($Aliases -join ',')") } } catch { - Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to add aliases to $Email : $($_.Exception.Message)" -Sev 'Error' - $Body = $results.add("ERROR: Failed to add aliases to $Email : $($_.Exception.Message)") + $ErrorMessage = Get-NormalizedError -message $_.Exception.Message + Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to add aliases to $Email : $ErrorMessage" -Sev 'Error' + $Body = $results.add("ERROR: Failed to add aliases to $Email : $ErrorMessage") } $Body = [pscustomobject] @{ 'Results' = @($results) } From 983285f56bdbd9ab1b02c636199280d91fa2c86f Mon Sep 17 00:00:00 2001 From: Esco Date: Fri, 14 Jun 2024 10:24:54 +0200 Subject: [PATCH 44/91] Added intuneBrandingProfile standard --- ...voke-CIPPStandardintuneBrandingProfile.ps1 | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 new file mode 100644 index 000000000000..c049ebb95749 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 @@ -0,0 +1,67 @@ +function Invoke-CIPPStandardintuneBrandingProfile { + <# + .FUNCTIONALITY + Internal + #> + + param($Tenant, $Settings) + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/intuneBrandingProfiles/c3a59481-1bf2-46ce-94b3-66eec07a8d60/' -tenantid $Tenant -AsApp $true + + $StateIsCorrect = ((-not $Settings.displayName) -or ($CurrentState.displayName -eq $Settings.displayName)) -and + ((-not $Settings.showLogo) -or ($CurrentState.showLogo -eq $Settings.showLogo)) -and + ((-not $Settings.showDisplayNameNextToLogo) -or ($CurrentState.showDisplayNameNextToLogo -eq $Settings.showDisplayNameNextToLogo)) -and + ((-not $Settings.contactITName) -or ($CurrentState.contactITName -eq $Settings.contactITName)) -and + ((-not $Settings.contactITPhoneNumber) -or ($CurrentState.contactITPhoneNumber -eq $Settings.contactITPhoneNumber)) -and + ((-not $Settings.contactITEmailAddress) -or ($CurrentState.contactITEmailAddress -eq $Settings.contactITEmailAddress)) -and + ((-not $Settings.contactITNotes) -or ($CurrentState.contactITNotes -eq $Settings.contactITNotes)) -and + ((-not $Settings.onlineSupportSiteName) -or ($CurrentState.onlineSupportSiteName -eq $Settings.onlineSupportSiteName)) -and + ((-not $Settings.onlineSupportSiteUrl) -or ($CurrentState.onlineSupportSiteUrl -eq $Settings.onlineSupportSiteUrl)) -and + ((-not $Settings.privacyUrl) -or ($CurrentState.privacyUrl -eq $Settings.privacyUrl)) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is already correctly configured' -sev Info + } else { + $Body = @{} + if ($Settings.displayName) { $Body.displayName = $Settings.displayName } + if ($Settings.showLogo) { $Body.showLogo = $Settings.showLogo } + if ($Settings.showDisplayNameNextToLogo) { $Body.showDisplayNameNextToLogo = $Settings.showDisplayNameNextToLogo } + if ($Settings.contactITName) { $Body.contactITName = $Settings.contactITName } + if ($Settings.contactITPhoneNumber) { $Body.contactITPhoneNumber = $Settings.contactITPhoneNumber } + if ($Settings.contactITEmailAddress) { $Body.contactITEmailAddress = $Settings.contactITEmailAddress } + if ($Settings.contactITNotes) { $Body.contactITNotes = $Settings.contactITNotes } + if ($Settings.onlineSupportSiteName) { $Body.onlineSupportSiteName = $Settings.onlineSupportSiteName } + if ($Settings.onlineSupportSiteUrl) { $Body.onlineSupportSiteUrl = $Settings.onlineSupportSiteUrl } + if ($Settings.privacyUrl) { $Body.privacyUrl = $Settings.privacyUrl } + + $cmdparams = @{ + tenantid = $tenant + uri = 'https://graph.microsoft.com/beta/deviceManagement/intuneBrandingProfiles/c3a59481-1bf2-46ce-94b3-66eec07a8d60/' + AsApp = $true + Type = 'PATCH' + Body = ($Body | ConvertTo-Json) + ContentType = 'application/json; charset=utf-8' + } + + try { + New-GraphPostRequest @cmdparams + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully updated Intune Branding Profile' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to update Intune Branding Profile. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is correctly configured' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is not correctly configured' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'intuneBrandingProfile' -FieldValue [bool]$StateIsCorrect -StoreAs bool -Tenant $tenant + } +} From a9cd2d4779a01f2744ebccd7cc38a2db31ff2d94 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:03:02 +0200 Subject: [PATCH 45/91] added anchor conversion --- Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 index 4a05cf778fe7..d9bca21efd69 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 @@ -22,6 +22,7 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc if ($cmdparams.Identity) { $Anchor = $cmdparams.Identity } if ($cmdparams.anr) { $Anchor = $cmdparams.anr } if ($cmdparams.User) { $Anchor = $cmdparams.User } + if ($cmdparams.mailbox) { $Anchor = $cmdparams.mailbox } if (!$Anchor -or $useSystemMailbox) { if (!$Tenant.initialDomainName) { @@ -31,6 +32,15 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc } $anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)" } + #if the anchor is a GUID, try looking up the user. + if ($Anchor -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') { + $Anchor = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$Anchor" -tenantid $tenantid -NoAuthCheck $NoAuthCheck + if ($Anchor) { + $Anchor = $Anchor.UserPrincipalName + } else { + Write-Error "Failed to find user with GUID $Anchor" + } + } } Write-Host "Using $Anchor" $Headers = @{ From 103a05e3137a25980ce01968e878c4a2e22b72cb Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:06:02 +0200 Subject: [PATCH 46/91] added support for incorrect initial domain --- Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 index d9bca21efd69..8ef890eaf10d 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 @@ -25,7 +25,7 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc if ($cmdparams.mailbox) { $Anchor = $cmdparams.mailbox } if (!$Anchor -or $useSystemMailbox) { - if (!$Tenant.initialDomainName) { + if (!$Tenant.initialDomainName -or $Tenant.initialDomainName -notlike '*onmicrosoft.com*') { $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantid -NoAuthCheck $NoAuthCheck | Where-Object -Property isInitial -EQ $true).id } else { $OnMicrosoft = $Tenant.initialDomainName From a9924f0664e9065227a709696d9ee0efcde5a6da Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:26:27 +0200 Subject: [PATCH 47/91] fix pagination issue --- .../CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 | 8 ++++---- SendStats/run.ps1 | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index ebf491cec05a..9828682c6348 100644 --- a/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -267,7 +267,7 @@ function Invoke-NinjaOneTenantSync { @{ id = 'Users' method = 'GET' - url = '/users' + url = '/users?$top=999' }, @{ id = 'TenantDetails' @@ -292,7 +292,7 @@ function Invoke-NinjaOneTenantSync { @{ id = 'Devices' method = 'GET' - url = '/deviceManagement/managedDevices' + url = '/deviceManagement/managedDevices?$top=999' }, @{ id = 'DeviceCompliancePolicies' @@ -317,12 +317,12 @@ function Invoke-NinjaOneTenantSync { @{ id = 'SecureScore' method = 'GET' - url = '/security/secureScores' + url = '/security/secureScores?$top=999' }, @{ id = 'SecureScoreControlProfiles' method = 'GET' - url = '/security/secureScoreControlProfiles' + url = '/security/secureScoreControlProfiles?$top=999' }, @{ id = 'Subscriptions' diff --git a/SendStats/run.ps1 b/SendStats/run.ps1 index b4427d230338..2e30b113ab55 100644 --- a/SendStats/run.ps1 +++ b/SendStats/run.ps1 @@ -17,6 +17,7 @@ $SendingObject = [PSCustomObject]@{ SetupComplete = $SetupComplete RunningVersionAPI = $APIVersion.trim() CountOfTotalTenants = $tenantcount + uid = $env:TenantID } | ConvertTo-Json Invoke-RestMethod -Uri 'https://management.cipp.app/api/stats' -Method POST -Body $SendingObject -ContentType 'application/json' \ No newline at end of file From b5cbb59c116b577cf1fe9a3f3887d84dc3463897 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:27:42 +0200 Subject: [PATCH 48/91] fixes ninja bug --- Modules/CippExtensions/Public/Get-ExtensionRateLimit.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/CippExtensions/Public/Get-ExtensionRateLimit.ps1 b/Modules/CippExtensions/Public/Get-ExtensionRateLimit.ps1 index 2a0e718402f4..242d4dd86390 100644 --- a/Modules/CippExtensions/Public/Get-ExtensionRateLimit.ps1 +++ b/Modules/CippExtensions/Public/Get-ExtensionRateLimit.ps1 @@ -24,7 +24,6 @@ function Get-ExtensionRateLimit($ExtensionName, $ExtensionPartitionKey, $RateLim } if (($ActiveJobs | Measure-Object).count -ge $RateLimit) { Write-Host "Rate Limiting. Currently $($ActiveJobs.count) Active Jobs" - Start-Sleep -Seconds $WaitTime $CurrentMap = Get-ExtensionRateLimit -ExtensionName $ExtensionName -ExtensionPartitionKey $ExtensionPartitionKey -RateLimit $RateLimit -WaitTime $WaitTime } From a89f3700cfd51023d43ed0de68b6c80dbec821c0 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 14:59:43 +0200 Subject: [PATCH 49/91] version up --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index edb1d397cf28..a94a88fbb889 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.8.0 \ No newline at end of file +5.8.5 \ No newline at end of file From 79a21a9a0c25a36ab8e62219a63a885513c802ef Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 15:27:54 +0200 Subject: [PATCH 50/91] final touches prerelease --- Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 4 ++-- .../Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index 9b32fb178747..6c2d544dcfd9 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -34,7 +34,7 @@ function Set-CIPPPerUserMFA { try { $int = 0 $Body = @{ - state = $State + perUserMFAstate = $State } $Requests = foreach ($id in $userId) { @{ @@ -47,7 +47,7 @@ function Set-CIPPPerUserMFA { } } } - $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true + $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) "Successfully set Per user MFA State for $userId" $Users = foreach ($id in $userId) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 index 9ecd363c44a3..c83204529423 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 @@ -19,7 +19,7 @@ function Invoke-CIPPStandardPerUserMFA { If ($Settings.remediate -eq $true) { if ($UsersWithoutMFA) { try { - $MFAMessage = Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $UsersWithoutMFA.UserPrincipalName -State 'Enforced' + $MFAMessage = Set-CIPPPeruserMFA -TenantFilter $Tenant -UserId $UsersWithoutMFA.UserPrincipalName -State 'enforced' Write-LogMessage -API 'Standards' -tenant $tenant -message $MFAMessage -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message From 693c3ac255686fac62e309faa221d6dcb7c5d6bc Mon Sep 17 00:00:00 2001 From: Jr7468 Date: Tue, 18 Jun 2024 13:35:32 +0100 Subject: [PATCH 51/91] Added anchor to EXO Cmdlet --- .../Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 index 9112981dad14..fbbe6c93bdd2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 @@ -17,9 +17,9 @@ Function Invoke-ListCalendarPermissions { try { $GetCalParam = @{Identity = $UserID; FolderScope = 'Calendar' } - $CalendarFolder = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderStatistics' -cmdParams $GetCalParam | Select-Object -First 1 + $CalendarFolder = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderStatistics' -anchor $UserID -cmdParams $GetCalParam | Select-Object -First 1 $CalParam = @{Identity = "$($UserID):\$($CalendarFolder.name)" } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderPermission' -cmdParams $CalParam -UseSystemMailbox $true | Select-Object Identity, User, AccessRights, FolderName + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderPermission' -anchor $UserID -cmdParams $CalParam -UseSystemMailbox $true | Select-Object Identity, User, AccessRights, FolderName Write-LogMessage -API 'List Calendar Permissions' -tenant $tenantfilter -message "Calendar permissions listed for $($tenantfilter)" -sev Debug $StatusCode = [HttpStatusCode]::OK } catch { From eb578d98c217761d7d7016986dae345f92c8ad99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 18 Jun 2024 20:04:02 +0200 Subject: [PATCH 52/91] Add blocking of sign-in for new mailboxes --- .../Invoke-AddSharedMailbox.ps1 | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 index 20af9ebdd475..a786671ec4a4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 @@ -16,46 +16,59 @@ Function Invoke-AddSharedMailbox { Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Results = [System.Collections.ArrayList]@() - $groupobj = $Request.body - $Aliases = $groupobj.addedAliases -Split '\n' + $MailboxObject = $Request.body + $Aliases = $MailboxObject.addedAliases -Split '\n' # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' try { - $Email = "$($groupobj.username)@$($groupobj.domain)" - $BodyToship = [pscustomobject] @{ - 'displayName' = $groupobj.Displayname - 'name' = $groupobj.username + $Email = "$($MailboxObject.username)@$($MailboxObject.domain)" + $BodyToShip = [pscustomobject] @{ + 'displayName' = $MailboxObject.Displayname + 'name' = $MailboxObject.username 'primarySMTPAddress' = $Email Shared = $true } - $AddSharedRequest = New-ExoRequest -tenantid $groupobj.tenantid -cmdlet 'New-Mailbox' -cmdparams $BodyToship + $AddSharedRequest = New-ExoRequest -tenantid $MailboxObject.tenantid -cmdlet 'New-Mailbox' -cmdparams $BodyToShip $Body = $Results.add("Successfully created shared mailbox: $Email.") - Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Created shared mailbox $($groupobj.displayname) with email $Email" -Sev 'Info' + Write-LogMessage -user $User -API $APINAME -tenant $($MailboxObject.tenantid) -message "Created shared mailbox $($MailboxObject.displayname) with email $Email" -Sev 'Info' } catch { - Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to create shared mailbox. Error: $($_.Exception.Message)" -Sev 'Error' - $Body = $Results.add("Failed to create Shared Mailbox. $($_.Exception.Message)") + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -user $User -API $APINAME -tenant $($MailboxObject.tenantid) -message "Failed to create shared mailbox. Error: $ErrorMessage" -Sev 'Error' + $Body = $Results.add("Failed to create Shared Mailbox. $ErrorMessage") } + # Block sign-in for the mailbox try { - if ($Aliases) { + $null = Set-CIPPSignInState -userid $AddSharedRequest.ExternalDirectoryObjectId -TenantFilter $($MailboxObject.tenantid) -APIName $APINAME -ExecutingUser $User -AccountEnabled $false + Write-LogMessage -user $User -API $APINAME -tenant $($MailboxObject.tenantid) -message "Blocked sign-in for shared mailbox $Email" -Sev 'Info' + $Body = $Results.add("Blocked sign-in for shared mailbox $Email") + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -user $User -API $APINAME -tenant $($MailboxObject.tenantid) -message "Failed to block sign-in for shared mailbox $Email. Error: $ErrorMessage" -Sev 'Error' + $Body = $Results.add("Failed to block sign-in for shared mailbox $Email. Error: $ErrorMessage") + } + # Add aliases to the mailbox if any are provided + if ($Aliases) { + try { Start-Sleep 3 # Sleep since there is apparently a race condition with the mailbox creation if we don't delay for a lil bit $AliasBodyToShip = [pscustomobject] @{ 'Identity' = $AddSharedRequest.Guid 'EmailAddresses' = @{'@odata.type' = '#Exchange.GenericHashTable'; Add = $Aliases } } - $AliasBodyToShip - New-ExoRequest -tenantid $groupobj.tenantid -cmdlet 'Set-Mailbox' -cmdparams $AliasBodyToShip -UseSystemMailbox $true - Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Added aliases to $Email : $($Aliases -join ',')" -Sev 'Info' + $null = New-ExoRequest -tenantid $MailboxObject.tenantid -cmdlet 'Set-Mailbox' -cmdparams $AliasBodyToShip -UseSystemMailbox $true + Write-LogMessage -user $User -API $APINAME -tenant $($MailboxObject.tenantid) -message "Added aliases to $Email : $($Aliases -join ',')" -Sev 'Info' $Body = $results.add("Added Aliases to $Email : $($Aliases -join ',')") + + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -user $User -API $APINAME -tenant $($MailboxObject.tenantid) -message "Failed to add aliases to $Email : $ErrorMessage" -Sev 'Error' + $Body = $results.add("ERROR: Failed to add aliases to $Email : $ErrorMessage") } - } catch { - Write-LogMessage -user $User -API $APINAME -tenant $($groupobj.tenantid) -message "Failed to add aliases to $Email : $($_.Exception.Message)" -Sev 'Error' - $Body = $results.add("ERROR: Failed to add aliases to $Email : $($_.Exception.Message)") } $Body = [pscustomobject] @{ 'Results' = @($results) } From cd9283853ad7188192ff01d7ac4c9f1ed29381c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 18 Jun 2024 20:05:00 +0200 Subject: [PATCH 53/91] Some cleanup and change to use Get-NormalizedError --- .../Users/Invoke-ExecDisableUser.ps1 | 4 ++-- Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 index 69ac4dd83ec8..b5b80a86d7c8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 @@ -12,11 +12,11 @@ Function Invoke-ExecDisableUser { $APIName = $TriggerMetadata.FunctionName try { - ([System.Convert]::ToBoolean($Request.Query.Enable)) $State = Set-CIPPSignInState -userid $Request.query.ID -TenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -AccountEnabled ([System.Convert]::ToBoolean($Request.Query.Enable)) $Results = [pscustomobject]@{'Results' = "$State" } } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Results = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 index ea26d3d309ed..4c99b82c84df 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 @@ -1,7 +1,7 @@ function Set-CIPPSignInState { [CmdletBinding()] param ( - $userid, + $UserId, [bool]$AccountEnabled, $TenantFilter, $APIName = 'Disable User Sign-in', @@ -11,13 +11,14 @@ function Set-CIPPSignInState { try { $body = @{ accountEnabled = [bool]$AccountEnabled - } | ConvertTo-Json -Compress -Depth 1 - $SignInState = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $body -verbose - Write-LogMessage -user $ExecutingUser -API $APIName -message "Set account enabled state to $AccountEnabled for $userid" -Sev 'Info' -tenant $TenantFilter - return "Set account enabled state to $AccountEnabled for $userid" + } + $body = ConvertTo-Json -InputObject $body -Compress -Depth 5 + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)" -tenantid $TenantFilter -type PATCH -body $body -verbose + Write-LogMessage -user $ExecutingUser -API $APIName -message "Set account enabled state to $AccountEnabled for $UserId" -Sev 'Info' -tenant $TenantFilter + return "Set account enabled state to $AccountEnabled for $UserId" } catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not disable sign in for $userid. Error: $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter - return "Could not disable $userid. Error: $($_.Exception.Message)" + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not disable sign in for $UserId. Error: $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + return "Could not disable $UserId. Error: $($_.Exception.Message)" } } From afc6e7868331d99cca411eb2b48dc0417715bb64 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Wed, 19 Jun 2024 09:14:18 +0100 Subject: [PATCH 54/91] Update Invoke-ExecRevokeSessions.ps1 Fixed missing username from logbook when revoking sessions --- .../Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 index 5c5c56fe568f..a17b40139b05 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 @@ -16,7 +16,7 @@ Function Invoke-ExecRevokeSessions { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter try { - $RevokeSessions = Revoke-CIPPSessions -userid $Request.Query.id -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $RevokeSessions = Revoke-CIPPSessions -userid $Request.Query.id -tenantFilter $TenantFilter -username $Request.Query.Username -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' $Results = [pscustomobject]@{'Results' = $RevokeSessions } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } From 768b137654160001050e235abcf0c211683ab86d Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Wed, 19 Jun 2024 17:07:00 +0100 Subject: [PATCH 55/91] Renamed Functions Changed: ExecSharePointOwner to: ExecSharePointPerms and Set-CIPPSharePointOwner to Set-CIPPSharePointPerms --- .../Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 | 4 ++-- Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 | 2 +- Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 index 542dfb665b9f..347a5e5721bd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecSharePointOwner { +Function Invoke-ExecSharePointPerms { <# .FUNCTIONALITY Entrypoint @@ -13,7 +13,7 @@ Function Invoke-ExecSharePointOwner { $APIName = $TriggerMetadata.FunctionName $tenantFilter = $Request.Body.TenantFilter try { - $State = Set-CIPPSharePointOwner -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission -URL $Request.Body.URL + $State = Set-CIPPSharePointPerms -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission -URL $Request.Body.URL $Results = [pscustomobject]@{'Results' = "$State" } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 index 533d0954679a..e051a2a0144b 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 @@ -36,7 +36,7 @@ function Invoke-CIPPOffboardingJob { } { $_.'OnedriveAccess' -ne '' } { - $Options.OnedriveAccess | ForEach-Object { Set-CIPPSharePointOwner -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -ExecutingUser $ExecutingUser -APIName $APIName } + $Options.OnedriveAccess | ForEach-Object { Set-CIPPSharePointPerms -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -ExecutingUser $ExecutingUser -APIName $APIName } } { $_.'AccessNoAutomap' -ne '' } { diff --git a/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 index 3acdfc3d314f..1ee26318b465 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 @@ -1,4 +1,4 @@ -function Set-CIPPSharePointOwner { +function Set-CIPPSharePointPerms { [CmdletBinding()] param ( $userid, From 679e21b38fa767cf49e9c69237af4e724118a3c0 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Wed, 19 Jun 2024 17:40:23 +0100 Subject: [PATCH 56/91] Changed File Names ExecSharePointOwner to ExecSharePointPerms Set-CIPPSharePointOwner to Set-CIPPSharePointPerms --- ...oke-ExecSharePointOwner.ps1 => Invoke-ExecSharePointPerms.ps1} | 0 .../{Set-CIPPSharePointOwner.ps1 => Set-CIPPSharePointPerms.ps1} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/{Invoke-ExecSharePointOwner.ps1 => Invoke-ExecSharePointPerms.ps1} (100%) rename Modules/CIPPCore/Public/{Set-CIPPSharePointOwner.ps1 => Set-CIPPSharePointPerms.ps1} (100%) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointPerms.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointOwner.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointPerms.ps1 diff --git a/Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Set-CIPPSharePointOwner.ps1 rename to Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 From 9bd6d1f3598829585435a0ffc136ea197d78e392 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 19 Jun 2024 12:42:34 -0400 Subject: [PATCH 57/91] Make role lowercase --- .../HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 index a1e92d2c3f89..c5725a2cafb8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 @@ -14,7 +14,7 @@ function Invoke-ExecCustomRole { Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API 'ExecCustomRole' -message "Saved custom role $($Request.Body.RoleName)" -Sev 'Info' $Role = @{ 'PartitionKey' = 'CustomRoles' - 'RowKey' = "$($Request.Body.RoleName)" + 'RowKey' = "$($Request.Body.RoleName.ToLower())" 'Permissions' = "$($Request.Body.Permissions | ConvertTo-Json -Compress)" 'AllowedTenants' = "$($Request.Body.AllowedTenants | ConvertTo-Json -Compress)" 'BlockedTenants' = "$($Request.Body.BlockedTenants | ConvertTo-Json -Compress)" From 6af915e0e70107ae487046e39f2c1b6333611e8e Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Wed, 19 Jun 2024 22:29:52 +0100 Subject: [PATCH 58/91] Update Invoke-EditGroup.ps1 Moved AllowExternalSenders to use the pre existing function Set-CIPPGroupAuthentication --- .../Administration/Groups/Invoke-EditGroup.ps1 | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 index 122c4f118739..9deb382c2d85 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 @@ -130,19 +130,11 @@ Function Invoke-EditGroup { if ($userobj.allowExternal -eq 'true') { try { - if ($userobj.groupType -eq 'Distribution list') { - $Params = @{ Identity = $userobj.groupid; RequireSenderAuthenticationEnabled = $false } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Set-DistributionGroup' -cmdParams $params - } else { - $Params = @{ Identity = $userobj.groupid; RequireSenderAuthenticationEnabled = $false } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Set-UnifiedGroup' -cmdParams $params - } - $body = $results.add("Allowed external senders to send to $($userobj.groupName).") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Allowed external senders to send to $($userobj.groupName)" -Sev 'Info' - + Set-CIPPGroupAuthentication -ID $userobj.mail -GroupType $userobj.groupType -tenantFilter $Userobj.tenantid -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $body = $results.add("Allowed external senders to send to $($userobj.mail).") } catch { - $body = $results.add("Failed to allow external senders to send to $($userobj.groupName).") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to allow external senders for $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' + $body = $results.add("Failed to allow external senders to send to $($userobj.mail).") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to allow external senders for $($userobj.mail). Error:$($_.Exception.Message)" -Sev 'Error' } } From 239e215853965c8a766dbd3caeaa748bac114107 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 19 Jun 2024 21:59:25 -0400 Subject: [PATCH 59/91] JIT tweaks --- .../Users/Invoke-ExecJITAdmin.ps1 | 40 ++++++++++++++++++- .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 20 ++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 index 1c1c575a598f..d2d5839c2c9c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -21,7 +21,7 @@ Function Invoke-ExecJITAdmin { Endpoint = 'users' Parameters = @{ '$count' = 'true' - '$select' = "id,displayName,userPrincipalName,$($Schema.id)" + '$select' = "id,accountEnabled,displayName,userPrincipalName,$($Schema.id)" '$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false" } } @@ -42,6 +42,7 @@ Function Invoke-ExecJITAdmin { id = $_.id displayName = $_.displayName userPrincipalName = $_.userPrincipalName + accountEnabled = $_.accountEnabled jitAdminEnabled = $_.($Schema.id).jitAdminEnabled jitAdminExpiration = $_.($Schema.id).jitAdminExpiration memberOf = $MemberOf @@ -81,9 +82,44 @@ Function Invoke-ExecJITAdmin { $CreateResult = Set-CIPPUserJITAdmin @JITAdmin $Username = $CreateResult.userPrincipalName $Results.Add("Created User: $($CreateResult.userPrincipalName)") - $Results.Add("Password: $($CreateResult.password)") + if (!$Request.Body.UseTAP) { + $Results.Add("Password: $($CreateResult.password)") + } + $Results.Add("JIT Expires: $($Expiration)") Start-Sleep -Seconds 1 } + + if ($Request.Body.UseTAP) { + try { + if ($Start -gt (Get-Date)) { + $TapParams = @{ + startDateTime = [System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.StartDate).DateTime + } + $TapBody = ConvertTo-Json -Depth 5 -InputObject $TapParams + } else { + $TapBody = '{}' + } + Write-Information "https://graph.microsoft.com/beta/users/$Username/authentication/temporaryAccessPassMethods" + $TapRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($Username)/authentication/temporaryAccessPassMethods" -tenantid $Request.Body.TenantFilter -type POST -body $TapBody + + $TempPass = $TapRequest.temporaryAccessPass + $PasswordExpiration = $TapRequest.LifetimeInMinutes + + $PasswordLink = New-PwPushLink -Payload $TempPass + if ($PasswordLink) { + $Password = $PasswordLink + } + $Results.Add("Temporary Access Pass: $Password") + $Results.Add("This TAP is usable starting at $($TapRequest.startDateTime) UTC for the next $PasswordExpiration minutes") + } catch { + $Results.Add('Failed to create TAP, if this is not yet enabled, use the Standards to push the settings to the tenant.') + Write-Information (Get-CippException -Exception $_ | ConvertTo-Json -Depth 5) + if ($Password) { + $Results.Add("Password: $Password") + } + } + } + $Parameters = @{ TenantFilter = $Request.Body.TenantFilter User = @{ diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 692b6c4828ef..e25bf6443acd 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -91,6 +91,17 @@ function Set-CIPPUserJITAdmin { $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/`$ref" -tenantid $TenantFilter -body $Json -ErrorAction SilentlyContinue } catch {} } + $UserEnabled = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)?`$select=accountEnabled" -tenantid $TenantFilter).accountEnabled + if (-not $UserEnabled) { + $Body = @{ + accountEnabled = $true + } + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + try { + New-GraphPOSTRequest -type PATCH -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $TenantFilter -body $Json | Out-Null + } catch {} + } + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration | Out-Null return "Added admin roles to user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } @@ -115,10 +126,13 @@ function Set-CIPPUserJITAdmin { $Body = @{ accountEnabled = $false } - $Json = ConvertTo-Json -Depth 5 -InputObject $Body + $Json = ConvertTo-Json -Depth 5 -InputObject $Body -Compress try { - New-GraphPOSTRequest -type PATCH -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $TenantFilter -body $Json - Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled:$false | Out-Null + Write-Information "Disabling user $($UserObj.displayName) ($($User.UserPrincipalName))" + Write-Information $Json + Write-Information "https://graph.microsoft.com/beta/users/$($User.UserPrincipalName)" + $null = New-GraphPOSTRequest -type PATCH -uri "https://graph.microsoft.com/beta/users/$($User.UserPrincipalName)" -tenantid $TenantFilter -body $Json + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $User.UserPrincipalName -Clear | Out-Null return "Disabled user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } catch { return "Error disabling user $($UserObj.displayName) ($($UserObj.userPrincipalName)): $($_.Exception.Message)" From c2226304d8b3d4708621e5841aaadd7c18aa33dc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 20 Jun 2024 14:14:38 -0400 Subject: [PATCH 60/91] Quota alert fixes --- .../Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 | 12 ++++++++++-- .../Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 index 32b63925c02a..5d6a4faf5bd8 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 @@ -17,9 +17,17 @@ function Get-CIPPAlertQuotaUsed { return } $AlertData | ForEach-Object { - if ($_.StorageUsedInBytes -eq 0) { return } + if ($_.StorageUsedInBytes -eq 0 -or $_.prohibitSendReceiveQuotaInBytes -eq 0) { return } $PercentLeft = [math]::round(($_.storageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes) * 100) - if ($InputValue) { $Value = [int]$InputValue } else { $Value = 90 } + try { + if ([int]$InputValue -gt 0) { + $Value = [int]$InputValue + } else { + $Value = 90 + } + } catch { + $Value = 90 + } if ($PercentLeft -gt $Value) { "$($_.userPrincipalName): Mailbox is more than $($value)% full. Mailbox is $PercentLeft% full" } diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 index 4cb04042f495..abc609cbd53a 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 @@ -20,7 +20,11 @@ function Get-CIPPAlertSharepointQuota { return } if ($sharepointQuota) { - if ($InputValue -Is [Boolean]) { $Value = 90 } else { $Value = $InputValue } + try { + if ([int]$InputValue -gt 0) { $Value = [int]$InputValue } else { $Value = 90 } + } catch { + $Value = 90 + } $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) if ($UsedStoragePercentage -gt $Value) { $AlertData = "SharePoint Storage is at $($UsedStoragePercentage)%. Your alert threshold is $($Value)%" From 3d2b48affc363aba6d67dce53da4050bbd40d962 Mon Sep 17 00:00:00 2001 From: BNWEIN Date: Thu, 20 Jun 2024 22:54:31 +0100 Subject: [PATCH 61/91] Delete .github/workflows/dev_cippvh5nk.yml --- .github/workflows/dev_cippvh5nk.yml | 30 ----------------------------- 1 file changed, 30 deletions(-) delete mode 100644 .github/workflows/dev_cippvh5nk.yml diff --git a/.github/workflows/dev_cippvh5nk.yml b/.github/workflows/dev_cippvh5nk.yml deleted file mode 100644 index dbe0410fb709..000000000000 --- a/.github/workflows/dev_cippvh5nk.yml +++ /dev/null @@ -1,30 +0,0 @@ -# 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 - cippvh5nk - -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: 'cippvh5nk' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_AF29E35A0BA344B1A163D7A38F78191D }} \ No newline at end of file From 53f0d9824e991fdfed4f9bfce212e9875ed91aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Bentsen=20Kj=C3=A6rg=C3=A5rd=20=28KBK=29?= Date: Fri, 21 Jun 2024 09:59:54 +0200 Subject: [PATCH 62/91] Change exits to returns --- .../Invoke-CIPPStandardActivityBasedTimeout.ps1 | 2 +- .../Public/Standards/Invoke-CIPPStandardBookings.ps1 | 2 +- .../Invoke-CIPPStandardCloudMessageRecall.ps1 | 2 +- .../Standards/Invoke-CIPPStandardDisableViva.ps1 | 2 +- .../Standards/Invoke-CIPPStandardEnablePronouns.ps1 | 2 +- .../Invoke-CIPPStandardExternalMFATrusted.ps1 | 2 +- .../Standards/Invoke-CIPPStandardFocusedInbox.ps1 | 2 +- ...nvoke-CIPPStandardGlobalQuarantineNotifications.ps1 | 4 ++-- .../Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 | 4 ++-- .../Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 | 2 +- .../Invoke-CIPPStandardSendReceiveLimitTenant.ps1 | 4 ++-- .../Standards/Invoke-CIPPStandardShortenMeetings.ps1 | 10 +++++----- .../Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 | 4 ++-- .../Public/Standards/Invoke-CIPPStandardTAP.ps1 | 2 +- .../Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 | 2 +- .../Invoke-CIPPStandardTenantDefaultTimezone.ps1 | 2 +- .../Standards/Invoke-CIPPStandardUserSubmissions.ps1 | 2 +- .../Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 | 2 +- .../Public/Standards/Invoke-CIPPStandardcalDefault.ps1 | 2 +- .../Standards/Invoke-CIPPStandardsharingCapability.ps1 | 2 +- 20 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 index e0c0ff5031a7..cf03f748d032 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardActivityBasedTimeout { # Input validation if ([string]::isNullOrEmpty($Settings.timeout) -or $Settings.timeout -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ActivityBasedTimeout: Invalid timeout parameter set' -sev Error - Exit + Return } # Backwards compatibility for v5.7.0 and older diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 index 4ba2c72e57cc..c60e23d3acd1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardBookings { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'BookingsEnabled: Invalid state parameter set' -sev Error - Exit + Return } $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').BookingsEnabled diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 index b09f91554f3b..446056aee5be 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardCloudMessageRecall { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'MessageRecallEnabled: Invalid state parameter set' -sev Error - Exit + Return } $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').MessageRecallEnabled diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 index 0b790cfd9581..57673d0d7fb0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 @@ -10,7 +10,7 @@ function Invoke-CIPPStandardDisableViva { } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to get Viva insights settings. Error: $ErrorMessage" -sev Error - Exit + Return } If ($Settings.remediate -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 index 873d52976ff7..bd4d6c85e70e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 @@ -11,7 +11,7 @@ function Invoke-CIPPStandardEnablePronouns { } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not get CurrentState for Pronouns. Error: $ErrorMessage" -sev Error - Exit + Return } Write-Host $CurrentState diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 index 2ae91ffae326..fd3b2e0fec99 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardExternalMFATrusted { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error - Exit + Return } $ExternalMFATrusted = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default?$select=inboundTrust' -tenantid $Tenant) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index b14040073120..e1f80e8df02e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardFocusedInbox { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error - Exit + Return } $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').FocusedInboxOn diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 index 4d2bb6e9b039..c067e350f6b1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 @@ -5,13 +5,13 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { #> param ($Tenant, $Settings) - # Exit if invalid state in the frontend is selected + # Input validation try { $WantedState = [timespan]$Settings.NotificationInterval } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -tenant $Tenant -message "Invalid state selected for Global Quarantine Notifications. Error: $ErrorMessage" -sev Error - Exit + Return } $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-QuarantinePolicy' -cmdParams @{ QuarantinePolicyType = 'GlobalQuarantinePolicy' } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index 2263412053ee..ffbedce078b5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -8,12 +8,12 @@ function Invoke-CIPPStandardNudgeMFA { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid state parameter set' -sev Error - Exit + Return } # Input validation if ($Settings.snoozeDurationInDays -lt 0 -or $Settings.snoozeDurationInDays -gt 15) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid snoozeDurationInDays parameter set' -sev Error - Exit + Return } $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $Tenant diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 index 3a2175f65c2d..4528d789539e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'PWcompanionAppAllowedState: Invalid state parameter set' -sev Error - Exit + Return } $authenticatorFeaturesState = (New-GraphGetRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type GET) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 index 822471d17466..68c7519f5e25 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 @@ -8,13 +8,13 @@ function Invoke-CIPPStandardSendReceiveLimitTenant { # Input validation if ($Settings.SendLimit -lt 1 -or $Settings.SendLimit -gt 150) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'SendReceiveLimitTenant: Invalid SendLimit parameter set' -sev Error - Exit + Return } # Input validation if ($Settings.ReceiveLimit -lt 1 -or $Settings.ReceiveLimit -gt 150) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'SendReceiveLimitTenant: Invalid ReceiveLimit parameter set' -sev Error - Exit + Return } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 index 4946b64e8b4b..f6605904777f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 @@ -8,17 +8,17 @@ function Invoke-CIPPStandardShortenMeetings { # Input validation if ([Int32]$Settings.DefaultMinutesToReduceShortEventsBy -lt 0 -or [Int32]$Settings.DefaultMinutesToReduceShortEventsBy -gt 29) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Invalid shorten meetings settings specified. DefaultMinutesToReduceShortEventsBy must be an integer between 0 and 29' -sev Error - Exit + Return } if ([Int32]$Settings.DefaultMinutesToReduceLongEventsBy -lt 0 -or [Int32]$Settings.DefaultMinutesToReduceLongEventsBy -gt 29) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Invalid shorten meetings settings specified. DefaultMinutesToReduceLongEventsBy must be an integer between 0 and 29' -sev Error - Exit + Return } - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' | + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' | Select-Object -Property ShortenEventScopeDefault, DefaultMinutesToReduceShortEventsBy, DefaultMinutesToReduceLongEventsBy - $CorrectState = if ($CurrentState.ShortenEventScopeDefault -eq $Settings.ShortenEventScopeDefault -and - $CurrentState.DefaultMinutesToReduceShortEventsBy -eq $Settings.DefaultMinutesToReduceShortEventsBy -and + $CorrectState = if ($CurrentState.ShortenEventScopeDefault -eq $Settings.ShortenEventScopeDefault -and + $CurrentState.DefaultMinutesToReduceShortEventsBy -eq $Settings.DefaultMinutesToReduceShortEventsBy -and $CurrentState.DefaultMinutesToReduceLongEventsBy -eq $Settings.DefaultMinutesToReduceLongEventsBy) { $true } else { $false } if ($Settings.remediate -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index 9f10326925af..b9ead2f3e0b9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardSpoofWarn { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'SpoofWarn: Invalid state parameter set' -sev Error - Exit + Return } $CurrentInfo = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ExternalInOutlook') @@ -17,7 +17,7 @@ function Invoke-CIPPStandardSpoofWarn { $status = if ($Settings.enable -and $Settings.disable) { # Handle legacy settings when this was 2 separate standards Write-LogMessage -API 'Standards' -tenant $tenant -message 'You cannot both enable and disable the Spoof Warnings setting' -sev Error - Exit + Return } elseif ($Settings.state -eq 'enabled' -or $Settings.enable) { $true } else { $false } if ($CurrentInfo.Enabled -eq $status) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 index c627e055f36b..aaed774d7dcf 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardTAP { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'TAP: Invalid state parameter set' -sev Error - Exit + Return } $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass' -tenantid $Tenant diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 676db45e78ff..3054bac5f2ce 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'TeamsMeetingsByDefault: Invalid state parameter set' -sev Error - Exit + Return } $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').OnlineMeetingsByDefaultEnabled diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 index e26119fca311..4427c31986d5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 @@ -9,7 +9,7 @@ function Invoke-CIPPStandardTenantDefaultTimezone { # Input validation if ([string]::isNullOrEmpty($Settings.Timezone) -or $Settings.Timezone -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'TenantDefaultTimezone: Invalid Timezone parameter set' -sev Error - Exit + Return } $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index b4e66edb49dd..d0759ecb4a22 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardUserSubmissions { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'UserSubmissions: Invalid state parameter set' -sev Error - Exit + Return } $Policy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ReportSubmissionPolicy' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 index e9498ee706ac..36afc500320a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardallowOAuthTokens { # Input validation if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'allowOAuthTokens: Invalid state parameter set' -sev Error - Exit + Return } $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/softwareOath' -tenantid $Tenant diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 index 9b6782f5ad30..e9f95984fc9f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardcalDefault { # Input validation if ([string]::isNullOrEmpty($Settings.permissionlevel) -or $Settings.permissionlevel -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'calDefault: Invalid permissionlevel parameter set' -sev Error - Exit + Return } If ($Settings.remediate -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index effaf7743996..c733398f2b26 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardsharingCapability { # Input validation if ([string]::isNullOrEmpty($Settings.sharingCapability) -or $Settings.sharingCapability -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'sharingCapability: Invalid sharingCapability parameter set' -sev Error - Exit + Return } $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true From 305e67c016b5866907088344af19cccd77ec2a65 Mon Sep 17 00:00:00 2001 From: Chris Brannon Date: Fri, 21 Jun 2024 09:05:36 -0400 Subject: [PATCH 63/91] SharePoint Admin URL Fix --- .../CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 | 2 +- .../Public/Entrypoints/Invoke-ListSharepointQuota.ps1 | 2 +- Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 | 4 ++-- .../Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 index abc609cbd53a..e8cefb6d0bd2 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 @@ -12,7 +12,7 @@ function Get-CIPPAlertSharepointQuota { $TenantFilter ) Try { - $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Where-Object { $_.isInitial -eq $true }).id.Split('.')[0] + $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/root' -tenantid $TenantFilter).id.Split('.')[0] $sharepointToken = (Get-GraphToken -scope "https://$($tenantName)-admin.sharepoint.com/.default" -tenantid $TenantFilter) $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 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 index b8d7d8a50995..21d521629abc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 @@ -23,7 +23,7 @@ Function Invoke-ListSharepointQuota { $UsedStoragePercentage = 'Not Supported' } else { try { - $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Where-Object { $_.isInitial -eq $true }).id.Split('.')[0] + $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/root' -tenantid $TenantFilter).id.Split('.')[0] $sharepointToken = (Get-GraphToken -scope "https://$($tenantName)-admin.sharepoint.com/.default" -tenantid $TenantFilter) $sharepointToken.Add('accept', 'application/json') diff --git a/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 index 1ee26318b465..ab447f685994 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 @@ -19,8 +19,8 @@ function Set-CIPPSharePointPerms { if (!$URL) { $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)/Drives" -asapp $true -tenantid $TenantFilter).WebUrl } - $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $TenantFilter | Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 - $AdminUrl = "https://$($OnMicrosoft)-admin.sharepoint.com" + $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/root' -tenantid $TenantFilter).id.Split('.')[0] + $AdminUrl = "https://$($tenantName)-admin.sharepoint.com" $XML = @" diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 index d080ca55f0c5..dec70bd076ec 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 @@ -60,9 +60,8 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive { } try { - $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenant | - Where-Object -Property isInitial -EQ $true).id.split('.') | Select-Object -First 1 - $AdminUrl = "https://$($OnMicrosoft)-admin.sharepoint.com" + $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/root' -tenantid $TenantFilter).id.Split('.')[0] + $AdminUrl = "https://$($tenantName)-admin.sharepoint.com" $graphRequest = @{ 'scope' = "$AdminURL/.default" 'tenantid' = $tenant From 5896f2fe806e539025b09fa50fc0e48a4f85ad85 Mon Sep 17 00:00:00 2001 From: kakaiwa Date: Fri, 21 Jun 2024 11:24:29 -0400 Subject: [PATCH 64/91] Updated Invoke-AddSpamFilter.ps1 to automatically set priority to 0 --- .../HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 | 1 + package-lock.json | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 package-lock.json diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 index deb78b344897..30417b9b6e78 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 @@ -26,6 +26,7 @@ Function Invoke-AddSpamFilter { 'hostedcontentfilterpolicy' = "$($RequestParams.name)" 'recipientdomainis' = @($domains) 'Enabled' = $true + 'Priority' = 0 } $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-HostedContentFilterRule' -cmdParams $ruleparams "Successfully created spamfilter for $tenantfilter." diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000000..9c41ecf7e309 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "CIPP-API", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From da4d517e0c5bffcc43a347bc16d206d188c68eb0 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 21 Jun 2024 13:58:19 -0400 Subject: [PATCH 65/91] Sign in report tweaks --- .../Public/Entrypoints/Invoke-ListSignIns.ps1 | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 index b58f472a7494..5547efe9cfd2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 @@ -16,27 +16,32 @@ Function Invoke-ListSignIns { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter + $Days = $Request.Query.Days ?? 7 + try { - if ($Request.query.failedlogonOnly) { + if ($Request.Query.failedLogonsOnly) { $FailedLogons = ' and (status/errorCode eq 50126)' } - $filters = if ($Request.query.Filter) { - $request.query.filter + $filters = if ($Request.Query.Filter) { + $Request.Query.filter } else { - $currentTime = Get-Date -Format 'yyyy-MM-dd' - $ts = (Get-Date).AddDays(-7) + $ts = (Get-Date).AddDays(-$Days).ToUniversalTime() $endTime = $ts.ToString('yyyy-MM-dd') - "createdDateTime ge $($endTime) and createdDateTime lt $($currentTime) and userDisplayName ne 'On-Premises Directory Synchronization Service Account' $FailedLogons" + "createdDateTime ge $($endTime) and userDisplayName ne 'On-Premises Directory Synchronization Service Account' $FailedLogons" } Write-Host $Filters + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved sign in report' -Sev 'Debug' -tenant $TenantFilter $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&`$filter=$($filters)" -tenantid $TenantFilter -erroraction stop $response = $GraphRequest | Select-Object *, @{l = 'additionalDetails'; e = { $_.status.additionalDetails } } , @{l = 'errorCode'; e = { $_.status.errorCode } }, @{l = 'locationcipp'; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved sign in report' -Sev 'Debug' -tenant $TenantFilter + + if ($Request.Query.failedLogonsOnly -and $Request.Query.FailureThreshold -and $Request.Query.FailureThreshold -gt 0) { + $response = $response | Group-Object -Property userPrincipalName | Where-Object { $_.Count -ge $Request.Query.FailureThreshold } | Select-Object -ExpandProperty Group + } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ From b4a8039456454fed485db6fb16a24eaa021e6006 Mon Sep 17 00:00:00 2001 From: cipptesting Date: Fri, 21 Jun 2024 14:05:51 -0400 Subject: [PATCH 66/91] Updated Invoke-AddSpamFilter.ps1. Made priority configurable --- .../HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 index 30417b9b6e78..a27660da63c5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 @@ -15,6 +15,7 @@ Function Invoke-AddSpamFilter { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, comments + $RequestPriority = $Request.Body.Priority $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value $Result = foreach ($Tenantfilter in $tenants) { @@ -26,7 +27,7 @@ Function Invoke-AddSpamFilter { 'hostedcontentfilterpolicy' = "$($RequestParams.name)" 'recipientdomainis' = @($domains) 'Enabled' = $true - 'Priority' = 0 + 'Priority' = $RequestPriority } $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-HostedContentFilterRule' -cmdParams $ruleparams "Successfully created spamfilter for $tenantfilter." From 564b433e5f3c46a356ec38e93f6e444a8961bee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 21 Jun 2024 20:45:16 +0200 Subject: [PATCH 67/91] Change to use IsNullOrWhiteSpace and handle reporting when invalid state is set --- .../Public/Standards/Get-CIPPStandards.ps1 | 2 +- ...nvoke-CIPPStandardActivityBasedTimeout.ps1 | 2 +- .../Standards/Invoke-CIPPStandardBookings.ps1 | 23 ++++++++-------- .../Invoke-CIPPStandardCloudMessageRecall.ps1 | 22 ++++++++------- .../Invoke-CIPPStandardDisableViva.ps1 | 1 + .../Invoke-CIPPStandardExternalMFATrusted.ps1 | 21 +++++++-------- .../Invoke-CIPPStandardFocusedInbox.ps1 | 2 +- ...PStandardGlobalQuarantineNotifications.ps1 | 27 +++++++++---------- .../Standards/Invoke-CIPPStandardNudgeMFA.ps1 | 18 +++++++------ ...CIPPStandardPWcompanionAppAllowedState.ps1 | 16 +++++------ .../Invoke-CIPPStandardSpoofWarn.ps1 | 16 +++++------ .../Standards/Invoke-CIPPStandardTAP.ps1 | 16 +++++------ ...oke-CIPPStandardTeamsMeetingsByDefault.ps1 | 23 ++++++++-------- ...voke-CIPPStandardTenantDefaultTimezone.ps1 | 17 ++++++------ .../Invoke-CIPPStandardUserSubmissions.ps1 | 21 ++++++++------- .../Invoke-CIPPStandardallowOAuthTokens.ps1 | 16 ++++++----- .../Invoke-CIPPStandardcalDefault.ps1 | 2 +- .../Invoke-CIPPStandardsharingCapability.ps1 | 17 +++++------- 18 files changed, 134 insertions(+), 128 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 13c3aa29b47b..58626e946e74 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -64,7 +64,7 @@ function Get-CIPPStandards { } else { foreach ($Setting in $CurrentStandard.PSObject.Properties.Name) { # Write-Host "$Setting - Current: $($CurrentStandard.$Setting) | Computed: $($ComputedStandards[$StandardName].$($Setting))" - if ($CurrentStandard.$Setting -ne $false -and $CurrentStandard.$Setting -ne $ComputedStandards[$StandardName].$($Setting) -and ![string]::IsNullOrEmpty($CurrentStandard.$Setting)) { + if ($CurrentStandard.$Setting -ne $false -and $CurrentStandard.$Setting -ne $ComputedStandards[$StandardName].$($Setting) -and ![string]::IsNullOrWhiteSpace($CurrentStandard.$Setting)) { #Write-Host "Overriding $Setting for $StandardName at tenant level" if ($ComputedStandards[$StandardName].PSObject.Properties.Name -contains $Setting) { $ComputedStandards[$StandardName].$($Setting) = $CurrentStandard.$Setting diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 index cf03f748d032..ebf92d21e199 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 @@ -6,7 +6,7 @@ function Invoke-CIPPStandardActivityBasedTimeout { param($Tenant, $Settings) # Input validation - if ([string]::isNullOrEmpty($Settings.timeout) -or $Settings.timeout -eq 'Select a value') { + if ([string]::IsNullOrWhiteSpace($Settings.timeout) -or $Settings.timeout -eq 'Select a value' ) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ActivityBasedTimeout: Invalid timeout parameter set' -sev Error Return } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 index c60e23d3acd1..406f0c06bd84 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -5,16 +5,21 @@ function Invoke-CIPPStandardBookings { #> param($Tenant, $Settings) - # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'BookingsEnabled: Invalid state parameter set' -sev Error - Return - } - $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').BookingsEnabled $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } + if ($Settings.report -eq $true) { + # Default is not set, not set means it's enabled + if ($null -eq $CurrentState ) { $CurrentState = $true } + Add-CIPPBPAField -FieldName 'BookingsState' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + } + + # Input validation + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'BookingsEnabled: Invalid state parameter set' -sev Error + Return + } if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $false) { @@ -39,10 +44,6 @@ function Invoke-CIPPStandardBookings { } } - if ($Settings.report -eq $true) { - # Default is not set, not set means it's enabled - if ($null -eq $CurrentState ) { $CurrentState = $true } - Add-CIPPBPAField -FieldName 'BookingsState' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant - } + } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 index 446056aee5be..19c6926d5af4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -5,16 +5,22 @@ function Invoke-CIPPStandardCloudMessageRecall { #> param($Tenant, $Settings) + $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').MessageRecallEnabled + $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } + + if ($Settings.report -eq $true) { + # Default is not set, not set means it's enabled + if ($null -eq $CurrentState ) { $CurrentState = $true } + Add-CIPPBPAField -FieldName 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'MessageRecallEnabled: Invalid state parameter set' -sev Error Return } - $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').MessageRecallEnabled - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } - $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } - if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $false) { @@ -39,10 +45,6 @@ function Invoke-CIPPStandardCloudMessageRecall { } } - if ($Settings.report -eq $true) { - # Default is not set, not set means it's enabled - if ($null -eq $CurrentState ) { $CurrentState = $true } - Add-CIPPBPAField -FieldName 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant - } + } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 index 57673d0d7fb0..2a87da3fef09 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 @@ -4,6 +4,7 @@ function Invoke-CIPPStandardDisableViva { Internal #> param($Tenant, $Settings) + try { # TODO This does not work without Global Admin permissions for some reason. Throws an "EXCEPTION: Tenant admin role is required" error. -Bobby $CurrentSetting = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/organization/$Tenant/settings/peopleInsights" -tenantid $Tenant -AsApp $true diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 index fd3b2e0fec99..6fefb63e5b59 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 @@ -5,16 +5,21 @@ function Invoke-CIPPStandardExternalMFATrusted { #> param($Tenant, $Settings) + $ExternalMFATrusted = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default?$select=inboundTrust' -tenantid $Tenant) + $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + $StateMessage = if ($WantedState) { 'enabled' } else { 'disabled' } + + if ($Settings.report -eq $true) { + + Add-CIPPBPAField -FieldName 'ExternalMFATrusted' -FieldValue $ExternalMFATrusted.inboundTrust.isMfaAccepted -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error Return } - $ExternalMFATrusted = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default?$select=inboundTrust' -tenantid $Tenant) - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } - $StateMessage = if ($WantedState) { 'enabled' } else { 'disabled' } - if ($Settings.remediate -eq $true) { Write-Host 'Remediate External MFA Trusted' @@ -41,11 +46,5 @@ function Invoke-CIPPStandardExternalMFATrusted { } else { Write-LogMessage -API 'Standards' -tenant $tenant -message "External MFA Trusted is not $StateMessage." -sev Alert } - - } - - if ($Settings.report -eq $true) { - - Add-CIPPBPAField -FieldName 'ExternalMFATrusted' -FieldValue $ExternalMFATrusted.inboundTrust.isMfaAccepted -StoreAs bool -Tenant $tenant } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index e1f80e8df02e..6dccab45117f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 @@ -6,7 +6,7 @@ function Invoke-CIPPStandardFocusedInbox { param($Tenant, $Settings) # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if ([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error Return } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 index c067e350f6b1..583a39ecb8f8 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 @@ -5,15 +5,6 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { #> param ($Tenant, $Settings) - # Input validation - try { - $WantedState = [timespan]$Settings.NotificationInterval - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Invalid state selected for Global Quarantine Notifications. Error: $ErrorMessage" -sev Error - Return - } - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-QuarantinePolicy' -cmdParams @{ QuarantinePolicyType = 'GlobalQuarantinePolicy' } # This might take the cake on ugly hacky stuff i've done, @@ -26,6 +17,19 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { Default { $null } } + if ($Settings.report -eq $true) { + + Add-CIPPBPAField -FieldName 'GlobalQuarantineNotificationsSet' -FieldValue [string]$CurrentState.EndUserSpamNotificationFrequency -StoreAs string -Tenant $tenant + } + # Input validation + try { + $WantedState = [timespan]$Settings.NotificationInterval + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Invalid state selected for Global Quarantine Notifications. Error: $ErrorMessage" -sev Error + Return + } + if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' @@ -50,9 +54,4 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { Write-LogMessage -API 'Standards' -tenant $tenant -message "Global Quarantine Notifications are not set to the desired value of $WantedState" -sev Alert } } - - if ($Settings.report -eq $true) { - - Add-CIPPBPAField -FieldName 'GlobalQuarantineNotificationsSet' -FieldValue [string]$CurrentState.EndUserSpamNotificationFrequency -StoreAs string -Tenant $tenant - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index ffbedce078b5..6d387b212767 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -5,19 +5,25 @@ function Invoke-CIPPStandardNudgeMFA { #> param($Tenant, $Settings) + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $Tenant + $State = if ($CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq 'enabled') { $true } else { $false } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'NudgeMFA' -FieldValue $State -StoreAs bool -Tenant $tenant + } + + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid state parameter set' -sev Error Return } # Input validation - if ($Settings.snoozeDurationInDays -lt 0 -or $Settings.snoozeDurationInDays -gt 15) { + if (($Settings.snoozeDurationInDays -lt 0 -or $Settings.snoozeDurationInDays -gt 15) -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid snoozeDurationInDays parameter set' -sev Error Return } - $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $Tenant - $State = if ($CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq 'enabled') { $true } else { $false } If ($Settings.remediate -eq $true) { @@ -50,8 +56,4 @@ function Invoke-CIPPStandardNudgeMFA { Write-LogMessage -API 'Standards' -tenant $tenant -message "Authenticator App Nudge is not enabled with a snooze duration of $($CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays)" -sev Alert } } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'NudgeMFA' -FieldValue $State -StoreAs bool -Tenant $tenant - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 index 4528d789539e..c2e3c7a687b7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 @@ -5,15 +5,19 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { #> param($Tenant, $Settings) + $authenticatorFeaturesState = (New-GraphGetRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type GET) + $authstate = if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq 'enabled') { $true } else { $false } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'companionAppAllowedState' -FieldValue $authstate -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'PWcompanionAppAllowedState: Invalid state parameter set' -sev Error Return } - $authenticatorFeaturesState = (New-GraphGetRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type GET) - $authstate = if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq 'enabled') { $true } else { $false } - If ($Settings.remediate -eq $true) { if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq $Settings.state) { @@ -53,8 +57,4 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { Write-LogMessage -API 'Standards' -tenant $tenant -message 'companionAppAllowedState is not enabled.' -sev Alert } } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'companionAppAllowedState' -FieldValue $authstate -StoreAs bool -Tenant $tenant - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index b9ead2f3e0b9..af9e03c6122c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 @@ -5,17 +5,21 @@ function Invoke-CIPPStandardSpoofWarn { #> param($Tenant, $Settings) + $CurrentInfo = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ExternalInOutlook') + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SpoofingWarnings' -FieldValue $CurrentInfo.Enabled -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'SpoofWarn: Invalid state parameter set' -sev Error Return } - $CurrentInfo = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ExternalInOutlook') - If ($Settings.remediate -eq $true) { $status = if ($Settings.enable -and $Settings.disable) { - # Handle legacy settings when this was 2 separate standards + # Handle pre standards v2.0 legacy settings when this was 2 separate standards Write-LogMessage -API 'Standards' -tenant $tenant -message 'You cannot both enable and disable the Spoof Warnings setting' -sev Error Return } elseif ($Settings.state -eq 'enabled' -or $Settings.enable) { $true } else { $false } @@ -40,8 +44,4 @@ function Invoke-CIPPStandardSpoofWarn { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Outlook external spoof warnings are not enabled.' -sev Alert } } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SpoofingWarnings' -FieldValue $CurrentInfo.Enabled -StoreAs bool -Tenant $tenant - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 index aaed774d7dcf..ce9a3c95ef62 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 @@ -5,15 +5,19 @@ function Invoke-CIPPStandardTAP { #> param($Tenant, $Settings) + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass' -tenantid $Tenant + $State = if ($CurrentInfo.state -eq 'enabled') { $true } else { $false } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TemporaryAccessPass' -FieldValue $State -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'TAP: Invalid state parameter set' -sev Error Return } - $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass' -tenantid $Tenant - $State = if ($CurrentInfo.state -eq 'enabled') { $true } else { $false } - If ($Settings.remediate -eq $true) { if ($State) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Temporary Access Passwords is already enabled.' -sev Info @@ -29,8 +33,4 @@ function Invoke-CIPPStandardTAP { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Temporary Access Passwords is not enabled.' -sev Alert } } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TemporaryAccessPass' -FieldValue $State -StoreAs bool -Tenant $tenant - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 3054bac5f2ce..615dd6e94237 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -5,16 +5,22 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { #> param($Tenant, $Settings) + $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').OnlineMeetingsByDefaultEnabled + $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } + + if ($Settings.report -eq $true) { + # Default is not set, not set means it's enabled + if ($null -eq $CurrentState ) { $CurrentState = $true } + Add-CIPPBPAField -FieldName 'TeamsMeetingsByDefault' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'TeamsMeetingsByDefault: Invalid state parameter set' -sev Error Return } - $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').OnlineMeetingsByDefaultEnabled - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } - $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } - if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $false) { @@ -38,11 +44,4 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant TeamsMeetingsByDefault is not set correctly to $($Settings.state)" -sev Alert } } - - if ($Settings.report -eq $true) { - # Default is not set, not set means it's enabled - if ($null -eq $CurrentState ) { $CurrentState = $true } - Add-CIPPBPAField -FieldName 'TeamsMeetingsByDefault' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant - } - } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 index 4427c31986d5..c2651ae346a9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 @@ -6,16 +6,20 @@ function Invoke-CIPPStandardTenantDefaultTimezone { param($Tenant, $Settings) + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true + $ExpectedTimezone = $Settings.Timezone.value + $StateIsCorrect = $CurrentState.tenantDefaultTimezone -eq $ExpectedTimezone + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TenantDefaultTimezone' -FieldValue $CurrentState.tenantDefaultTimezone -StoreAs string -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.Timezone) -or $Settings.Timezone -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.Timezone) -or $Settings.Timezone -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'TenantDefaultTimezone: Invalid Timezone parameter set' -sev Error Return } - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true - $ExpectedTimezone = $Settings.Timezone.value - $StateIsCorrect = $CurrentState.tenantDefaultTimezone -eq $ExpectedTimezone - If ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $tenant -message "Tenant Default Timezone is already set to $ExpectedTimezone" -sev Info @@ -38,7 +42,4 @@ function Invoke-CIPPStandardTenantDefaultTimezone { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Tenant Default Timezone is not set to the desired value.' -sev Alert } } - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TenantDefaultTimezone' -FieldValue $CurrentState.tenantDefaultTimezone -StoreAs string -Tenant $tenant - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index d0759ecb4a22..0d20abaeb57a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -5,13 +5,22 @@ function Invoke-CIPPStandardUserSubmissions { #> param($Tenant, $Settings) + $Policy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ReportSubmissionPolicy' + + if ($Settings.report -eq $true) { + if ($Policy.length -eq 0) { + Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $false -StoreAs bool -Tenant $tenant + } else { + Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $Policy.EnableReportToMicrosoft -StoreAs bool -Tenant $tenant + } + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if ([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'UserSubmissions: Invalid state parameter set' -sev Error Return } - $Policy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ReportSubmissionPolicy' If ($Settings.remediate -eq $true) { $Status = if ($Settings.state -eq 'enable') { $true } else { $false } @@ -63,12 +72,4 @@ function Invoke-CIPPStandardUserSubmissions { } } } - - if ($Settings.report -eq $true) { - if ($Policy.length -eq 0) { - Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $false -StoreAs bool -Tenant $tenant - } else { - Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $Policy.EnableReportToMicrosoft -StoreAs bool -Tenant $tenant - } - } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 index 36afc500320a..a5f43f175998 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 @@ -5,14 +5,20 @@ function Invoke-CIPPStandardallowOAuthTokens { #> param($Tenant, $Settings) + $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/softwareOath' -tenantid $Tenant + $State = if ($CurrentInfo.state -eq 'enabled') { $true } else { $false } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'softwareOath' -FieldValue $State -StoreAs bool -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.state) -or $Settings.state -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'allowOAuthTokens: Invalid state parameter set' -sev Error Return } - $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/softwareOath' -tenantid $Tenant - $State = if ($CurrentInfo.state -eq 'enabled') { $true } else { $false } + If ($Settings.remediate -eq $true) { if ($State) { @@ -31,7 +37,5 @@ function Invoke-CIPPStandardallowOAuthTokens { } } - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'softwareOath' -FieldValue $State -StoreAs bool -Tenant $tenant - } + } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 index e9f95984fc9f..491d35ab7eb5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 @@ -6,7 +6,7 @@ function Invoke-CIPPStandardcalDefault { param($Tenant, $Settings, $QueueItem) # Input validation - if ([string]::isNullOrEmpty($Settings.permissionlevel) -or $Settings.permissionlevel -eq 'Select a value') { + if ([string]::IsNullOrWhiteSpace($Settings.permissionlevel) -or $Settings.permissionlevel -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'calDefault: Invalid permissionlevel parameter set' -sev Error Return } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index c733398f2b26..95dfcec5a26d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -5,17 +5,18 @@ function Invoke-CIPPStandardsharingCapability { #> param($Tenant, $Settings) + $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'sharingCapability' -FieldValue $CurrentInfo.sharingCapability -StoreAs string -Tenant $tenant + } + # Input validation - if ([string]::isNullOrEmpty($Settings.sharingCapability) -or $Settings.sharingCapability -eq 'Select a value') { + if (([string]::IsNullOrWhiteSpace($Settings.sharingCapability) -or $Settings.sharingCapability -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'sharingCapability: Invalid sharingCapability parameter set' -sev Error Return } - $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true - # $CurrentInfo.sharingCapability.GetType() - $Settings.Level - $CurrentInfo.sharingCapability - If ($Settings.remediate -eq $true) { if ($CurrentInfo.sharingCapability -eq $Settings.Level) { @@ -41,8 +42,4 @@ function Invoke-CIPPStandardsharingCapability { Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is not set to $($Settings.Level)" -sev Alert } } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'sharingCapability' -FieldValue $CurrentInfo.sharingCapability -StoreAs string -Tenant $tenant - } } From e3f506dcfd6a251cfa099d25932acaab915052a6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 21 Jun 2024 17:53:19 -0400 Subject: [PATCH 68/91] DomainAnalyser tweaks --- .../Domain Analyser/Push-DomainAnalyserDomain.ps1 | 4 ++-- .../Domain Analyser/Push-DomainAnalyserTenant.ps1 | 6 ++++-- .../Tenant/Standards/Invoke-ListDomainAnalyser.ps1 | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserDomain.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserDomain.ps1 index 5366603a4492..9952ff679677 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserDomain.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserDomain.ps1 @@ -30,7 +30,7 @@ function Push-DomainAnalyserDomain { } Set-DnsResolver -Resolver $Resolver - $Domain = $DomainObject.rowKey + $Domain = $DomainObject.RowKey try { $Tenant = $DomainObject.TenantDetails | ConvertFrom-Json -ErrorAction Stop @@ -250,7 +250,7 @@ function Push-DomainAnalyserDomain { # Final Write to Output Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message "DNS Analyser Finished For $Domain" -sev Info } catch { - Write-LogMessage -API -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message "Error saving domain $Domain to table " -sev Error -LogData (Get-CippException -Exception $_) + Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message "Error saving domain $Domain to table " -sev Error -LogData (Get-CippException -Exception $_) } return $null } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 index 605c56bebb53..440f7e37d4cf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-DomainAnalyserTenant.ps1 @@ -20,7 +20,7 @@ function Push-DomainAnalyserTenant { return } else { try { - $Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/domains' -tenantid $Tenant.customerId | Where-Object { ($_.id -notlike '*.microsoftonline.com' -and $_.id -NotLike '*.exclaimer.cloud' -and $_.id -Notlike '*.excl.cloud' -and $_.id -NotLike '*.codetwo.online' -and $_.id -NotLike '*.call2teams.com' -and $_.isVerified) } + $Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $Tenant.customerId | Where-Object { ($_.id -notlike '*.microsoftonline.com' -and $_.id -NotLike '*.exclaimer.cloud' -and $_.id -Notlike '*.excl.cloud' -and $_.id -NotLike '*.codetwo.online' -and $_.id -NotLike '*.call2teams.com' -and $_.isVerified) } $TenantDomains = foreach ($d in $Domains) { [PSCustomObject]@{ @@ -38,9 +38,11 @@ function Push-DomainAnalyserTenant { } } + Write-Information ($TenantDomains | ConvertTo-Json -Depth 10) + $DomainCount = ($TenantDomains | Measure-Object).Count if ($DomainCount -gt 0) { - Write-Host "$DomainCount tenant Domains" + Write-Host "############# $DomainCount tenant Domains" $TenantDomainObjects = [System.Collections.Generic.List[object]]::new() try { foreach ($TenantDomain in $TenantDomains) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainAnalyser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainAnalyser.ps1 index 95077930211f..3d85e4747122 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainAnalyser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainAnalyser.ps1 @@ -11,7 +11,7 @@ Function Invoke-ListDomainAnalyser { [CmdletBinding()] param($Request, $TriggerMetadata) - $Results = Get-CIPPDomainAnalyser -TenantFilter $Request.query.tenantFilter + $Results = Get-CIPPDomainAnalyser -TenantFilter $Request.Query.tenantFilter # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ From 72a07d816117310491ff7150781657e75d216976 Mon Sep 17 00:00:00 2001 From: Esco Date: Sat, 22 Jun 2024 18:09:40 +0200 Subject: [PATCH 69/91] Added Risky Sign-in Report --- .../Entrypoints/Invoke-ListRiskySignIns.ps1 | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 new file mode 100644 index 000000000000..9a14ab116ace --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 @@ -0,0 +1,47 @@ +using namespace System.Net + +Function Invoke-ListRiskySignIns { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.AuditLog.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.TenantFilter + $Days = $Request.Query.Days ?? 14 + + try { + $filters = if ($Request.Query.Filter) { + $Request.Query.filter + } else { + $ts = (Get-Date).AddDays(-$Days).ToUniversalTime() + $endTime = $ts.ToString('yyyy-MM-dd') + "createdDateTime ge $($endTime) and userDisplayName ne 'On-Premises Directory Synchronization Service Account' and riskState ne 'none'" + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved risky sign in report' -Sev 'Debug' -tenant $TenantFilter + + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&`$filter=$($filters)" -tenantid $TenantFilter + $response = $GraphRequest | Select-Object *, + @{l = 'additionalDetails'; e = { $_.status.additionalDetails } } , + @{l = 'errorCode'; e = { $_.status.errorCode } }, + @{l = 'locationcipp'; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($response) + }) + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Risky Sign In report: $ErrorMessage" -Sev 'Error' -tenant $TenantFilter + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = '500' + Body = $ErrorMessage + }) + } +} From f59ce37319824da8af2a58642cb1d1232c83f829 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 23 Jun 2024 23:07:09 +0200 Subject: [PATCH 70/91] changed add minutes --- .../CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index 363c31402feb..2f55cc17c07c 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -56,7 +56,7 @@ function Get-CIPPAuditLogContentBundles { if (!$ShowAll.IsPresent) { if ($null -ne $WebhookConfig.LastContentCreated) { $StartTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime() - $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddHours(4) + $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddMinutes(30) } } From 8c5e5029048b54f9d3dd51eb478ca5d2ac21ca57 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 02:37:01 +0200 Subject: [PATCH 71/91] fixes ca issues --- .../Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 | 1 - Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 index 60d86236ca22..498441852f6f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 @@ -60,7 +60,6 @@ Function Invoke-AddIntuneTemplate { $TemplateJson = $Template | ConvertTo-Json -Depth 100 $DisplayName = $Template.name - } 'windowsDriverUpdateProfiles' { $Type = 'windowsDriverUpdateProfiles' diff --git a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 index 15ecab0ea749..2999f0705b17 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 @@ -5,11 +5,11 @@ function Set-CIPPAssignedPolicy { $PolicyId, $Type, $TenantFilter, - $PlatformType = 'deviceManagement', + $PlatformType, $APIName = 'Assign Policy', $ExecutingUser ) - + if (!$PlatformType) { $PlatformType = 'deviceManagement' } try { $assignmentsObject = switch ($GroupName) { 'allLicensedUsers' { @@ -70,9 +70,11 @@ function Set-CIPPAssignedPolicy { assignments = @($assignmentsObject) } if ($PSCmdlet.ShouldProcess($GroupName, "Assigning policy $PolicyId")) { + Write-Host "https://graph.microsoft.com/beta/$($PlatformType)/$Type('$($PolicyId)')/assign" $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$($PlatformType)/$Type('$($PolicyId)')/assign" -tenantid $tenantFilter -type POST -body ($assignmentsObject | ConvertTo-Json -Depth 10) Write-LogMessage -user $ExecutingUser -API $APIName -message "Assigned Policy to $($GroupName)" -Sev 'Info' -tenant $TenantFilter } + return "Assigned policy to $($GroupName) Policy ID is $($PolicyId)." } catch { Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to assign Policy to $GroupName. Policy ID is $($PolicyId)." -Sev 'Error' -tenant $TenantFilter -LogData (Get-CippException -Exception $_) From d0159b28e328c539225024ba4da9fd3aaa402f48 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 13:46:28 +0200 Subject: [PATCH 72/91] fixes bpa table error in console --- .../HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 index 22e078617475..d597a8d6bb87 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 @@ -19,7 +19,6 @@ Function Invoke-ListBPA { # Get all possible JSON files for reports, find the correct one, select the Columns $JSONFields = @() - $Columns = $null $BPATemplateTable = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'BPATemplate'" $Templates = (Get-CIPPAzDataTableEntity @BPATemplateTable -Filter $Filter).JSON | ConvertFrom-Json @@ -74,7 +73,7 @@ Function Invoke-ListBPA { $Results = [PSCustomObject]@{ Data = @($Data) - Columns = $Columns + Columns = @($Columns) Style = $Style } From 599e5ba9f13e8130e7fcf6c118d94c443370a5c7 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 15:29:09 +0200 Subject: [PATCH 73/91] remove bpa file reads --- BestPracticeAnalyser_OrchestrationStarter/run.ps1 | 10 ++++------ BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/BestPracticeAnalyser_OrchestrationStarter/run.ps1 b/BestPracticeAnalyser_OrchestrationStarter/run.ps1 index 0afc6fdc07e0..3135509f9b3e 100644 --- a/BestPracticeAnalyser_OrchestrationStarter/run.ps1 +++ b/BestPracticeAnalyser_OrchestrationStarter/run.ps1 @@ -8,12 +8,10 @@ if ($Request.Query.TenantFilter) { $TenantList = Get-Tenants $Name = 'Best Practice Analyser (All Tenants)' } -$CippRoot = (Get-Item $PSScriptRoot).Parent.FullName -$TemplatesLoc = Get-ChildItem "$CippRoot\Config\*.BPATemplate.json" -$Templates = $TemplatesLoc | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json - $Template.Name -} + +$BPATemplateTable = Get-CippTable -tablename 'templates' +$Filter = "PartitionKey eq 'BPATemplate'" +$Templates = ((Get-CIPPAzDataTableEntity @BPATemplateTable -Filter $Filter).JSON | ConvertFrom-Json).Name $BPAReports = foreach ($Tenant in $TenantList) { foreach ($Template in $Templates) { diff --git a/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 b/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 index f111844160d4..0b9faa0a7c8b 100644 --- a/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 +++ b/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 @@ -7,12 +7,10 @@ if ($env:DEV_SKIP_BPA_TIMER) { $TenantList = Get-Tenants -$CippRoot = (Get-Item $PSScriptRoot).Parent.FullName -$TemplatesLoc = Get-ChildItem "$CippRoot\Config\*.BPATemplate.json" -$Templates = $TemplatesLoc | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json - $Template.Name -} +$BPATemplateTable = Get-CippTable -tablename 'templates' +$Filter = "PartitionKey eq 'BPATemplate'" +$Templates = ((Get-CIPPAzDataTableEntity @BPATemplateTable -Filter $Filter).JSON | ConvertFrom-Json).Name + $BPAReports = foreach ($Tenant in $TenantList) { foreach ($Template in $Templates) { From f096830195aebcd56654d7c8a6c654ab90ce513c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 15:59:33 +0200 Subject: [PATCH 74/91] added delete report --- .../Public/Invoke-RemoveBPATemplate.ps1 | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 new file mode 100644 index 000000000000..b9ae2a8c13e1 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 @@ -0,0 +1,38 @@ +using namespace System.Net + +Function Invoke-RemoveBPATemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + $ID = $request.query.TemplateName + try { + $Table = Get-CippTable -tablename 'templates' + + $Filter = "PartitionKey eq 'BPATemplate' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity @Table -Entity $clearRow + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed BPA Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed BPA Template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove BPA template $ID. $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($_.Exception.Message)" } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + + +} From 2dc2299b63bb373b6b829810228b55dd749b7369 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 16:27:50 +0200 Subject: [PATCH 75/91] remove file support bpa --- .../Activity Triggers/BPA/Push-BPACollectData.ps1 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 index 71d41acb852b..af2c6092ff21 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 @@ -6,10 +6,12 @@ function Push-BPACollectData { param($Item) $TenantName = Get-Tenants | Where-Object -Property defaultDomainName -EQ $Item.Tenant - $CippRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.Parent.Parent.FullName - $TemplatesLoc = Get-ChildItem "$CippRoot\Config\*.BPATemplate.json" + $BPATemplateTable = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'BPATemplate'" + $TemplatesLoc = (Get-CIPPAzDataTableEntity @BPATemplateTable -Filter $Filter).JSON | ConvertFrom-Json + $Templates = $TemplatesLoc | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json + $Template = $_ [PSCustomObject]@{ Data = $Template Name = $Template.Name @@ -17,7 +19,7 @@ function Push-BPACollectData { } } $Table = Get-CippTable -tablename 'cachebpav2' - + Write-Host "Working on BPA for $($TenantName.displayName) with GUID $($TenantName.customerId) - Report ID $($Item.Template)" $Template = $Templates | Where-Object -Property Name -EQ -Value $Item.Template # Build up the result object that will be stored in tables $Result = @{ @@ -39,13 +41,13 @@ function Push-BPACollectData { } if ($Field.parameters.psobject.properties.name) { $field.Parameters | ForEach-Object { - Write-Information "Doing: $($_.psobject.properties.name) with value $($_.psobject.properties.value)" $paramsField[$_.psobject.properties.name] = $_.psobject.properties.value } } $FieldInfo = New-GraphGetRequest @paramsField | Where-Object $filterscript | Select-Object $field.ExtractFields } 'Exchange' { + Write-Host "Trying to execute $($field.Command) for $($TenantName.displayName) with GUID $($TenantName.customerId)" if ($field.Command -notlike 'get-*') { Write-LogMessage -API 'BPA' -tenant $tenant -message 'The BPA only supports get- exchange commands. A set or update command was used.' -sev Error break @@ -93,6 +95,7 @@ function Push-BPACollectData { } 'JSON' { if ($FieldInfo -eq $null) { $JsonString = '{}' } else { $JsonString = (ConvertTo-Json -Depth 15 -InputObject $FieldInfo -Compress) } + Write-Host "Adding $($field.Name) to table with value $JsonString" $Result.Add($field.Name, $JSONString) } 'string' { From 6f502fd50d0ccddfedea86ba62945ad89cbca5ef Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 17:31:54 +0200 Subject: [PATCH 76/91] added lost sku exclusion --- Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 b/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 index 3200c46782c5..b2fdba7b43ae 100644 --- a/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 +++ b/Modules/CippExtensions/Private/New-GradientServiceSyncRun.ps1 @@ -41,7 +41,7 @@ function New-GradientServiceSyncRun { Import-Module '.\Modules\CIPPCore' Write-Host "Doing $domainName" try { - $Licrequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $_.defaultDomainName -ErrorAction Stop + $Licrequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus' -tenantid $_.defaultDomainName -ErrorAction Stop | Where-Object -Property skuId -NotIn $ExcludedSkuList.RowKey [PSCustomObject]@{ Tenant = $domainName Licenses = $Licrequest From 53ec64da4633e0abbb746126a0b27918e3cf2b11 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 21 Jun 2024 23:33:35 +0200 Subject: [PATCH 77/91] update to exo commands --- Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 index 8ef890eaf10d..fac7a03612a0 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1 @@ -23,14 +23,14 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc if ($cmdparams.anr) { $Anchor = $cmdparams.anr } if ($cmdparams.User) { $Anchor = $cmdparams.User } if ($cmdparams.mailbox) { $Anchor = $cmdparams.mailbox } - + if ($cmdlet -eq 'Set-AdminAuditLogConfig') { $anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)" } if (!$Anchor -or $useSystemMailbox) { if (!$Tenant.initialDomainName -or $Tenant.initialDomainName -notlike '*onmicrosoft.com*') { $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantid -NoAuthCheck $NoAuthCheck | Where-Object -Property isInitial -EQ $true).id } else { $OnMicrosoft = $Tenant.initialDomainName } - $anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)" + $anchor = "UPN:SystemMailbox{bb558c35-97f1-4cb9-8ff7-d53741dc928c}@$($OnMicrosoft)" } #if the anchor is a GUID, try looking up the user. if ($Anchor -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') { From 8fd30d34480c2bbae687538496d6e1dacfa1a2f1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sat, 22 Jun 2024 02:22:48 +0200 Subject: [PATCH 78/91] updated api --- .../HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 index 1ec68eb1a7c7..a49abf454b11 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 @@ -29,7 +29,7 @@ Function Invoke-GetCippAlerts { Write-LogMessage -message 'Your CIPP API is out of date. Please update to the latest version' -API 'Updates' -tenant 'All Tenants' -sev Alert } - if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.Add(@{Alert = 'You have not yet completed your SAM Setup. Please go to the SAM Setup Wizard in settings to connect CIPP to your tenant.'; link = '/cipp/setup'; type = 'warning' }) } + if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.Add(@{Alert = 'You have not yet completed your SAM Setup. Please go to the SAM Setup Wizard in settings to connect CIPP to your tenant.'; link = '/cipp/setup'; type = 'warning'; setupCompleted = $false }) } if ($role -like '*superadmin*') { $Alerts.Add(@{Alert = 'You are logged in under a superadmin account. This account should not be used for normal usage.'; link = 'https://docs.cipp.app/setup/installation/owntenant'; type = 'danger' }) } if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1' -and $env:AzureWebJobsStorage -ne 'UseDevelopmentStorage=true') { $Alerts.Add( From 75a59b04fcab0cf0808cdbc91d0945aab3e5583f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 24 Jun 2024 10:53:02 +0200 Subject: [PATCH 79/91] fixes shared mailbox disablement --- .../Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 index 31955cc04c72..d9d3356eba00 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 @@ -4,7 +4,8 @@ function Invoke-CIPPStandardDisableSharedMailbox { Internal #> param($Tenant, $Settings) - $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($Tenant)/Mailbox?`$filter=ExchangeUserAccountControl ne 'accountdisabled'" -Tenantid $tenant -scope ExchangeOnline | Where-Object { $_.RecipientTypeDetails -EQ 'SharedMailbox' -or $_.RecipientTypeDetails -eq 'SchedulingMailbox' }) + $UserList = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/users?$top=999&$filter=accountEnabled eq true' -Tenantid $tenant -scope 'https://graph.microsoft.com/.default' + $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($Tenant)/Mailbox" -Tenantid $tenant -scope ExchangeOnline | Where-Object { $_.RecipientTypeDetails -EQ 'SharedMailbox' -or $_.RecipientTypeDetails -eq 'SchedulingMailbox' -and $_.UserPrincipalName -in $UserList.UserPrincipalName }) If ($Settings.remediate -eq $true) { From cc2964c710d08a0697c62b074b3a0d714da11c38 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 24 Jun 2024 13:15:35 +0200 Subject: [PATCH 80/91] Added APIs for Risk detection --- Modules/CIPPCore/Public/SAMManifest.json | 417 ++++++++++++----------- 1 file changed, 210 insertions(+), 207 deletions(-) diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index b7ee864cd6f6..427d2f98fe0c 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -1,207 +1,210 @@ -{ - "isFallbackPublicClient": true, - "signInAudience": "AzureADMultipleOrgs", - "displayName": "CIPP-SAM", - "web": { - "redirectUris": [ - "https://login.microsoftonline.com/common/oauth2/nativeclient", - "https://localhost", - "http://localhost", - "http://localhost:8400" - ] - }, - "requiredResourceAccess": [ - { - "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", - "resourceAccess": [ - { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } - ] - }, - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, - { "id": "0f4595f7-64b1-4e13-81bc-11a249df07a9", "type": "Scope" }, - { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, - { "id": "7ab1d787-bae7-4d5d-8db6-37ea32df9186", "type": "Scope" }, - { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, - { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, - { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, - { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, - { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, - { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, - { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, - { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, - { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, - { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, - { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, - { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, - { "id": "8696daa5-bce5-4b2e-83f9-51b6defc4e1e", "type": "Scope" }, - { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, - { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, - { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, - { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, - { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, - { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, - { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, - { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, - { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, - { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, - { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, - { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, - { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, - { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, - { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, - { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, - { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, - { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, - { "id": "c79f8feb-a9db-4090-85f9-90d820caa0eb", "type": "Scope" }, - { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, - { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, - { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, - { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, - { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, - { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, - { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, - { "id": "59dacb05-e88d-4c13-a684-59f1afc8cc98", "type": "Scope" }, - { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, - { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, - { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, - { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, - { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, - { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, - { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, - { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, - { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, - { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, - { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, - { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, - { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, - { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, - { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, - { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, - { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, - { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, - { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, - { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, - { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, - { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, - { "id": "bf3fbf03-f35f-4e93-963e-47e4d874c37a", "type": "Scope" }, - { "id": "5248dcb1-f83b-4ec3-9f4d-a4428a961a72", "type": "Scope" }, - { "id": "c395395c-ff9a-4dba-bc1f-8372ba9dca84", "type": "Scope" }, - { "id": "2e25a044-2580-450d-8859-42eeb6e996c0", "type": "Scope" }, - { "id": "0ce33576-30e8-43b7-99e5-62f8569a4002", "type": "Scope" }, - { "id": "207e0cb1-3ce7-4922-b991-5a760c346ebc", "type": "Scope" }, - { "id": "093f8818-d05f-49b8-95bc-9d2a73e9a43c", "type": "Scope" }, - { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, - { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, - { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, - { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, - { "id": "aa85bf13-d771-4d5d-a9e6-bca04ce44edf", "type": "Scope" }, - { "id": "ee928332-e9c2-4747-b4a0-f8c164b68de6", "type": "Scope" }, - { "id": "c975dd04-a06e-4fbb-9704-62daad77bb49", "type": "Scope" }, - { "id": "c37c9b61-7762-4bff-a156-afc0005847a0", "type": "Scope" }, - { "id": "b9abcc4f-94fc-4457-9141-d20ce80ec952", "type": "Scope" }, - { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, - { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, - { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, - { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, - { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, - { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, - { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, - { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, - { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, - { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, - { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, - { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, - { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, - { "id": "b633e1c5-b582-4048-a93e-9f11b44c7e96", "type": "Role" }, - { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, - { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, - { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, - { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, - { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, - { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, - { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, - { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, - { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, - { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, - { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, - { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, - { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, - { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, - { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, - { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, - { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, - { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, - { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, - { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, - { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, - { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, - { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, - { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, - { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, - { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, - { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, - { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, - { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, - { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, - { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, - { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, - { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, - { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, - { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, - { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, - { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, - { "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", "type": "Scope" }, - { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, - { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, - { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, - { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" } - ] - }, - { - "resourceAppId": "00000002-0000-0000-c000-000000000000", - "resourceAccess": [ - { "id": "5778995a-e1bf-45b8-affa-663a9f3f4d04", "type": "Role" }, - { "id": "a42657d6-7f20-40e3-b6f0-cee03008a62a", "type": "Scope" }, - { "id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6", "type": "Scope" } - ] - }, - { - "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", - "resourceAccess": [ - { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, - { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } - ] - }, - { - "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, - { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" } - ] - }, - { - "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", - "resourceAccess": [ - { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } - ] - }, - { - "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", - "resourceAccess": [ - { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } - ] - }, - { - "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", - "resourceAccess": [ - { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } - ] - } - ] -} +{ + "isFallbackPublicClient": true, + "signInAudience": "AzureADMultipleOrgs", + "displayName": "CIPP-SAM", + "web": { + "redirectUris": [ + "https://login.microsoftonline.com/common/oauth2/nativeclient", + "https://localhost", + "http://localhost", + "http://localhost:8400" + ] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd", + "resourceAccess": [ + { "id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a", "type": "Scope" } + ] + }, + { + "resourceAppId": "00000003-0000-0000-c000-000000000000", + "resourceAccess": [ + { "id": "aa07f155-3612-49b8-a147-6c590df35536", "type": "Scope" }, + { "id": "0f4595f7-64b1-4e13-81bc-11a249df07a9", "type": "Scope" }, + { "id": "73e75199-7c3e-41bb-9357-167164dbb415", "type": "Scope" }, + { "id": "7ab1d787-bae7-4d5d-8db6-37ea32df9186", "type": "Scope" }, + { "id": "d01b97e9-cbc0-49fe-810a-750afd5527a3", "type": "Scope" }, + { "id": "46ca0847-7e6b-426e-9775-ea810a948356", "type": "Scope" }, + { "id": "dc38509c-b87d-4da0-bd92-6bec988bac4a", "type": "Scope" }, + { "id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182", "type": "Scope" }, + { "id": "ad902697-1014-4ef5-81ef-2b4301988e8c", "type": "Scope" }, + { "id": "572fea84-0151-49b2-9301-11cb16974376", "type": "Scope" }, + { "id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20", "type": "Scope" }, + { "id": "0883f392-0a7a-443d-8c76-16a6d39c7b63", "type": "Scope" }, + { "id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af", "type": "Scope" }, + { "id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d", "type": "Scope" }, + { "id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3", "type": "Scope" }, + { "id": "662ed50a-ac44-4eef-ad86-62eed9be2a29", "type": "Scope" }, + { "id": "8696daa5-bce5-4b2e-83f9-51b6defc4e1e", "type": "Scope" }, + { "id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc", "type": "Scope" }, + { "id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804", "type": "Scope" }, + { "id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd", "type": "Scope" }, + { "id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c", "type": "Scope" }, + { "id": "89fe6a52-be36-487e-b7d8-d061c450a026", "type": "Scope" }, + { "id": "a367ab51-6b49-43bf-a716-a1fb06d2a174", "type": "Scope" }, + { "id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4", "type": "Scope" }, + { "id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0", "type": "Scope" }, + { "id": "0e263e50-5827-48a4-b97c-d940288653c7", "type": "Scope" }, + { "id": "e383f46e-2787-4529-855e-0e479a3ffac0", "type": "Scope" }, + { "id": "37f7f235-527c-4136-accd-4a02d197296e", "type": "Scope" }, + { "id": "14dad69e-099b-42c9-810b-d002981feec1", "type": "Scope" }, + { "id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be", "type": "Scope" }, + { "id": "0e755559-83fb-4b44-91d0-4cc721b9323e", "type": "Scope" }, + { "id": "a84a9652-ffd3-496e-a991-22ba5529156a", "type": "Scope" }, + { "id": "1d89d70c-dcac-4248-b214-903c457af83a", "type": "Scope" }, + { "id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53", "type": "Scope" }, + { "id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4", "type": "Scope" }, + { "id": "c79f8feb-a9db-4090-85f9-90d820caa0eb", "type": "Scope" }, + { "id": "bdfbf15f-ee85-4955-8675-146e8e5296b5", "type": "Scope" }, + { "id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e", "type": "Scope" }, + { "id": "cac97e40-6730-457d-ad8d-4852fddab7ad", "type": "Scope" }, + { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" }, + { "id": "48971fc1-70d7-4245-af77-0beb29b53ee2", "type": "Scope" }, + { "id": "aec28ec7-4d02-4e8c-b864-50163aea77eb", "type": "Scope" }, + { "id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e", "type": "Scope" }, + { "id": "59dacb05-e88d-4c13-a684-59f1afc8cc98", "type": "Scope" }, + { "id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9", "type": "Scope" }, + { "id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311", "type": "Scope" }, + { "id": "951183d1-1a61-466f-a6d1-1fde911bfd95", "type": "Scope" }, + { "id": "637d7bec-b31e-4deb-acc9-24275642a2c9", "type": "Scope" }, + { "id": "101147cf-4178-4455-9d58-02b5c164e759", "type": "Scope" }, + { "id": "cc83893a-e232-4723-b5af-bd0b01bcfe65", "type": "Scope" }, + { "id": "233e0cf1-dd62-48bc-b65b-b38fe87fcf8e", "type": "Scope" }, + { "id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378", "type": "Scope" }, + { "id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4", "type": "Scope" }, + { "id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87", "type": "Scope" }, + { "id": "48638b3c-ad68-4383-8ac4-e6880ee6ca57", "type": "Scope" }, + { "id": "39d65650-9d3e-4223-80db-a335590d027e", "type": "Scope" }, + { "id": "4a06efd2-f825-4e34-813e-82a57b03d1ee", "type": "Scope" }, + { "id": "f3bfad56-966e-4590-a536-82ecf548ac1e", "type": "Scope" }, + { "id": "4d135e65-66b8-41a8-9f8b-081452c91774", "type": "Scope" }, + { "id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075", "type": "Scope" }, + { "id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11", "type": "Scope" }, + { "id": "edb72de9-4252-4d03-a925-451deef99db7", "type": "Scope" }, + { "id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8", "type": "Scope" }, + { "id": "7e823077-d88e-468f-a337-e18f1f0e6c7c", "type": "Scope" }, + { "id": "edd3c878-b384-41fd-95ad-e7407dd775be", "type": "Scope" }, + { "id": "40b534c3-9552-4550-901b-23879c90bcf9", "type": "Scope" }, + { "id": "bf3fbf03-f35f-4e93-963e-47e4d874c37a", "type": "Scope" }, + { "id": "5248dcb1-f83b-4ec3-9f4d-a4428a961a72", "type": "Scope" }, + { "id": "c395395c-ff9a-4dba-bc1f-8372ba9dca84", "type": "Scope" }, + { "id": "2e25a044-2580-450d-8859-42eeb6e996c0", "type": "Scope" }, + { "id": "0ce33576-30e8-43b7-99e5-62f8569a4002", "type": "Scope" }, + { "id": "207e0cb1-3ce7-4922-b991-5a760c346ebc", "type": "Scope" }, + { "id": "093f8818-d05f-49b8-95bc-9d2a73e9a43c", "type": "Scope" }, + { "id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0", "type": "Scope" }, + { "id": "2104a4db-3a2f-4ea0-9dba-143d457dc666", "type": "Scope" }, + { "id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b", "type": "Scope" }, + { "id": "55896846-df78-47a7-aa94-8d3d4442ca7f", "type": "Scope" }, + { "id": "aa85bf13-d771-4d5d-a9e6-bca04ce44edf", "type": "Scope" }, + { "id": "ee928332-e9c2-4747-b4a0-f8c164b68de6", "type": "Scope" }, + { "id": "c975dd04-a06e-4fbb-9704-62daad77bb49", "type": "Scope" }, + { "id": "c37c9b61-7762-4bff-a156-afc0005847a0", "type": "Scope" }, + { "id": "b9abcc4f-94fc-4457-9141-d20ce80ec952", "type": "Scope" }, + { "id": "128ca929-1a19-45e6-a3b8-435ec44a36ba", "type": "Scope" }, + { "id": "b27add92-efb2-4f16-84f5-8108ba77985c", "type": "Scope" }, + { "id": "3404d2bf-2b13-457e-a330-c24615765193", "type": "Scope" }, + { "id": "b955410e-7715-4a88-a940-dfd551018df3", "type": "Scope" }, + { "id": "9e4862a5-b68f-479e-848a-4e07e25c9916", "type": "Scope" }, + { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" }, + { "id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515", "type": "Scope" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "19b94e34-907c-4f43-bde9-38b1909ed408", "type": "Role" }, + { "id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9", "type": "Role" }, + { "id": "292d869f-3427-49a8-9dab-8c70152b74e9", "type": "Role" }, + { "id": "2f51be20-0bb4-4fed-bf7b-db946066c75e", "type": "Role" }, + { "id": "58ca0d9a-1575-47e1-a3cb-007ef2e4583b", "type": "Role" }, + { "id": "06a5fe6d-c49d-46a7-b082-56b1b14103c7", "type": "Role" }, + { "id": "246dd0d5-5bd0-4def-940b-0421030a5b68", "type": "Role" }, + { "id": "bf394140-e372-4bf9-a898-299cfc7564e5", "type": "Role" }, + { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" }, + { "id": "230c1aed-a721-4c5d-9cb4-a90514e508ef", "type": "Role" }, + { "id": "b633e1c5-b582-4048-a93e-9f11b44c7e96", "type": "Role" }, + { "id": "5b567255-7703-4780-807c-7be8301ae99b", "type": "Role" }, + { "id": "62a82d76-70ea-41e2-9197-370581804d09", "type": "Role" }, + { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" }, + { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, + { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, + { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, + { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, + { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, + { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, + { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, + { "id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e", "type": "Role" }, + { "id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695", "type": "Role" }, + { "id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f", "type": "Role" }, + { "id": "01c0a623-fc9b-48e9-b794-0756f8e8f067", "type": "Role" }, + { "id": "50483e42-d915-4231-9639-7fdb7fd190e5", "type": "Role" }, + { "id": "dbb9058a-0e50-45d7-ae91-66909b5d4664", "type": "Role" }, + { "id": "a82116e5-55eb-4c41-a434-62fe8a61c773", "type": "Role" }, + { "id": "f3a65bd4-b703-46df-8f7e-0174fea562aa", "type": "Role" }, + { "id": "59a6b24b-4225-4393-8165-ebaec5f55d7a", "type": "Role" }, + { "id": "0121dc95-1b9f-4aed-8bac-58c5ac466691", "type": "Role" }, + { "id": "3b55498e-47ec-484f-8136-9013221c06a9", "type": "Role" }, + { "id": "35930dcf-aceb-4bd1-b99a-8ffed403c974", "type": "Role" }, + { "id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec", "type": "Role" }, + { "id": "29c18626-4985-4dcd-85c0-193eef327366", "type": "Role" }, + { "id": "4437522e-9a86-4a41-a7da-e380edd4a97d", "type": "Role" }, + { "id": "34bf0e97-1971-4929-b999-9e2442d941d7", "type": "Role" }, + { "id": "45cc0394-e837-488b-a098-1918f48d186c", "type": "Role" }, + { "id": "be74164b-cff1-491c-8741-e671cb536e13", "type": "Role" }, + { "id": "2a60023f-3219-47ad-baa4-40e17cd02a1d", "type": "Role" }, + { "id": "338163d7-f101-4c92-94ba-ca46fe52447c", "type": "Role" }, + { "id": "cac88765-0581-4025-9725-5ebc13f729ee", "type": "Role" }, + { "id": "75359482-378d-4052-8f01-80520e7db3cd", "type": "Role" }, + { "id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7", "type": "Role" }, + { "id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30", "type": "Scope" }, + { "id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64", "type": "Scope" }, + { "id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9", "type": "Scope" }, + { "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" }, + { "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" }, + { "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", "type": "Scope" }, + { "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }, + { "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }, + { "id": "b6890674-9dd5-4e42-bb15-5af07f541ae1", "type": "Role" } + ] + }, + { + "resourceAppId": "00000002-0000-0000-c000-000000000000", + "resourceAccess": [ + { "id": "5778995a-e1bf-45b8-affa-663a9f3f4d04", "type": "Role" }, + { "id": "a42657d6-7f20-40e3-b6f0-cee03008a62a", "type": "Scope" }, + { "id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6", "type": "Scope" } + ] + }, + { + "resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92", + "resourceAccess": [ + { "id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe", "type": "Scope" }, + { "id": "41269fc5-d04d-4bfd-bce7-43a51cea049a", "type": "Role" } + ] + }, + { + "resourceAppId": "00000002-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c", "type": "Scope" }, + { "id": "dc50a0fb-09a3-484d-be87-e023b12c6440", "type": "Role" } + ] + }, + { + "resourceAppId": "00000003-0000-0ff1-ce00-000000000000", + "resourceAccess": [ + { "id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0", "type": "Scope" } + ] + }, + { + "resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239", + "resourceAccess": [ + { "id": "e60370c1-e451-437e-aa6e-d76df38e5f15", "type": "Scope" } + ] + }, + { + "resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2", + "resourceAccess": [ + { "id": "594c1fb6-4f81-4475-ae41-0c394909246c", "type": "Scope" } + ] + } + ] +} From 92be750ef38e70fa86822d1c595dbf134e529080 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 24 Jun 2024 13:35:51 +0200 Subject: [PATCH 81/91] Updated to RiskDetection --- ...nIns.ps1 => Invoke-ListRiskDetections.ps1} | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) rename Modules/CIPPCore/Public/Entrypoints/{Invoke-ListRiskySignIns.ps1 => Invoke-ListRiskDetections.ps1} (54%) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 similarity index 54% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 index 9a14ab116ace..631c4e62329d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskySignIns.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 @@ -1,11 +1,11 @@ using namespace System.Net -Function Invoke-ListRiskySignIns { +Function Invoke-ListRiskDetections { <# .FUNCTIONALITY Entrypoint .ROLE - Identity.AuditLog.Read + IdentityRiskEvent.ReadWrite.All #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -13,22 +13,12 @@ Function Invoke-ListRiskySignIns { Write-Host 'PowerShell HTTP trigger function processed a request.' Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.Query.TenantFilter - $Days = $Request.Query.Days ?? 14 try { - $filters = if ($Request.Query.Filter) { - $Request.Query.filter - } else { - $ts = (Get-Date).AddDays(-$Days).ToUniversalTime() - $endTime = $ts.ToString('yyyy-MM-dd') - "createdDateTime ge $($endTime) and userDisplayName ne 'On-Premises Directory Synchronization Service Account' and riskState ne 'none'" - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved risky sign in report' -Sev 'Debug' -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved risk detections' -Sev 'Debug' -tenant $TenantFilter - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&`$filter=$($filters)" -tenantid $TenantFilter + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identityProtection/riskDetections" -tenantid $TenantFilter $response = $GraphRequest | Select-Object *, - @{l = 'additionalDetails'; e = { $_.status.additionalDetails } } , - @{l = 'errorCode'; e = { $_.status.errorCode } }, @{l = 'locationcipp'; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ @@ -38,7 +28,7 @@ Function Invoke-ListRiskySignIns { } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Risky Sign In report: $ErrorMessage" -Sev 'Error' -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Risk Detections: $ErrorMessage" -Sev 'Error' -tenant $TenantFilter Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = '500' Body = $ErrorMessage From 8a366b023f8e654d136413b01974a58ca3fac9a7 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 24 Jun 2024 14:35:27 +0200 Subject: [PATCH 82/91] Added Risky Users --- .../Users/Invoke-ListRiskyUsers.ps1 | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 new file mode 100644 index 000000000000..18739a6fc01d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 @@ -0,0 +1,35 @@ +using namespace System.Net + +Function Invoke-ListRiskyUsers { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + IdentityRiskyUser.ReadWrite.All + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.TenantFilter + + try { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved risky users' -Sev 'Debug' -tenant $TenantFilter + + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identityProtection/riskyUsers" -tenantid $TenantFilter + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) + } + catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve risky users: $ErrorMessage" -Sev 'Error' -tenant $TenantFilter + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = '500' + Body = $ErrorMessage + }) + } +} From fe099badc9f1ad75fe646533e0461cb33b0ea82e Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 24 Jun 2024 14:48:47 +0200 Subject: [PATCH 83/91] Added Error message for missing license --- .../GraphHelper/Get-NormalizedError.ps1 | 127 +++++++++--------- 1 file changed, 64 insertions(+), 63 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 index 42bdbfcd5356..46f092f6aff3 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 @@ -1,63 +1,64 @@ -function Get-NormalizedError { - <# - .FUNCTIONALITY - Internal - #> - [CmdletBinding()] - param ( - [string]$message - ) - - #Check if the message is valid JSON. - try { - $JSONMsg = $message | ConvertFrom-Json - } catch { - } - #if the message is valid JSON, there can be multiple fields in which the error resides. These are: - # $message.error.Innererror.Message - # $message.error.Message - # $message.error.details.message - # $message.error.innererror.internalException.message - - #We need to check if the message is in one of these fields, and if so, return it. - if ($JSONMsg.error.innererror.message) { - Write-Host 'innererror.message found' - $message = $JSONMsg.error.innererror.message - } elseif ($JSONMsg.error.message) { - Write-Host 'error.message found' - $message = $JSONMsg.error.message - } elseif ($JSONMsg.error.details.message) { - Write-Host 'error.details.message found' - $message = $JSONMsg.error.details.message - } elseif ($JSONMsg.error.innererror.internalException.message) { - Write-Host 'error.innererror.internalException.message found' - $message = $JSONMsg.error.innererror.internalException.message - } - - - #finally, put the message through the translator. If it's not in the list, just return the original message - switch -Wildcard ($message) { - 'Request not applicable to target tenant.' { 'Required license not available for this tenant' } - "Neither tenant is B2C or tenant doesn't have premium license" { 'This feature requires a P1 license or higher' } - 'Response status code does not indicate success: 400 (Bad Request).' { 'Error 400 occured. There is an issue with the token configuration for this tenant. Please perform an access check' } - '*Microsoft.Skype.Sync.Pstn.Tnm.Common.Http.HttpResponseException*' { 'Could not connect to Teams Admin center - Tenant might be missing a Teams license' } - '*Provide valid credential.*' { 'Error 400: There is an issue with your Exchange Token configuration. Please perform an access check for this tenant' } - '*This indicate that a subscription within the tenant has lapsed*' { 'There is subscription for this service available, Check licensing information.' } - '*User was not found.*' { 'The relationship between this tenant and the partner has been dissolved from the tenant side.' } - '*The user or administrator has not consented to use the application*' { 'CIPP cannot access this tenant. Perform a CPV Refresh and Access Check via the settings menu' } - '*AADSTS50020*' { 'AADSTS50020: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } - '*AADSTS50177' { 'AADSTS50177: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } - '*invalid or malformed*' { 'The request is malformed. Have you finished the SAM Setup?' } - '*Windows Store repository apps feature is not supported for this tenant*' { 'This tenant does not have WinGet support available' } - '*AADSTS650051*' { 'The application does not exist yet. Try again in 30 seconds.' } - '*AppLifecycle_2210*' { 'Failed to call Intune APIs: Does the tenant have a license available?' } - '*One or more added object references already exist for the following modified properties:*' { 'This user is already a member of this group.' } - '*Microsoft.Exchange.Management.Tasks.MemberAlreadyExistsException*' { 'This user is already a member of this group.' } - '*The property value exceeds the maximum allowed size (64KB)*' { 'One of the values exceeds the maximum allowed size (64KB).' } - '*Unable to initialize the authorization context*' { 'Your GDAP configuration does not allow us to write to this tenant, please check your group mappings and tenant onboarding.' } - '*Providers.Common.V1.CoreException*' { '403 (Access Denied) - We cannot connect to this tenant.' } - '*Authentication failed. MFA required*' { 'Authentication failed. MFA required' } - Default { $message } - - } -} +function Get-NormalizedError { + <# + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + param ( + [string]$message + ) + + #Check if the message is valid JSON. + try { + $JSONMsg = $message | ConvertFrom-Json + } catch { + } + #if the message is valid JSON, there can be multiple fields in which the error resides. These are: + # $message.error.Innererror.Message + # $message.error.Message + # $message.error.details.message + # $message.error.innererror.internalException.message + + #We need to check if the message is in one of these fields, and if so, return it. + if ($JSONMsg.error.innererror.message) { + Write-Host 'innererror.message found' + $message = $JSONMsg.error.innererror.message + } elseif ($JSONMsg.error.message) { + Write-Host 'error.message found' + $message = $JSONMsg.error.message + } elseif ($JSONMsg.error.details.message) { + Write-Host 'error.details.message found' + $message = $JSONMsg.error.details.message + } elseif ($JSONMsg.error.innererror.internalException.message) { + Write-Host 'error.innererror.internalException.message found' + $message = $JSONMsg.error.innererror.internalException.message + } + + + #finally, put the message through the translator. If it's not in the list, just return the original message + switch -Wildcard ($message) { + 'Request not applicable to target tenant.' { 'Required license not available for this tenant' } + "Neither tenant is B2C or tenant doesn't have premium license" { 'This feature requires a P1 license or higher' } + 'Response status code does not indicate success: 400 (Bad Request).' { 'Error 400 occured. There is an issue with the token configuration for this tenant. Please perform an access check' } + '*Microsoft.Skype.Sync.Pstn.Tnm.Common.Http.HttpResponseException*' { 'Could not connect to Teams Admin center - Tenant might be missing a Teams license' } + '*Provide valid credential.*' { 'Error 400: There is an issue with your Exchange Token configuration. Please perform an access check for this tenant' } + '*This indicate that a subscription within the tenant has lapsed*' { 'There is subscription for this service available, Check licensing information.' } + '*User was not found.*' { 'The relationship between this tenant and the partner has been dissolved from the tenant side.' } + '*The user or administrator has not consented to use the application*' { 'CIPP cannot access this tenant. Perform a CPV Refresh and Access Check via the settings menu' } + '*AADSTS50020*' { 'AADSTS50020: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } + '*AADSTS50177' { 'AADSTS50177: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } + '*invalid or malformed*' { 'The request is malformed. Have you finished the SAM Setup?' } + '*Windows Store repository apps feature is not supported for this tenant*' { 'This tenant does not have WinGet support available' } + '*AADSTS650051*' { 'The application does not exist yet. Try again in 30 seconds.' } + '*AppLifecycle_2210*' { 'Failed to call Intune APIs: Does the tenant have a license available?' } + '*One or more added object references already exist for the following modified properties:*' { 'This user is already a member of this group.' } + '*Microsoft.Exchange.Management.Tasks.MemberAlreadyExistsException*' { 'This user is already a member of this group.' } + '*The property value exceeds the maximum allowed size (64KB)*' { 'One of the values exceeds the maximum allowed size (64KB).' } + '*Unable to initialize the authorization context*' { 'Your GDAP configuration does not allow us to write to this tenant, please check your group mappings and tenant onboarding.' } + '*Providers.Common.V1.CoreException*' { '403 (Access Denied) - We cannot connect to this tenant.' } + '*Authentication failed. MFA required*' { 'Authentication failed. MFA required' } + '*Your tenant is not licensed for this feature.*' { 'Required license not available for this tenant' } + Default { $message } + + } +} From 0f3023a3017ee984da0859534ee34bc843749595 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 24 Jun 2024 16:49:42 +0200 Subject: [PATCH 84/91] Moved to ListGraphRequest --- .../Users/Invoke-ListRiskyUsers.ps1 | 35 ------------------ .../Entrypoints/Invoke-ListRiskDetections.ps1 | 37 ------------------- 2 files changed, 72 deletions(-) delete mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 delete mode 100644 Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 deleted file mode 100644 index 18739a6fc01d..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListRiskyUsers.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -using namespace System.Net - -Function Invoke-ListRiskyUsers { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - IdentityRiskyUser.ReadWrite.All - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - Write-Host 'PowerShell HTTP trigger function processed a request.' - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $Request.Query.TenantFilter - - try { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved risky users' -Sev 'Debug' -tenant $TenantFilter - - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identityProtection/riskyUsers" -tenantid $TenantFilter - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) - }) - } - catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve risky users: $ErrorMessage" -Sev 'Error' -tenant $TenantFilter - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = '500' - Body = $ErrorMessage - }) - } -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 deleted file mode 100644 index 631c4e62329d..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRiskDetections.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -using namespace System.Net - -Function Invoke-ListRiskDetections { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - IdentityRiskEvent.ReadWrite.All - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - Write-Host 'PowerShell HTTP trigger function processed a request.' - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $Request.Query.TenantFilter - - try { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved risk detections' -Sev 'Debug' -tenant $TenantFilter - - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identityProtection/riskDetections" -tenantid $TenantFilter - $response = $GraphRequest | Select-Object *, - @{l = 'locationcipp'; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($response) - }) - } - catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Risk Detections: $ErrorMessage" -Sev 'Error' -tenant $TenantFilter - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = '500' - Body = $ErrorMessage - }) - } -} From 7ec9a4e3faab5f04fb94551fb32cd9bf77fb6ff6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 24 Jun 2024 10:58:12 -0400 Subject: [PATCH 85/91] Fix tenant info in alerts --- .../Activity Triggers/Push-ExecScheduledCommand.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index f020fdd828c0..e94a5d904bf1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -66,8 +66,8 @@ function Push-ExecScheduledCommand { Write-Host 'Scheduler: Sending the results to the target.' Write-Host "The content of results is: $Results" switch -wildcard ($task.PostExecution) { - '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML } - '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML } + '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML -TenantFilter $tenant } + '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML -TenantFilter $tenant } '*webhook*' { $Webhook = [PSCustomObject]@{ 'Tenant' = $tenant From 58b895cb93d39d5fdfe471234d65735075a98829 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 24 Jun 2024 11:05:56 -0400 Subject: [PATCH 86/91] Add comment help to forwarding --- .../CIPPCore/Public/Set-CIPPForwarding.ps1 | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 b/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 index 593344a886ef..130ff65ff430 100644 --- a/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPForwarding.ps1 @@ -1,15 +1,50 @@ function Set-CIPPForwarding { + <# + .SYNOPSIS + Set forwarding for a user mailbox. + + .DESCRIPTION + Set forwarding for a user mailbox. + + .PARAMETER userid + User ID to set forwarding for. + + .PARAMETER forwardingSMTPAddress + SMTP address to forward to. + + .PARAMETER tenantFilter + Tenant to manage for forwarding. + + .PARAMETER username + Username to manage for forwarding. + + .PARAMETER ExecutingUser + CIPP user executing the command. + + .PARAMETER APIName + Name of the API executing the command. + + .PARAMETER Forward + Forwarding address. + + .PARAMETER KeepCopy + Keep a copy of the email. + + .PARAMETER Disable + Disable forwarding. + + #> [CmdletBinding(SupportsShouldProcess = $true)] param( - $userid, - $forwardingSMTPAddress, - $tenantFilter, - $username, - $ExecutingUser, - $APIName = 'Forwarding', - $Forward, - $KeepCopy, - $Disable + [string]$userid, + [string]$forwardingSMTPAddress, + [string]$tenantFilter, + [string]$username, + [string]$ExecutingUser, + [string]$APIName = 'Forwarding', + [string]$Forward, + [bool]$KeepCopy, + [bool]$Disable ) try { From bfcfc9ef9c4dd1fd026c8b0856b977f1f2f5b3a7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 24 Jun 2024 11:49:34 -0400 Subject: [PATCH 87/91] Fix logging --- .../Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 index d2d5839c2c9c..f9dbca2ab349 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -57,10 +57,11 @@ Function Invoke-ExecJITAdmin { } } } else { - Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message "Executing JIT Admin for $($Request.Body.UserPrincipalName)" -Sev 'Info' + if ($Request.Body.UserId -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') { $Username = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.UserId)" -tenantid $Request.Body.TenantFilter).userPrincipalName } + Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message "Executing JIT Admin for $Username" -Sev 'Info' $Start = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.StartDate)).DateTime.ToLocalTime() $Expiration = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.EndDate)).DateTime.ToLocalTime() From b382d5be2413e74902ead07555d09d546e3bf031 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 24 Jun 2024 15:27:20 -0400 Subject: [PATCH 88/91] Audit logging --- .../Push-AuditLogBundleProcessing.ps1 | 68 ++++++++----------- .../Webhooks/Push-AuditLogTenant.ps1 | 57 ++++++++++++++++ .../Public/GraphHelper/Get-Tenants.ps1 | 6 +- .../Get-CIPPAuditLogContentBundles.ps1 | 28 +++----- .../Webhooks/Test-CIPPAuditLogRules.ps1 | 12 ++-- Scheduler_PollAuditLogs/run.ps1 | 9 ++- 6 files changed, 110 insertions(+), 70 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 index d8bf577eac0d..13f2315e94a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 @@ -1,48 +1,40 @@ function Push-AuditLogBundleProcessing { Param($Item) - $TenantFilter = $Item.TenantFilter - Write-Information "Audit log tenant filter: $TenantFilter" - $ConfigTable = get-cipptable -TableName 'WebhookRules' - $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable - #$WebhookIncoming = Get-CIPPTable -TableName 'WebhookIncoming' - $SchedulerConfig = Get-CIPPTable -TableName 'SchedulerConfig' - $CIPPURL = Get-CIPPAzDataTableEntity @SchedulerConfig -Filter "PartitionKey eq 'webhookcreation'" | Select-Object -First 1 -ExpandProperty CIPPURL - $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } | ForEach-Object { - [pscustomobject]@{ - Tenants = ($_.Tenants | ConvertFrom-Json).fullValue - Conditions = $_.Conditions - Actions = $_.Actions - LogType = $_.Type + try { + $AuditBundleTable = Get-CippTable -tablename 'AuditLogBundles' + $AuditLogBundle = Get-CIPPAzDataTableEntity @AuditBundleTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and RowKey eq '$($Item.ContentId)'" + if ($AuditLogBundle.ProcessingStatus -ne 'Pending') { + Write-Information 'Audit log bundle already processed' + return + } + try { + $AuditLogTest = Test-CIPPAuditLogRules -TenantFilter $Item.TenantFilter -LogType $AuditLogBundle.ContentType -ContentUri $AuditLogBundle.ContentUri + $AuditLogBundle.ProcessingStatus = 'Completed' + $AuditLogBundle.MatchedRules = [string](ConvertTo-Json -Compress -Depth 10 -InputObject $AuditLogTest.MatchedRules) + $AuditLogBundle.MatchedLogs = $AuditLogTest.MatchedLogs + } catch { + $AuditLogBundle.ProcessingStatus = 'Failed' + $AuditLogBundle | Add-Member -NotePropertyName Error -NotePropertyValue $_.InvocationInfo.PositionMessage -TypeName string } - } - - if (($Configuration | Measure-Object).Count -eq 0) { - Write-Information "No configuration found for tenant $TenantFilter" - return - } - - $LogTypes = $Configuration.LogType | Select-Object -Unique - foreach ($LogType in $LogTypes) { - Write-Information "Querying for log type: $LogType" try { - $DataToProcess = (Test-CIPPAuditLogRules -TenantFilter $TenantFilter -LogType $LogType).DataToProcess + Add-CIPPAzDataTableEntity @AuditBundleTable -Entity $AuditLogBundle -Force + } catch { + Write-Host ( 'Error logging audit bundle: {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + } - Write-Information "Webhook: Data to process found: $($DataToProcess.count) items" - foreach ($AuditLog in $DataToProcess) { - Write-Information "Processing $($item.operation)" - $Webhook = @{ - Data = $AuditLog - CIPPURL = [string]$CIPPURL - TenantFilter = $TenantFilter - } - #Add-CIPPAzDataTableEntity @WebhookIncoming -Entity $Entity -Force - #Write-Information ($AuditLog | ConvertTo-Json -Depth 10) - Invoke-CippWebhookProcessing @Webhook + $DataToProcess = ($AuditLogTest).DataToProcess + Write-Information "Webhook: Data to process found: $($DataToProcess.count) items" + foreach ($AuditLog in $DataToProcess) { + Write-Information "Processing $($AuditLog.operation)" + $Webhook = @{ + Data = $AuditLog + CIPPURL = [string]$AuditLogBundle.CIPPURL + TenantFilter = $Item.TenantFilter } - } catch { - #Write-LogMessage -API 'Webhooks' -message 'Error processing webhooks' -sev Error -LogData (Get-CippException -Exception $_) - Write-Host ( 'Audit log error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + Invoke-CippWebhookProcessing @Webhook } + } catch { + Write-Host ( 'Audit log error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 new file mode 100644 index 000000000000..0f4c03e1c833 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 @@ -0,0 +1,57 @@ +function Push-AuditLogTenant { + Param($Item) + + $AuditBundleTable = Get-CippTable -tablename 'AuditLogBundles' + $SchedulerConfig = Get-CIPPTable -TableName 'SchedulerConfig' + $CIPPURL = Get-CIPPAzDataTableEntity @SchedulerConfig -Filter "PartitionKey eq 'webhookcreation'" | Select-Object -First 1 -ExpandProperty CIPPURL + $WebhookTable = Get-CippTable -tablename 'webhookTable' + $Webhooks = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and Version eq '3'" | Where-Object { $_.Resource -match '^Audit' } + $ExistingBundles = Get-CIPPAzDataTableEntity @AuditBundleTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and ContentType eq '$ContentType'" + + $NewBundles = [System.Collections.Generic.List[object]]::new() + foreach ($Webhook in $Webhooks) { + $TenantFilter = $Webhook.PartitionKey + $LogType = $Webhook.Resource + Write-Information "Querying for $LogType on $TenantFilter" + $ContentBundleQuery = @{ + TenantFilter = $TenantFilter + ContentType = $LogType + StartTime = $Item.StartTime + EndTime = $Item.EndTime + } + $LogBundles = Get-CIPPAuditLogContentBundles @ContentBundleQuery + + foreach ($Bundle in $LogBundles) { + if ($ExistingBundles.RowKey -notcontains $Bundle.contentId) { + $NewBundles.Add([PSCustomObject]@{ + PartitionKey = $TenantFilter + RowKey = $Bundle.contentId + DefaultDomainName = $TenantFilter + ContentType = $Bundle.contentType + ContentUri = $Bundle.contentUri + ContentCreated = $Bundle.contentCreated + ContentExpiration = $Bundle.contentExpiration + CIPPURL = [string]$CIPPURL + ProcessingStatus = 'Pending' + MatchedRules = '' + MatchedLogs = 0 + }) + } + } + } + + if (($NewBundles | Measure-Object).Count -gt 0) { + Add-CIPPAzDataTableEntity @AuditBundleTable -Entity $NewBundles + Write-Information ($NewBundles | ConvertTo-Json -Depth 5 -Compress) + + $Batch = $NewBundles | Select-Object @{Name = 'ContentId'; Expression = { $_.RowKey } }, @{Name = 'TenantFilter'; Expression = { $_.PartitionKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogBundleProcessing' } } + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'AuditLogs' + Batch = @($Batch) + SkipLog = $true + } + $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) + Write-Host "Started orchestration with ID = '$InstanceId'" + } + +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 index fdcb3d3eb95b..fc635a188857 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -67,7 +67,7 @@ function Get-Tenants { $ActiveRelationships = $GDAPList | Where-Object { $_.customerId -notin $SkipListCache.customerId } $TenantList = $ActiveRelationships | Group-Object -Property customerId | ForEach-Object { - Write-Host "Processing $($_.Name) to add to tenant list." + #Write-Host "Processing $($_.Name) to add to tenant list." $ExistingTenantInfo = Get-CIPPAzDataTableEntity @TenantsTable -Filter "PartitionKey eq 'Tenants' and RowKey eq '$($_.Name)'" if ($TriggerRefresh.IsPresent -and $ExistingTenantInfo.customerId) { @@ -77,7 +77,7 @@ function Get-Tenants { } if ($ExistingTenantInfo -and $ExistingTenantInfo.RequiresRefresh -eq $false) { - Write-Host 'Existing tenant found. We already have it cached, skipping.' + #Write-Host 'Existing tenant found. We already have it cached, skipping.' $ExistingTenantInfo return } @@ -86,7 +86,7 @@ function Get-Tenants { if (-not $SkipDomains.IsPresent) { try { - Write-Host "Getting domains for $($_.Name)." + #Write-Host "Getting domains for $($_.Name)." $Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $LatestRelationship.customerId -NoAuthCheck:$true -ErrorAction Stop $defaultDomainName = ($Domains | Where-Object { $_.isDefault -eq $true }).id $initialDomainName = ($Domains | Where-Object { $_.isInitial -eq $true }).id diff --git a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 index 2f55cc17c07c..43fe9ac024c7 100644 --- a/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Get-CIPPAuditLogContentBundles.ps1 @@ -42,8 +42,9 @@ function Get-CIPPAuditLogContentBundles { $DefaultDomainName = (Get-Tenants | Where-Object { $_.customerId -eq $TenantFilter }).defaultDomainName } - $WebhookTable = Get-CippTable -TableName 'webhookTable' + $WebhookTable = Get-CippTable -tablename 'webhookTable' $WebhookConfig = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq '$DefaultDomainName' and Version eq '3' and Resource eq '$ContentType'" + if (!$WebhookConfig) { throw "No webhook config found for $DefaultDomainName - $ContentType" } @@ -54,9 +55,9 @@ function Get-CIPPAuditLogContentBundles { } if (!$ShowAll.IsPresent) { - if ($null -ne $WebhookConfig.LastContentCreated) { - $StartTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime() - $EndTime = $WebhookConfig.LastContentCreated.DateTime.ToLocalTime().AddMinutes(30) + if (!$StartTime) { + $StartTime = (Get-Date).AddMinutes(-30) + $EndTime = Get-Date } } @@ -69,6 +70,8 @@ function Get-CIPPAuditLogContentBundles { } } + Write-Information "StartTime: $StartTime" + Write-Information "EndTime: $EndTime" $GraphQuery = [System.UriBuilder]('https://manage.office.com/api/v1.0/{0}/activity/feed/subscriptions/content' -f $TenantFilter) $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($Item in ($Parameters.GetEnumerator())) { @@ -78,22 +81,7 @@ function Get-CIPPAuditLogContentBundles { Write-Verbose "GET [ $($GraphQuery.ToString()) ]" $LogBundles = New-GraphGetRequest -uri $GraphQuery.ToString() -tenantid $TenantFilter -scope 'https://manage.office.com/.default' -IncludeResponseHeaders - $AuditLogContents = $LogBundles | Select-Object contentUri, contentCreated, @{Name = 'TenantFilter'; Expression = { $TenantFilter } } + $AuditLogContents = $LogBundles | Select-Object contentId, contentUri, contentCreated, contentExpiration, contentType, @{Name = 'TenantFilter'; Expression = { $TenantFilter } }, @{ Name = 'DefaultDomainName'; Expression = { $DefaultDomainName } } - if (!$ShowAll.IsPresent) { - $LastContent = ($AuditLogContents | Sort-Object contentCreated -Descending | Select-Object -First 1 -ExpandProperty contentCreated) | Get-Date - if ($WebhookConfig.LastContentCreated) { - $AuditLogContents = $AuditLogContents | Where-Object { ($_.contentCreated | Get-Date).ToLocalTime() -gt $StartTime } - } - if ($LastContent) { - if ($WebhookConfig.PSObject.Properties.Name -contains 'LastContentCreated') { - $WebhookConfig.LastContentCreated = [datetime]$LastContent - } else { - $WebhookConfig | Add-Member -MemberType NoteProperty -Name LastContentCreated -Value '' - $WebhookConfig.LastContentCreated = [datetime]$LastContent - } - $null = Add-CIPPAzDataTableEntity @WebhookTable -Entity $WebhookConfig -Force - } - } return $AuditLogContents } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 index 763efa62656b..dd3158876945 100644 --- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -4,9 +4,10 @@ function Test-CIPPAuditLogRules { [Parameter(Mandatory = $true)] $TenantFilter, [Parameter(Mandatory = $true)] + $ContentUri, + [Parameter(Mandatory = $true)] [ValidateSet('Audit.AzureActiveDirectory', 'Audit.Exchange')] - $LogType, - [switch]$ShowAll + $LogType ) $Results = [PSCustomObject]@{ @@ -34,13 +35,12 @@ function Test-CIPPAuditLogRules { LogType = $_.Type } } - $ContentBundleQuery = @{ + $AuditLogQuery = @{ TenantFilter = $TenantFilter - ContentType = $LogType - ShowAll = $ShowAll.IsPresent + ContentUri = $ContentUri } Write-Information 'Getting data from Office 365 Management Activity API' - $Data = Get-CIPPAuditLogContentBundles @ContentBundleQuery | Get-CIPPAuditLogContent + $Data = Get-CIPPAuditLogContent @AuditLogQuery $LogCount = ($Data | Measure-Object).Count Write-Information "Logs to process: $LogCount" $Results.TotalLogs = $LogCount diff --git a/Scheduler_PollAuditLogs/run.ps1 b/Scheduler_PollAuditLogs/run.ps1 index 9fb8105f809e..828cf3327c5e 100644 --- a/Scheduler_PollAuditLogs/run.ps1 +++ b/Scheduler_PollAuditLogs/run.ps1 @@ -8,16 +8,19 @@ try { return } - try { + <#try { $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq 'AuditLogCollection' -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' -and $_.Timestamp.DateTime.ToLocalTime() -lt (Get-Date).AddMinutes(-10) } if ($RunningQueue) { Write-Host 'Audit log collection already running' return } - } catch {} + } catch {}#> + + $StartTime = (Get-Date).AddMinutes(-30) + $EndTime = Get-Date $Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($Webhooks | Sort-Object -Property PartitionKey -Unique | Measure-Object).Count - $Batch = $Webhooks | Sort-Object -Property PartitionKey -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.PartitionKey } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogBundleProcessing' } } + $Batch = $Webhooks | Sort-Object -Property PartitionKey -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.PartitionKey } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } }, @{Name = 'StartTime'; Expression = { $StartTime } }, @{Name = 'EndTime'; Expression = { $EndTime } } $InputObject = [PSCustomObject]@{ OrchestratorName = 'AuditLogs' Batch = @($Batch) From 7db2b0571993f6079168157f1f80684f3548d084 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 24 Jun 2024 22:11:21 +0200 Subject: [PATCH 89/91] version up --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index a94a88fbb889..cf5136119071 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.8.5 \ No newline at end of file +5.9.0 \ No newline at end of file From 7fa9d5c49219ca69102c531392dd3067e112b385 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 24 Jun 2024 19:09:06 -0400 Subject: [PATCH 90/91] Update version_latest.txt --- version_latest.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index dc28d5028f5c..b3d91f9cfc04 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1,2 +1 @@ 5.9.0 - From 80997b5a60e591c6a277a985e0e1007cfed9a76f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 24 Jun 2024 20:37:36 -0400 Subject: [PATCH 91/91] Update version_latest.txt --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index b3d91f9cfc04..cf5136119071 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.9.0 +5.9.0 \ No newline at end of file