From 151bb02716ac1b31c458c97a69655edb369911fa Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 8 May 2024 22:57:22 -0400 Subject: [PATCH 001/138] JIT admin functions --- .../Public/Set-CIPPSchemaExtension.ps1 | 52 +++++++++++++++++++ .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 20 +++++++ 2 files changed, 72 insertions(+) create mode 100644 Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 create mode 100644 Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 diff --git a/Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 b/Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 new file mode 100644 index 000000000000..111e02daa7d1 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 @@ -0,0 +1,52 @@ +function Set-CIPPSchemaExtension { + [CmdletBinding()] + Param() + + $Schema = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/schemaExtensions?`$filter=owner eq '$($env:applicationid)'" -NoAuthCheck $true -AsApp $true + + $Properties = [PSCustomObject]@( + @{ + name = 'jitAdminEnabled' + type = 'Boolean' + } + @{ + name = 'jitAdminExpiration' + type = 'DateTime' + } + ) + $TargetTypes = @('User') + + if (!$Schema.id) { + $Body = [PSCustomObject]@{ + id = 'cippSchema' + description = 'CIPP Schema Extension' + targetTypes = $TargetTypes + properties = $Properties + } + + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + Write-Host $Json + $Schema = New-GraphPOSTRequest -type POST -Uri 'https://graph.microsoft.com/v1.0/schemaExtensions' -Body $Json -AsApp $true -NoAuthCheck $true + $Schema.status = 'Available' + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true + } else { + $Schema = $Schema | Where-Object { $_.id -match 'cippSchema' } + $Patch = @{} + if (Compare-Object -ReferenceObject ($Properties | Select-Object name, type) -DifferenceObject $Schema.properties) { + $Patch.properties = $Properties + } + if ($Schema.status -ne 'Available') { + $Patch.status = 'Available' + } + if ($Schema.targetTypes -ne $TargetTypes) { + $Patch.targetTypes = $TargetTypes + } + + if ($Patch.Keys.Count -gt 0) { + $Json = ConvertTo-Json -Depth 5 -InputObject $Patch + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true + } else { + $Schema + } + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 new file mode 100644 index 000000000000..143d12ae02b5 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -0,0 +1,20 @@ +function Set-CIPPUserJITAdmin { + [CmdletBinding()] + Param( + [string]$TenantFilter, + [string]$UserId, + [switch]$Enabled, + $Expiration + ) + $Schema = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/schemaExtensions?`$filter=owner eq '$($env:applicationid)'" -NoAuthCheck $true -AsApp $true | Where-Object { $_.owner -eq $env:applicationid } + + $Body = [PSCustomObject]@{ + "$($Schema.id)" = @{ + jitAdminEnabled = $Enabled.IsPresent + jitAdminExpiration = $Expiration + } + } + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + Write-Host $Json + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter +} \ No newline at end of file From 6a1b3990400fd26015727eca9ac2e894e7d41b2b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 16 May 2024 10:23:05 +0200 Subject: [PATCH 002/138] fix missing tenant info from emails --- .../Activity Triggers/Push-ExecScheduledCommand.ps1 | 4 ++-- .../Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index ddfa5a2f29eb..de573c156b7a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -60,8 +60,8 @@ function Push-ExecScheduledCommand { if ($Results) { $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 '', "$TableDesign
" | Out-String - $title = "$TaskType - $($task.Name)" + $HTML = $FinalResults -replace '
', "This alert is for tenant $tenant.

$TableDesign
" | Out-String + $title = "$TaskType - $($task.Name) - $tenant" Write-Host 'Scheduler: Sending the results to the target.' Write-Host "The content of results is: $Results" switch -wildcard ($task.PostExecution) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 index 235feac18ab3..d62e02a3a223 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 @@ -8,9 +8,9 @@ function Invoke-CIPPStandardOauthConsent { $StateIsCorrect = if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -eq 'managePermissionGrantsForSelf.cipp-consent-policy') { $true } else { $false } If ($Settings.remediate -eq $true) { - $AllowedAppIdsForTenant = $Settings.AllowedApps -split ',' + $AllowedAppIdsForTenant = $settings.AllowedApps -split ',' try { - if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('ManagePermissionGrantsForSelf.cipp-1sent-policy')) { + if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('managePermissionGrantsForSelf.cipp-consent-policy')) { $Existing = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies/' -tenantid $tenant) | Where-Object -Property id -EQ 'cipp-consent-policy' if (!$Existing) { New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/permissionGrantPolicies' -Type POST -Body '{ "id":"cipp-consent-policy", "displayName":"Application Consent Policy", "description":"This policy controls the current application consent policies."}' -ContentType 'application/json' @@ -27,9 +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' } - if ($AllowedAppIdsForTenant) { - } - + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode has been enabled.' -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message From 7e7687cc31f8805e5f7bcc366c285203c41e5679 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 16 May 2024 17:25:22 +0200 Subject: [PATCH 003/138] hotfix --- Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 | 8 ++++++-- version_latest.txt | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 index c38b5c1c59b3..77a9e22e107b 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -103,7 +103,7 @@ function Get-Tenants { } } - [PSCustomObject]@{ + $obj = [PSCustomObject]@{ PartitionKey = 'Tenants' RowKey = $_.Name customerId = $_.Name @@ -111,7 +111,6 @@ function Get-Tenants { relationshipEnd = $LatestRelationship.relationshipEnd relationshipCount = $_.Count defaultDomainName = $defaultDomainName - initialDomainName = $initialDomainName hasAutoExtend = $AutoExtend delegatedPrivilegeStatus = 'granularDelegatedAdminPrivileges' domains = '' @@ -123,6 +122,10 @@ function Get-Tenants { RequiresRefresh = [bool]$RequiresRefresh LastRefresh = (Get-Date).ToUniversalTime() } + if ($Obj.defaultDomainName -eq 'Invalid' -or !$Obj.defaultDomainName) { + continue + } + Add-CIPPAzDataTableEntity @TenantsTable -Entity $obj -Force | Out-Null } } $IncludedTenantsCache = [system.collections.generic.list[object]]::new() @@ -145,6 +148,7 @@ function Get-Tenants { RequiresRefresh = [bool]$RequiresRefresh LastRefresh = (Get-Date).ToUniversalTime() }) | Out-Null + } foreach ($Tenant in $TenantList) { if ($Tenant.defaultDomainName -eq 'Invalid' -or !$Tenant.defaultDomainName) { diff --git a/version_latest.txt b/version_latest.txt index 3b867ccd76c3..262122f6796a 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.0 \ No newline at end of file +5.7.1 \ No newline at end of file From 7ad5f266e87f4f5c56302347fbd6c3a89f10e2e4 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 16 May 2024 14:03:53 -0400 Subject: [PATCH 004/138] Optimize graph request list --- .../GraphRequests/Get-GraphRequestList.ps1 | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index 80fd965ad859..20620029e0e9 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -66,6 +66,8 @@ function Get-GraphRequestList { [string]$ReverseTenantLookupProperty = 'tenantId' ) + $SingleTenantThreshold = 8000 + $TableName = ('cache{0}' -f ($Endpoint -replace '[^A-Za-z0-9]'))[0..62] -join '' Write-Information "Table: $TableName" $Endpoint = $Endpoint -replace '^/', '' @@ -86,39 +88,64 @@ function Get-GraphRequestList { $GraphQuery.Query = $ParamCollection.ToString() $PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString()) -join '-') Write-Information "PK: $PartitionKey" - Write-Information ( 'GET [ {0} ]' -f $GraphQuery.ToString()) + # Perform $count check before caching + $Count = 0 + if ($TenantFilter -ne 'AllTenants') { + $GraphRequest = @{ + uri = $GraphQuery.ToString() + tenantid = $TenantFilter + ComplexFilter = $true + } + + if ($NoPagination.IsPresent) { + $GraphRequest.noPagination = $NoPagination.IsPresent + } + if ($CountOnly.IsPresent) { + $GraphRequest.CountOnly = $CountOnly.IsPresent + } + if ($NoAuthCheck.IsPresent) { + $GraphRequest.noauthcheck = $NoAuthCheck.IsPresent + } + if ($Parameters.'$count' -and !$SkipCache.IsPresent -and !$NoPagination.IsPresent) { + $Count = New-GraphGetRequest @GraphRequest -CountOnly -ErrorAction Stop + if ($CountOnly.IsPresent) { return $Count } + Write-Information "Total results (`$count): $Count" + } + } + try { if ($QueueId) { $Table = Get-CIPPTable -TableName $TableName $Filter = "QueueId eq '{0}'" -f $QueueId $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter $Type = 'Queue' - } elseif ($TenantFilter -eq 'AllTenants' -or (!$SkipCache.IsPresent -and !$ClearCache.IsPresent -and !$CountOnly.IsPresent)) { - $Table = Get-CIPPTable -TableName $TableName - $Timestamp = (Get-Date).AddHours(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') - if ($TenantFilter -eq 'AllTenants') { - $Filter = "PartitionKey eq '{0}' and QueueType eq 'AllTenants' and Timestamp ge datetime'{1}'" -f $PartitionKey, $Timestamp - } else { - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}' and Timestamp ge datetime'{2}'" -f $PartitionKey, $TenantFilter, $Timestamp + Write-Information "Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))" + $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } + } elseif (!$SkipCache.IsPresent -and !$ClearCache.IsPresent -and !$CountOnly.IsPresent) { + if ($TenantFilter -eq 'AllTenants' -or $Count -gt $SingleTenantThreshold) { + $Table = Get-CIPPTable -TableName $TableName + $Timestamp = (Get-Date).AddHours(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') + if ($TenantFilter -eq 'AllTenants') { + $Filter = "PartitionKey eq '{0}' and QueueType eq 'AllTenants' and Timestamp ge datetime'{1}'" -f $PartitionKey, $Timestamp + } else { + $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}' and Timestamp ge datetime'{2}'" -f $PartitionKey, $TenantFilter, $Timestamp + } + $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter + $Type = 'Cache' + Write-Information "Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))" + $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey + $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } } - #Write-Information $Filter - $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter - $Type = 'Cache' - } else { - $Type = 'None' - $Rows = @() } - Write-Information "Cached: $(($Rows | Measure-Object).Count) rows (Type: $($Type))" - - $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey - $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } } catch { Write-Information $_.InvocationInfo.PositionMessage } if ($TenantFilter -ne 'AllTenants' -and $Endpoint -match '%tenantid%') { + Write-Information "Replacing TenantId in endpoint with $TenantFilter" $TenantId = (Get-Tenants -IncludeErrors | Where-Object { $_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter }).customerId $Endpoint = $Endpoint -replace '%tenantid%', $TenantId $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) @@ -127,6 +154,7 @@ function Get-GraphRequestList { $ParamCollection.Add($Item.Key, $Item.Value) } $GraphQuery.Query = $ParamCollection.ToString() + $GraphRequest.uri = $GraphQuery.ToString() } if (!$Rows) { @@ -208,31 +236,10 @@ function Get-GraphRequestList { } } default { - $GraphRequest = @{ - uri = $GraphQuery.ToString() - tenantid = $TenantFilter - ComplexFilter = $true - } - - if ($NoPagination.IsPresent) { - $GraphRequest.noPagination = $NoPagination.IsPresent - } - - if ($CountOnly.IsPresent) { - $GraphRequest.CountOnly = $CountOnly.IsPresent - } - - if ($NoAuthCheck.IsPresent) { - $GraphRequest.noauthcheck = $NoAuthCheck.IsPresent - } - try { $QueueThresholdExceeded = $false if ($Parameters.'$count' -and !$SkipCache -and !$NoPagination) { - $Count = New-GraphGetRequest @GraphRequest -CountOnly -ErrorAction Stop - if ($CountOnly.IsPresent) { return $Count } - Write-Information "Total results (`$count): $Count" - if ($Count -gt 8000) { + if ($Count -gt $singleTenantThreshold) { $QueueThresholdExceeded = $true if ($RunningQueue) { Write-Information 'Queue currently running' From 4ea7cca17e8a00df0a3093f52deda445003c13ed Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 17 May 2024 13:17:38 -0400 Subject: [PATCH 005/138] Add select value to extension mappings --- .../NinjaOne/Get-NinjaOneOrgMapping.ps1 | 16 ++++++++-------- .../CippExtensions/Private/Get-HaloMapping.ps1 | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 index 8f9e3d89936b..a0274cb0d16f 100644 --- a/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 +++ b/Modules/CippExtensions/NinjaOne/Get-NinjaOneOrgMapping.ps1 @@ -13,14 +13,14 @@ function Get-NinjaOneOrgMapping { $Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.NinjaOneName)"; value = "$($_.NinjaOne)" } } #Get Available Tenants - + #Get available Ninja clients $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json -ea stop).NinjaOne - - + + $Token = Get-NinjaOneToken -configuration $Configuration - + $After = 0 $PageSize = 1000 $NinjaOrgs = do { @@ -29,16 +29,16 @@ function Get-NinjaOneOrgMapping { $ResultCount = ($Result.id | Measure-Object -Maximum) $After = $ResultCount.maximum - } while ($ResultCount.count -eq $PageSize) - + } while ($ResultCount.count -eq $PageSize) + } catch { $Message = if ($_.ErrorDetails.Message) { Get-NormalizedError -Message $_.ErrorDetails.Message } else { $_.Exception.message } - - $NinjaOrgs = @(@{ name = $Message }) + + $NinjaOrgs = @(@{ name = 'Could not get NinjaOne Orgs, check your API credentials and try again.'; value = '-1' }) } $MappingObj = [PSCustomObject]@{ diff --git a/Modules/CippExtensions/Private/Get-HaloMapping.ps1 b/Modules/CippExtensions/Private/Get-HaloMapping.ps1 index 8391252ae065..fcae99cfd5d1 100644 --- a/Modules/CippExtensions/Private/Get-HaloMapping.ps1 +++ b/Modules/CippExtensions/Private/Get-HaloMapping.ps1 @@ -32,7 +32,7 @@ function Get-HaloMapping { } Write-LogMessage -Message "Could not get HaloPSA Clients, error: $Message " -Level Error -tenant 'CIPP' -API 'HaloMapping' - $RawHaloClients = @(@{name = "Could not get HaloPSA Clients, error: $Message" }) + $RawHaloClients = @(@{name = "Could not get HaloPSA Clients, error: $Message"; value = '-1' }) } $HaloClients = $RawHaloClients | ForEach-Object { [PSCustomObject]@{ From b47bc2b9141a1f4b263e1b00ec56636cfd9033f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 17 May 2024 20:01:31 +0200 Subject: [PATCH 006/138] Fix DKIM standard logging and Set part parms --- .../Standards/Invoke-CIPPStandardAddDKIM.ps1 | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index b4673244d148..cfaea620aa4d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -5,7 +5,7 @@ function Invoke-CIPPStandardAddDKIM { #> param($Tenant, $Settings) - $AllDomains = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/domains?$top=999' -tenantid $Tenant | Where-Object { $_.supportedServices -contains 'Email' }).id + $AllDomains = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/domains?$top=999' -tenantid $Tenant | Where-Object { $_.supportedServices -contains 'Email' -or $_.id -like '*mail.onmicrosoft.com' }).id $DKIM = (New-ExoRequest -tenantid $tenant -cmdlet 'Get-DkimSigningConfig') | Select-Object Domain, Enabled, Status # List of domains for each way to enable DKIM @@ -18,6 +18,8 @@ function Invoke-CIPPStandardAddDKIM { Write-LogMessage -API 'Standards' -tenant $tenant -message 'DKIM is already enabled for all available domains.' -sev Info } else { $ErrorCounter = 0 + Write-LogMessage -API 'Standards' -tenant $tenant -message "Trying to enable DKIM for:$($NewDomains -join ', ' ) $($SetDomains.Domain -join ', ')" -sev Info + # New-domains $Request = $NewDomains | ForEach-Object { @{ @@ -27,39 +29,42 @@ function Invoke-CIPPStandardAddDKIM { } } } - - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) -useSystemMailbox $true + if ($null -ne $Request) { $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) -useSystemMailbox $true } $BatchResults | ForEach-Object { if ($_.error) { $ErrorCounter ++ $ErrorMessage = Get-NormalizedError -Message $_.error Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable DKIM. Error: $ErrorMessage" -sev Error + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for a domain' -sev Info } } + # Set-domains $Request = $SetDomains | ForEach-Object { @{ CmdletInput = @{ CmdletName = 'Set-DkimSigningConfig' - Parameters = @{ Identity = $Domain.Domain; Enabled = $true } + Parameters = @{ Identity = $_.Domain; Enabled = $true } } } } - - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) -useSystemMailbox $true + if ($null -ne $Request) { $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) -useSystemMailbox $true } $BatchResults | ForEach-Object { if ($_.error) { + $ErrorCounter ++ $ErrorMessage = Get-NormalizedError -Message $_.error Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set DKIM. Error: $ErrorMessage" -sev Error - $ErrorCounter ++ - } - - if ($ErrorCounter -eq 0) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for all domains in tenant' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Failed to enable DKIM for all domains in tenant' -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for a domain' -sev Info } } + + if ($ErrorCounter -eq 0) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for all domains in tenant' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Failed to enable DKIM for all domains in tenant' -sev Error + } } } From 0afacfd1ad1604e811a7a2fbd7a2a129aa43c767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 17 May 2024 20:05:06 +0200 Subject: [PATCH 007/138] Remove logging that does not work --- .../CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index cfaea620aa4d..dc1a1a2643ce 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -35,8 +35,6 @@ function Invoke-CIPPStandardAddDKIM { $ErrorCounter ++ $ErrorMessage = Get-NormalizedError -Message $_.error Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable DKIM. Error: $ErrorMessage" -sev Error - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for a domain' -sev Info } } @@ -55,8 +53,6 @@ function Invoke-CIPPStandardAddDKIM { $ErrorCounter ++ $ErrorMessage = Get-NormalizedError -Message $_.error Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set DKIM. Error: $ErrorMessage" -sev Error - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for a domain' -sev Info } } From bc7ea4a7902a05b2baf35248bb0fec4fb82f119c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 17 May 2024 20:12:33 +0200 Subject: [PATCH 008/138] Logging for when DKIM is enabled for some domains but not all --- .../CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index dc1a1a2643ce..d4b8bd35166c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -58,6 +58,8 @@ function Invoke-CIPPStandardAddDKIM { if ($ErrorCounter -eq 0) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled DKIM for all domains in tenant' -sev Info + } elseif ($ErrorCounter -gt 0 -and $ErrorCounter -lt ($NewDomains.Count + $SetDomains.Count)) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Failed to enable DKIM for some domains in tenant' -sev Error } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Failed to enable DKIM for all domains in tenant' -sev Error } From 6775d82c2dce4e46964f11d8eac160c9b46ac109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 17 May 2024 21:59:04 +0200 Subject: [PATCH 009/138] Update Activity Based Timeout standard to have options --- ...nvoke-CIPPStandardActivityBasedTimeout.ps1 | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 index 90d632232fe6..29d1862ecb01 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 @@ -4,41 +4,61 @@ function Invoke-CIPPStandardActivityBasedTimeout { Internal #> param($Tenant, $Settings) - $State = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' -tenantid $tenant).id + + if ($Settings.timeout -eq 'Select a value') { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'No value selected for Activity Based Timeout' -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)*" If ($Settings.remediate -eq $true) { try { - if (!$State) { - $body = @' -{ - "displayName": "DefaultTimeoutPolicy", - "isOrganizationDefault": true, - "definition":["{\"ActivityBasedTimeoutPolicy\":{\"Version\":1,\"ApplicationPolicies\":[{\"ApplicationId\":\"default\",\"WebSessionIdleTimeout\":\"01:00:00\"}]}}"] -} -'@ + if (!$StateIsCorrect) { + $PolicyTemplate = @{ + displayName = 'DefaultTimeoutPolicy' + isOrganizationDefault = $true + definition = @( + "{`"ActivityBasedTimeoutPolicy`":{`"Version`":1,`"ApplicationPolicies`":[{`"ApplicationId`":`"default`",`"WebSessionIdleTimeout`":`"$($Settings.timeout)`"}]}}" + ) + } + $body = ConvertTo-Json -InputObject $PolicyTemplate -Depth 10 -Compress - New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' -Type POST -Body $body -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled Activity Based Timeout of one hour' -sev Info + # Switch between parameter sets if the policy already exists + if ($null -eq $State.id) { + $RequestType = 'POST' + $URI = 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' + } 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' + Write-LogMessage -API 'Standards' -tenant $tenant -message "Enabled Activity Based Timeout with a value of $($Settings.timeout)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Activity Based Timeout is already enabled' -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Activity Based Timeout is already enabled and set to $($Settings.timeout)" -sev Info } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable Activity Based Timeout $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable Activity Based Timeout a value of $($Settings.timeout). Error: $ErrorMessage" -sev Error } } if ($Settings.alert -eq $true) { - if ($State) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Activity Based Timeout is enabled' -sev Info + if ($StateIsCorrect) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Activity Based Timeout is enabled and set to $($Settings.timeout)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Activity Based Timeout is not enabled' -sev Alert + Write-LogMessage -API 'Standards' -tenant $tenant -message "Activity Based Timeout is not set to $($Settings.timeout)" -sev Alert } } if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'ActivityBasedTimeout' -FieldValue $state -StoreAs bool -Tenant $tenant + + Add-CIPPBPAField -FieldName 'ActivityBasedTimeout' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } } From 63a8cf066837f8a279decce73555c42a966f8fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 17 May 2024 23:33:30 +0200 Subject: [PATCH 010/138] For some reason this needs to be inverted now to do what it says --- Modules/CIPPCore/Public/Set-CIPPDefaultAPEnrollment.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPDefaultAPEnrollment.ps1 b/Modules/CIPPCore/Public/Set-CIPPDefaultAPEnrollment.ps1 index 5d75e787f233..798dfdb71553 100644 --- a/Modules/CIPPCore/Public/Set-CIPPDefaultAPEnrollment.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPDefaultAPEnrollment.ps1 @@ -20,7 +20,7 @@ function Set-CIPPDefaultAPEnrollment { 'displayName' = 'All users and all devices' 'description' = 'This is the default enrollment status screen configuration applied with the lowest priority to all users and all devices regardless of group membership.' 'showInstallationProgress' = [bool]$ShowProgress - 'blockDeviceSetupRetryByUser' = [bool]$blockDevice + 'blockDeviceSetupRetryByUser' = ![bool]$blockDevice 'allowDeviceResetOnInstallFailure' = [bool]$AllowReset 'allowLogCollectionOnInstallFailure' = [bool]$EnableLog 'customErrorMessage' = "$ErrorMessage" From 939d1c2fcf29590a29451c29af9dbf7a961c259c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 20 May 2024 10:33:20 -0400 Subject: [PATCH 011/138] Scheduler fix --- Scheduler_GetQueue/run.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scheduler_GetQueue/run.ps1 b/Scheduler_GetQueue/run.ps1 index 87d355d1476c..f58f9d667ea6 100644 --- a/Scheduler_GetQueue/run.ps1 +++ b/Scheduler_GetQueue/run.ps1 @@ -21,7 +21,7 @@ $Tasks = foreach ($Tenant in $Tenants) { Tag = 'AllTenants' TenantID = $t.customerId Type = $Tenant.type - RowKey = $Tenant.RowKey + RowKey = $t.RowKey } } } From 863391f7f2dd2a612cc174abaacc91dd0f08a630 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 20 May 2024 11:29:02 -0400 Subject: [PATCH 012/138] Fix standards --- .../CIPPCore/Public/Standards/Get-CIPPStandards.ps1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 5b73e19eae98..60751d34303d 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -76,12 +76,13 @@ function Get-CIPPStandards { } } } - } - foreach ($Standard in $ComputedStandards.Keys) { - [pscustomobject]@{ - Tenant = $Tenant.defaultDomainName - Standard = $Standard - Settings = $ComputedStandards.$Standard + + foreach ($Standard in $ComputedStandards.Keys) { + [pscustomobject]@{ + Tenant = $Tenant.defaultDomainName + Standard = $Standard + Settings = $ComputedStandards.$Standard + } } } } From 80838e28aaf1df1ddefc32968d10958ae2d9e821 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 20 May 2024 17:45:18 -0400 Subject: [PATCH 013/138] up version --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index 262122f6796a..722fb619cef4 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.1 \ No newline at end of file +5.7.2 \ No newline at end of file From 4155a50382282f77c76f52732f79322b5c9963ee Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 21 May 2024 11:31:08 -0400 Subject: [PATCH 014/138] Domain Analyser tweak --- .../Domain Analyser/Push-DomainAnalyserTenant.ps1 | 13 +++++++++---- .../Domain Analyser/Push-GetTenantDomains.ps1 | 7 +++++++ 2 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 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 729ffbccee8b..a6e43f66dd78 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 @@ -41,8 +41,9 @@ function Push-DomainAnalyserTenant { $DomainCount = ($TenantDomains | Measure-Object).Count if ($DomainCount -gt 0) { Write-Host "$DomainCount tenant Domains" + $TenantDomainObjects = [System.Collections.Generic.List[object]]::new() try { - $TenantDomainObjects = foreach ($TenantDomain in $TenantDomains) { + foreach ($TenantDomain in $TenantDomains) { $TenantDetails = ($TenantDomain | ConvertTo-Json -Compress).ToString() $Filter = "PartitionKey eq '{0}' and RowKey eq '{1}'" -f $TenantDomain.Tenant, $TenantDomain.Domain $OldDomain = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter @@ -78,19 +79,23 @@ function Push-DomainAnalyserTenant { } } # Return domain object to list - $Domain + $TenantDomainObjects.Add($Domain) } # Batch insert tenant domains try { Add-CIPPAzDataTableEntity @DomainTable -Entity $TenantDomainObjects -Force $InputObject = [PSCustomObject]@{ - Batch = $TenantDomainObjects | Select-Object RowKey, @{n = 'FunctionName'; exp = { 'DomainAnalyserDomain' } } + QueueFunction = @{ + FunctionName = 'GetTenantDomains' + TenantGUID = $Tenant.customerId + } OrchestratorName = "DomainAnalyser_$($Tenant.defaultDomainName)" SkipLog = $true DurableMode = 'Sequence' } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) + Write-Host "Started orchestration for $DomainCount tenant domains in $($Tenant.defaultDomainName)" } catch { Write-LogMessage -API 'DomainAnalyser' -message 'Domain Analyser GetTenantDomains error' -sev info -LogData (Get-CippException -Exception $_) } @@ -99,7 +104,7 @@ function Push-DomainAnalyserTenant { } } } catch { - Write-Host (Get-CippException -Exception $_ | ConvertTo-Json) + #Write-Host (Get-CippException -Exception $_ | ConvertTo-Json) Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.defaultDomainName -message 'DNS Analyser GraphGetRequest' -LogData (Get-CippException -Exception $_) -sev Error } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 new file mode 100644 index 000000000000..8a2958ea6da1 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 @@ -0,0 +1,7 @@ +function Push-GetTenantDomains { + Param($Item) + $DomainTable = Get-CippTable -tablename 'Domains' + $Filter = "PartitionKey eq 'TenantDomains' and TenantGUID eq '{0}'" -f $Item.TenantGUID + $Domains = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter | Select-Object RowKey, @{n = 'FunctionName'; exp = { 'DomainAnalyserDomain' } } + return @($Domains) +} \ No newline at end of file From f0b507c4c3e986e4be65ef109401c8ea1fb450d6 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 21 May 2024 11:31:19 -0400 Subject: [PATCH 015/138] Disable logging for alert scheduled tasks --- .../Activity Triggers/Push-ExecScheduledCommand.ps1 | 4 +++- 1 file changed, 3 insertions(+), 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..b75de4bd1d4d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -107,5 +107,7 @@ function Push-ExecScheduledCommand { ScheduledTime = "$nextRunUnixTime" } } - Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Successfully executed task: $($task.Name)" -sev Info + if ($TaskType -ne 'Alert') { + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Successfully executed task: $($task.Name)" -sev Info + } } \ No newline at end of file From 40890edce37ad0c764d103cdb3409de677efc705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Tue, 21 May 2024 21:33:07 +0200 Subject: [PATCH 016/138] fix cust lockbox error message to say why it fails --- .../Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 index a7d8bd090172..b5741d27ac4d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 @@ -7,6 +7,7 @@ function Invoke-CIPPStandardEnableCustomerLockbox { $CustomerLockboxStatus = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').CustomerLockboxEnabled if ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' try { if ($CustomerLockboxStatus) { @@ -17,7 +18,11 @@ function Invoke-CIPPStandardEnableCustomerLockbox { } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable Customer Lockbox. Error: $ErrorMessage" -sev Error + if ($ErrorMessage -match 'Ex5E8EA4') { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable Customer Lockbox. E5 license required. Error: $ErrorMessage" -sev Error + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable Customer Lockbox. Error: $ErrorMessage" -sev Error + } } } From 61a4fe1674cb65deb522fb5bbe9cd09af543e027 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 24 May 2024 10:31:51 -0400 Subject: [PATCH 017/138] Domain Analyser tweak --- DomainAnalyser_OrchestrationStarter/run.ps1 | 1 - .../Push-DomainAnalyserDomain.ps1 | 20 +++++++++---------- .../Push-DomainAnalyserTenant.ps1 | 3 ++- .../Domain Analyser/Push-GetTenantDomains.ps1 | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/DomainAnalyser_OrchestrationStarter/run.ps1 b/DomainAnalyser_OrchestrationStarter/run.ps1 index a5a4b2f904f2..9c16b32afdba 100644 --- a/DomainAnalyser_OrchestrationStarter/run.ps1 +++ b/DomainAnalyser_OrchestrationStarter/run.ps1 @@ -16,7 +16,6 @@ $InputObject = [PSCustomObject]@{ } OrchestratorName = 'DomainAnalyser_Tenants' SkipLog = $true - DurableMode = 'Sequence' } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) 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 c80d265bf0ba..5366603a4492 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 @@ -122,8 +122,8 @@ function Push-DomainAnalyserDomain { } } catch { $Message = 'SPF Error' - Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -LogData (Get-CippException -Exception $_) -sev Error - throw $Message + Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message $Message -LogData (Get-CippException -Exception $_) -sev Error + return $Message } # Check SPF Record @@ -185,8 +185,8 @@ function Push-DomainAnalyserDomain { } } catch { $Message = 'DMARC Error' - Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -LogData (Get-CippException -Exception $_) -sev Error - throw $Message + Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message $Message -LogData (Get-CippException -Exception $_) -sev Error + return $Message } # DNS Sec Check @@ -203,8 +203,8 @@ function Push-DomainAnalyserDomain { } } catch { $Message = 'DNSSEC Error' - Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -LogData (Get-CippException -Exception $_) -sev Error - throw $Message + Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message $Message -LogData (Get-CippException -Exception $_) -sev Error + return $Message } # DKIM Check @@ -232,8 +232,8 @@ function Push-DomainAnalyserDomain { } } catch { $Message = 'DKIM Exception' - Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message $Message -LogData (Get-CippException -Exception $_) -sev Error - throw $Message + Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message $Message -LogData (Get-CippException -Exception $_) -sev Error + return $Message } # Final Score $Result.Score = $ScoreDomain @@ -248,9 +248,9 @@ function Push-DomainAnalyserDomain { Add-CIPPAzDataTableEntity @DomainTable -Entity $DomainObject -Force # Final Write to Output - Write-LogMessage -API 'DomainAnalyser' -tenant $tenant.tenant -message "DNS Analyser Finished For $Domain" -sev Info + Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message "DNS Analyser Finished For $Domain" -sev Info } catch { - Write-LogMessage -API -API 'DomainAnalyser' -tenant $tenant.tenant -message "Error saving domain $Domain to table " -sev Error -LogData (Get-CippException -Exception $_) + Write-LogMessage -API -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 a6e43f66dd78..09cd1f7ff95a 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 @@ -95,7 +95,8 @@ function Push-DomainAnalyserTenant { DurableMode = 'Sequence' } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) - Write-Host "Started orchestration for $DomainCount tenant domains in $($Tenant.defaultDomainName)" + Write-Host "Started analysis for $DomainCount tenant domains in $($Tenant.defaultDomainName)" + Write-LogMessage -API 'DomainAnalyser' -tenant $Tenant.defaultDomainName -message "Started analysis for $DomainCount tenant domains" -sev Info } catch { Write-LogMessage -API 'DomainAnalyser' -message 'Domain Analyser GetTenantDomains error' -sev info -LogData (Get-CippException -Exception $_) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 index 8a2958ea6da1..5fb9c64cdad1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Domain Analyser/Push-GetTenantDomains.ps1 @@ -2,6 +2,6 @@ function Push-GetTenantDomains { Param($Item) $DomainTable = Get-CippTable -tablename 'Domains' $Filter = "PartitionKey eq 'TenantDomains' and TenantGUID eq '{0}'" -f $Item.TenantGUID - $Domains = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter | Select-Object RowKey, @{n = 'FunctionName'; exp = { 'DomainAnalyserDomain' } } + $Domains = Get-CIPPAzDataTableEntity @DomainTable -Filter $Filter -Property RowKey | Select-Object RowKey, @{n = 'FunctionName'; exp = { 'DomainAnalyserDomain' } } return @($Domains) } \ No newline at end of file From b17050548ee0fe8c35fa02703782e98bce5d57ab Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 24 May 2024 10:59:45 -0400 Subject: [PATCH 018/138] Update Push-DomainAnalyserTenant.ps1 --- .../Domain Analyser/Push-DomainAnalyserTenant.ps1 | 1 - 1 file changed, 1 deletion(-) 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 09cd1f7ff95a..605c56bebb53 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 @@ -92,7 +92,6 @@ function Push-DomainAnalyserTenant { } OrchestratorName = "DomainAnalyser_$($Tenant.defaultDomainName)" SkipLog = $true - DurableMode = 'Sequence' } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) Write-Host "Started analysis for $DomainCount tenant domains in $($Tenant.defaultDomainName)" From ba6bb5cf8bcd9db2c455a865a00ca85653624cd8 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 24 May 2024 11:39:44 -0400 Subject: [PATCH 019/138] 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 722fb619cef4..23900d674daa 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.2 \ No newline at end of file +5.7.3 \ No newline at end of file From 0a1addcad95f55d96da75b42cc93aa365b41edb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 24 May 2024 23:47:18 +0200 Subject: [PATCH 020/138] Force input to bulk requests to be an array, so it can handle bulk request of only 1 entry --- .../Entrypoints/Invoke-ListTenantAllowBlockList.ps1 | 4 ++-- .../Standards/Invoke-CIPPStandardDelegateSentItems.ps1 | 10 ++++++---- .../Invoke-CIPPStandardEnableMailboxAuditing.ps1 | 4 ++-- .../Invoke-CIPPStandardEnableOnlineArchiving.ps1 | 2 +- .../Invoke-CIPPStandardSafeSendersDisable.ps1 | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 index ed51de874171..63c59971f13c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 @@ -16,7 +16,7 @@ Function Invoke-ListTenantAllowBlockList { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter - $ListTypes = 'Sender','Url','FileHash' + $ListTypes = 'Sender', 'Url', 'FileHash' try { $cmdletArray = $ListTypes | ForEach-Object { @{ @@ -26,7 +26,7 @@ Function Invoke-ListTenantAllowBlockList { } } } - $BatchResults = New-ExoBulkRequest -tenantid $TenantFilter -cmdletArray $cmdletArray + $BatchResults = New-ExoBulkRequest -tenantid $TenantFilter -cmdletArray @($cmdletArray) $StatusCode = [HttpStatusCode]::OK } catch { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 index 0407d9b3555e..b8ee94aafe9b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 @@ -6,12 +6,13 @@ function Invoke-CIPPStandardDelegateSentItems { param($Tenant, $Settings) $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) { + Write-Host 'Time to remediate' if ($Mailboxes) { try { - $Request = $mailboxes | ForEach-Object { + $Request = $Mailboxes | ForEach-Object { @{ CmdletInput = @{ CmdletName = 'Set-Mailbox' @@ -19,7 +20,7 @@ function Invoke-CIPPStandardDelegateSentItems { } } } - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray $Request + $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) $BatchResults | ForEach-Object { if ($_.error) { $ErrorMessage = Get-NormalizedError -Message $_.error @@ -27,6 +28,7 @@ function Invoke-CIPPStandardDelegateSentItems { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Delegate Sent Items Style to $($_.error.target) Error: $ErrorMessage" -sev Error } } + Write-LogMessage -API 'Standards' -tenant $tenant -message "Delegate Sent Items Style applied for $($Mailboxes.count - $BatchResults.Error.Count) mailboxes" -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Delegate Sent Items Style. Error: $ErrorMessage" -sev Error @@ -38,7 +40,7 @@ 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 + Write-LogMessage -API 'Standards' -tenant $tenant -message "Delegate Sent Items Style is not enabled for $($Mailboxes.count) mailboxes" -sev Alert } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Delegate Sent Items Style is enabled' -sev Info } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 index 460569529242..9181ae888e66 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 @@ -32,7 +32,7 @@ function Invoke-CIPPStandardEnableMailboxAuditing { } } - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray $Request + $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) $BatchResults | ForEach-Object { if ($_.error) { $ErrorMessage = Get-NormalizedError -Message $_.error @@ -53,7 +53,7 @@ function Invoke-CIPPStandardEnableMailboxAuditing { } } - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray $Request + $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) $BatchResults | ForEach-Object { if ($_.error) { $ErrorMessage = Get-NormalizedError -Message $_.error diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 index 92e387dc07ef..3c3dbd004c45 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardEnableOnlineArchiving { } } - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray $Request + $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) $BatchResults | ForEach-Object { if ($_.error) { $ErrorMessage = Get-NormalizedError -Message $_.error diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 index 4f01cbc8b55f..d70fe30cef99 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 @@ -20,7 +20,7 @@ function Invoke-CIPPStandardSafeSendersDisable { } } - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray $Request + $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) $BatchResults | ForEach-Object { if ($_.error) { $ErrorMessage = Get-NormalizedError -Message $_.error From c5571db75d11c5275be7bf2748b1a65bd04d6ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Sun, 26 May 2024 21:54:12 +0200 Subject: [PATCH 021/138] Add shorten meetings standard --- .../Invoke-CIPPStandardShortenMeetings.ps1 | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 new file mode 100644 index 000000000000..4946b64e8b4b --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 @@ -0,0 +1,57 @@ +function Invoke-CIPPStandardShortenMeetings { + <# + .FUNCTIONALITY + Internal + #> + param($Tenant, $Settings) + + # 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 + } + 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 + } + + $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 + $CurrentState.DefaultMinutesToReduceLongEventsBy -eq $Settings.DefaultMinutesToReduceLongEventsBy) { $true } else { $false } + + if ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' + + if ($CorrectState -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Shorten meetings settings are already in the correct state. ' -sev Info + } else { + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ShortenEventScopeDefault = $Settings.ShortenEventScopeDefault; DefaultMinutesToReduceShortEventsBy = $Settings.DefaultMinutesToReduceShortEventsBy; DefaultMinutesToReduceLongEventsBy = $Settings.DefaultMinutesToReduceLongEventsBy } + Write-LogMessage -API 'Standards' -tenant $tenant -message "Shorten meetings settings have been set to the following state. State: $($Settings.ShortenEventScopeDefault), Short:$($Settings.DefaultMinutesToReduceShortEventsBy), Long: $($Settings.DefaultMinutesToReduceLongEventsBy)" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set shorten meetings settings. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + + if ($CorrectState -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Shorten meetings settings are already in the correct state. Current state: $($CurrentState.ShortenEventScopeDefault), Short:$($CurrentState.DefaultMinutesToReduceShortEventsBy), Long: $($CurrentState.DefaultMinutesToReduceLongEventsBy)" -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "Shorten meetings settings are not in the correct state. Current state: $($CurrentState.ShortenEventScopeDefault), Short:$($CurrentState.DefaultMinutesToReduceShortEventsBy), Long: $($CurrentState.DefaultMinutesToReduceLongEventsBy)" -sev Alert + } + } + + if ($Settings.report -eq $true) { + + if ($CorrectState -eq $true) { + Add-CIPPBPAField -FieldName 'ShortenMeetings' -FieldValue $CorrectState -StoreAs bool -Tenant $tenant + } else { + Add-CIPPBPAField -FieldName 'ShortenMeetings' -FieldValue $CurrentState -StoreAs json -Tenant $tenant + } + } +} From fb37beb10c8cfba9409251dfc982da615234ff2f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 26 May 2024 22:31:27 +0200 Subject: [PATCH 022/138] added policy ids and --- Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 index 1aabf9920b17..25cc772e5802 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 @@ -72,9 +72,9 @@ function Set-CIPPAssignedPolicy { $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$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)" + return "Assigned policy to $($GroupName) Policy ID is $($PolicyId)." } catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to assign Policy to $GroupName" -Sev 'Error' -tenant $TenantFilter -LogData (Get-CippException -Exception $_) - return "Could not assign policy to $GroupName. Error: $($_.Exception.Message)" + 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 $_) + return "Could not assign policy to $GroupName. Policy ID is $($PolicyId). Error: $($_.Exception.Message)" } } From fdab193c911c0f6f7a5ec39cf2a131b162c95abb Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Sun, 26 May 2024 22:33:31 +0200 Subject: [PATCH 023/138] fixes bug with admin templates being blank if update ha;ppened. --- .../Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index 5a78adfa373a..39af5a0f9402 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -60,7 +60,7 @@ function Invoke-CIPPStandardIntuneTemplate { $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 - $UpdateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenant -type POST -body $RawJSON + $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 { From ce04504987881f1991e4f7dc265de31815237e30 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 26 May 2024 17:28:28 -0400 Subject: [PATCH 024/138] API Granular Permissions --- .../Public/CippQueue/Invoke-ListCippQueue.ps1 | 2 + .../CippQueue/Invoke-RemoveCippQueue.ps1 | 2 + .../CIPP/Core/Invoke-ExecAddAlert.ps1 | 4 +- .../CIPP/Core/Invoke-ExecDurableFunctions.ps1 | 2 + .../CIPP/Core/Invoke-ExecEditTemplate.ps1 | 8 +- .../CIPP/Core/Invoke-ExecGeoIPLookup.ps1 | 4 +- .../CIPP/Core/Invoke-ExecPartnerWebhook.ps1 | 2 + .../CIPP/Core/Invoke-GetCippAlerts.ps1 | 12 +- .../CIPP/Core/Invoke-GetVersion.ps1 | 4 +- .../Scheduler/Invoke-AddScheduledItem.ps1 | 4 +- .../Scheduler/Invoke-ListScheduledItems.ps1 | 4 +- .../Scheduler/Invoke-RemoveScheduledItem.ps1 | 6 +- .../CIPP/Settings/Invoke-ExecAccessChecks.ps1 | 4 +- .../CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 | 4 +- .../CIPP/Settings/Invoke-ExecBackendURLs.ps1 | 4 +- .../Settings/Invoke-ExecCPVPermissions.ps1 | 4 +- .../CIPP/Settings/Invoke-ExecDnsConfig.ps1 | 4 +- .../Settings/Invoke-ExecExcludeLicenses.ps1 | 4 +- .../Settings/Invoke-ExecExcludeTenant.ps1 | 4 +- .../Settings/Invoke-ExecExtensionMapping.ps1 | 4 +- .../Settings/Invoke-ExecExtensionSync.ps1 | 4 +- .../Settings/Invoke-ExecExtensionTest.ps1 | 69 +- .../Settings/Invoke-ExecExtensionsConfig.ps1 | 4 +- .../Invoke-ExecMaintenanceScripts.ps1 | 6 +- .../Invoke-ExecNotificationConfig.ps1 | 4 +- .../CIPP/Settings/Invoke-ExecPartnerMode.ps1 | 6 +- .../Settings/Invoke-ExecPasswordConfig.ps1 | 6 +- .../Settings/Invoke-ExecRestoreBackup.ps1 | 8 +- .../CIPP/Settings/Invoke-ExecRunBackup.ps1 | 8 +- .../CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 4 +- .../Email-Exchange/Invoke-AddContact.ps1 | 7 +- .../Email-Exchange/Invoke-AddExConnector.ps1 | 6 +- .../Invoke-AddExConnectorTemplate.ps1 | 10 +- .../Invoke-AddSharedMailbox.ps1 | 6 +- .../Email-Exchange/Invoke-AddSpamFilter.ps1 | 6 +- .../Invoke-AddSpamFilterTemplate.ps1 | 10 +- .../Invoke-AddTransportRule.ps1 | 8 +- .../Invoke-AddTransportTemplate.ps1 | 10 +- .../Email-Exchange/Invoke-EditExConnector.ps1 | 4 +- .../Email-Exchange/Invoke-EditSpamFilter.ps1 | 4 +- .../Invoke-EditTransportRule.ps1 | 4 +- .../Invoke-ExecConverttoSharedMailbox.ps1 | 4 +- .../Email-Exchange/Invoke-ExecCopyForSent.ps1 | 4 +- .../Invoke-ExecDisableEmailForward.ps1 | 4 +- .../Invoke-ExecEditCalendarPermissions.ps1 | 4 +- .../Invoke-ExecEditMailboxPermissions.ps1 | 20 +- .../Invoke-ExecEmailForward.ps1 | 14 +- .../Invoke-ExecEnableArchive.ps1 | 4 +- .../Invoke-ExecGroupsDelete.ps1 | 4 +- .../Invoke-ExecGroupsDeliveryManagement.ps1 | 6 +- .../Invoke-ExecGroupsHideFromGAL.ps1 | 6 +- .../Email-Exchange/Invoke-ExecHideFromGAL.ps1 | 4 +- .../Email-Exchange/Invoke-ExecMailTest.ps1 | 4 +- .../Invoke-ExecMailboxMobileDevices.ps1 | 4 +- .../Invoke-ExecMailboxRestore.ps1 | 4 +- .../Invoke-ExecQuarantineManagement.ps1 | 8 +- .../Invoke-ExecSetMailboxQuota.ps1 | 4 +- .../Email-Exchange/Invoke-ExecSetOoO.ps1 | 4 +- .../Invoke-ListMailQuarantine.ps1 | 4 +- .../Invoke-ListMessageTrace.ps1 | 8 +- .../Email-Exchange/Invoke-ListOoO.ps1 | 4 +- .../Invoke-ListPhishPolicies.ps1 | 4 +- .../Email-Exchange/Invoke-ListRecipients.ps1 | 10 +- .../Invoke-ListSpamFilterTemplates.ps1 | 10 +- .../Email-Exchange/Invoke-ListSpamfilter.ps1 | 4 +- .../Invoke-ListTransportRules.ps1 | 4 +- .../Invoke-ListTransportRulesTemplates.ps1 | 12 +- .../Applications/Invoke-AddChocoApp.ps1 | 4 +- .../Applications/Invoke-AddMSPApp.ps1 | 20 +- .../Applications/Invoke-AddOfficeApp.ps1 | 8 +- .../Applications/Invoke-AddWinGetApp.ps1 | 4 +- .../Applications/Invoke-ExecAssignApp.ps1 | 6 +- .../Invoke-ListApplicationQueue.ps1 | 4 +- .../Endpoint/Applications/Invoke-ListApps.ps1 | 48 +- .../Invoke-ListAppsRepository.ps1 | 6 +- .../Endpoint/Autopilot/Invoke-AddAPDevice.ps1 | 4 +- .../Autopilot/Invoke-AddAutopilotConfig.ps1 | 4 +- .../Autopilot/Invoke-AddEnrollment.ps1 | 4 +- .../Autopilot/Invoke-ExecAssignAPDevice.ps1 | 6 +- .../Autopilot/Invoke-ListAPDevices.ps1 | 6 +- .../MEM/Invoke-AddDefenderDeployment.ps1 | 26 +- .../Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 | 4 +- .../Endpoint/MEM/Invoke-AddPolicy.ps1 | 4 +- .../Endpoint/MEM/Invoke-EditPolicy.ps1 | 6 +- .../Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 | 6 +- .../Endpoint/MEM/Invoke-ExecDeviceAction.ps1 | 8 +- .../MEM/Invoke-ExecGetLocalAdminPassword.ps1 | 37 +- .../MEM/Invoke-ExecGetRecoveryKey.ps1 | 4 +- .../Endpoint/Reports/Invoke-ListDevices.ps1 | 6 +- .../Devices/Invoke-ExecDeviceDelete.ps1 | 4 +- .../Administration/Groups/Invoke-AddGroup.ps1 | 8 +- .../Groups/Invoke-AddGroupTemplate.ps1 | 6 +- .../Groups/Invoke-EditGroup.ps1 | 26 +- .../Administration/Users/Invoke-AddGuest.ps1 | 12 +- .../Administration/Users/Invoke-AddUser.ps1 | 4 +- .../Users/Invoke-AddUserBulk.ps1 | 6 +- .../Administration/Users/Invoke-EditUser.ps1 | 4 +- .../Users/Invoke-ExecBECCheck.ps1 | 4 +- .../Users/Invoke-ExecBECRemediate.ps1 | 8 +- .../Users/Invoke-ExecClrImmId.ps1 | 4 +- .../Users/Invoke-ExecCreateTAP.ps1 | 38 +- .../Users/Invoke-ExecDisableUser.ps1 | 34 +- .../Users/Invoke-ExecOffboardUser.ps1 | 8 +- ...Invoke-ExecOffboard_Mailboxpermissions.ps1 | 4 +- .../Users/Invoke-ExecOneDriveShortCut.ps1 | 4 +- .../Users/Invoke-ExecResetMFA.ps1 | 6 +- .../Users/Invoke-ExecResetPass.ps1 | 4 +- .../Users/Invoke-ExecRevokeSessions.ps1 | 40 +- .../Users/Invoke-ExecSendPush.ps1 | 10 +- ...voke-ListUserConditionalAccessPolicies.ps1 | 6 +- .../Users/Invoke-ListUserCounts.ps1 | 68 +- .../Users/Invoke-ListUserDevices.ps1 | 4 +- .../Users/Invoke-ListUserGroups.ps1 | 6 +- .../Users/Invoke-ListUserMailboxDetails.ps1 | 20 +- .../Users/Invoke-ListUserMailboxRules.ps1 | 4 +- .../Users/Invoke-ListUserPhoto.ps1 | 4 +- .../Users/Invoke-ListUserSettings.ps1 | 4 +- .../Users/Invoke-ListUserSigninLogs.ps1 | 6 +- .../Administration/Users/Invoke-ListUsers.ps1 | 8 +- .../Identity/Reports/Invoke-ListBasicAuth.ps1 | 8 +- .../Invoke-ListBasicAuthAllTenants.ps1 | 10 +- .../Invoke-ExecAlertsList.ps1 | 12 +- .../Invoke-ExecAlertsListAllTenants.ps1 | 14 +- .../Security/Invoke-ExecIncidentsList.ps1 | 16 +- .../Invoke-ExecIncidentsListAllTenants.ps1 | 14 +- .../Security/Invoke-ExecSetSecurityAlert.ps1 | 6 +- .../Invoke-ExecSetSecurityIncident.ps1 | 126 +-- .../Teams-Sharepoint/Invoke-AddTeam.ps1 | 6 +- .../Invoke-ExecSetSharePointMember.ps1 | 4 +- .../Invoke-ExecSharePointOwner.ps1 | 36 +- .../Invoke-ListSharepointSettings.ps1 | 6 +- .../Teams-Sharepoint/Invoke-ListSites.ps1 | 8 +- .../Teams-Sharepoint/Invoke-ListTeams.ps1 | 6 +- .../Invoke-ListTeamsActivity.ps1 | 6 +- .../Invoke-ListTeamsVoice.ps1 | 8 +- .../Administration/Alerts/Invoke-AddAlert.ps1 | 4 +- .../Alerts/Invoke-ListAlertsQueue.ps1 | 10 +- .../Alerts/Invoke-ListWebhookAlert.ps1 | 4 +- .../Alerts/Invoke-PublicWebhooks.ps1 | 32 +- .../Alerts/Invoke-RemoveQueuedAlert.ps1 | 6 +- .../Invoke-ExecAddMultiTenantApp.ps1 | 2 + .../Invoke-ExecAppApproval.ps1 | 6 +- .../Administration/Invoke-ExecAddSPN.ps1 | 40 +- .../Invoke-ExecOffboardTenant.ps1 | 24 +- .../Invoke-ExecOnboardTenant.ps1 | 2 + .../Invoke-ListAppConsentRequests.ps1 | 6 +- .../Invoke-ListTenantOnboarding.ps1 | 6 + .../Invoke-UpdateSecureScore.ps1 | 48 +- .../Tenant/Invoke-EditTenant.ps1 | 10 +- .../Tenant/Invoke-ListTenantDetails.ps1 | 6 +- .../Tenant/Invoke-ListTenants.ps1 | 4 +- .../Tenant/Conditional/Invoke-AddCAPolicy.ps1 | 4 +- .../Conditional/Invoke-AddCATemplate.ps1 | 10 +- .../Conditional/Invoke-AddNamedLocation.ps1 | 4 +- .../Conditional/Invoke-EditCAPolicy.ps1 | 4 +- .../Tenant/Conditional/Invoke-ExecCACheck.ps1 | 6 +- .../Conditional/Invoke-ExecCAExclusion.ps1 | 6 +- .../Conditional/Invoke-ListCAtemplates.ps1 | 8 +- .../Invoke-ListConditionalAccessPolicies.ps1 | 855 +++++++++--------- ...oke-ListConditionalAccessPolicyChanges.ps1 | 4 +- .../Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 | 106 +-- .../Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 | 28 +- .../Invoke-ExecDeleteGDAPRelationship.ps1 | 4 +- .../GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 | 46 +- .../Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 | 4 +- .../GDAP/Invoke-ExecGDAPInviteApproved.ps1 | 4 +- .../GDAP/Invoke-ExecGDAPRemoveGArole.ps1 | 4 +- .../Tenant/GDAP/Invoke-ListGDAPInvite.ps1 | 4 +- .../Tenant/GDAP/Invoke-ListGDAPQueue.ps1 | 6 +- .../Tenant/GDAP/Invoke-ListGDAPRoles.ps1 | 6 +- .../Standards/Invoke-AddStandardsDeploy.ps1 | 4 +- .../Standards/Invoke-AddStandardsTemplate.ps1 | 6 +- .../Invoke-BestPracticeAnalyser_List.ps1 | 6 +- .../Standards/Invoke-ExecStandardsRun.ps1 | 4 +- .../Tenant/Standards/Invoke-ListBPA.ps1 | 4 +- .../Standards/Invoke-ListBPATemplates.ps1 | 4 +- .../Standards/Invoke-ListDomainAnalyser.ps1 | 4 +- .../Standards/Invoke-ListDomainHealth.ps1 | 4 +- .../Invoke-listStandardTemplates.ps1 | 8 +- .../Standards/invoke-DomainAnalyser_List.ps1 | 6 +- .../Tools/Invoke-ExecGraphExplorerPreset.ps1 | 4 +- .../Invoke-AddTenantAllowBlockList.ps1 | 24 +- .../Invoke-ExecExtensionNinjaOneQueue.ps1 | 8 +- .../Entrypoints/Invoke-ExecListAppId.ps1 | 36 +- .../Entrypoints/Invoke-ExecRestoreDeleted.ps1 | 40 +- .../Invoke-ExecSchedulerBillingRun.ps1 | 4 +- .../Entrypoints/Invoke-ExecSendOrgMessage.ps1 | 6 +- .../Entrypoints/Invoke-ExecSyncAPDevices.ps1 | 4 +- .../Invoke-ExecUniversalSearch.ps1 | 4 +- .../Entrypoints/Invoke-ExecUserSettings.ps1 | 4 +- .../Invoke-ListAllTenantDeviceCompliance.ps1 | 16 +- .../Entrypoints/Invoke-ListAppStatus.ps1 | 4 +- .../Invoke-ListAutopilotconfig.ps1 | 4 +- .../Invoke-ListAzureADConnectStatus.ps1 | 8 +- .../Invoke-ListCalendarPermissions.ps1 | 4 +- .../Entrypoints/Invoke-ListContacts.ps1 | 4 +- .../Entrypoints/Invoke-ListDefenderState.ps1 | 10 +- .../Entrypoints/Invoke-ListDefenderTVM.ps1 | 6 +- .../Entrypoints/Invoke-ListDeletedItems.ps1 | 6 +- .../Entrypoints/Invoke-ListDeviceDetails.ps1 | 8 +- .../Public/Entrypoints/Invoke-ListDomains.ps1 | 48 +- .../Invoke-ListExConnectorTemplates.ps1 | 10 +- .../Invoke-ListExchangeConnectors.ps1 | 4 +- .../Invoke-ListExtensionsConfig.ps1 | 4 +- .../Invoke-ListExternalTenantInfo.ps1 | 4 +- .../Invoke-ListFunctionParameters.ps1 | 4 +- .../Entrypoints/Invoke-ListFunctionStats.ps1 | 4 +- .../Invoke-ListGenericAllTenants.ps1 | 4 +- .../Invoke-ListGenericTestFunction.ps1 | 4 +- .../Invoke-ListGraphExplorerPresets.ps1 | 4 +- .../Entrypoints/Invoke-ListGraphRequest.ps1 | 5 +- .../Entrypoints/Invoke-ListGroupTemplates.ps1 | 8 +- .../Public/Entrypoints/Invoke-ListGroups.ps1 | 10 +- .../Entrypoints/Invoke-ListHaloClients.ps1 | 74 +- .../Entrypoints/Invoke-ListIPWhitelist.ps1 | 4 +- .../Invoke-ListInactiveAccounts.ps1 | 50 +- .../Entrypoints/Invoke-ListIntuneIntents.ps1 | 48 +- .../Entrypoints/Invoke-ListIntunePolicy.ps1 | 6 +- .../Invoke-ListIntuneTemplates.ps1 | 6 +- .../Entrypoints/Invoke-ListKnownIPDb.ps1 | 4 +- .../Entrypoints/Invoke-ListLicenses.ps1 | 4 +- .../Public/Entrypoints/Invoke-ListLogs.ps1 | 4 +- .../Entrypoints/Invoke-ListMFAUsers.ps1 | 4 +- .../Entrypoints/Invoke-ListMailboxCAS.ps1 | 4 +- .../Invoke-ListMailboxMobileDevices copy.ps1 | 55 -- .../Invoke-ListMailboxMobileDevices.ps1 | 4 +- .../Invoke-ListMailboxRestores.ps1 | 6 + .../Entrypoints/Invoke-ListMailboxRules.ps1 | 4 +- .../Invoke-ListMailboxStatistics.ps1 | 4 +- .../Entrypoints/Invoke-ListMailboxes.ps1 | 4 +- .../Entrypoints/Invoke-ListNamedLocations.ps1 | 6 +- .../Invoke-ListNotificationConfig.ps1 | 4 +- .../Entrypoints/Invoke-ListOAuthApps.ps1 | 92 +- .../Public/Entrypoints/Invoke-ListOrg.ps1 | 42 +- .../Invoke-ListPartnerRelationships.ps1 | 4 +- .../Invoke-ListPendingWebhooks.ps1 | 4 +- .../Entrypoints/Invoke-ListPotentialApps.ps1 | 4 +- .../Public/Entrypoints/Invoke-ListRoles.ps1 | 6 +- .../Entrypoints/Invoke-ListRoomLists.ps1 | 8 +- .../Public/Entrypoints/Invoke-ListRooms.ps1 | 4 +- .../Entrypoints/Invoke-ListServiceHealth.ps1 | 4 +- ...Invoke-ListSharedMailboxAccountEnabled.ps1 | 14 +- .../Invoke-ListSharedMailboxStatistics.ps1 | 4 +- .../Invoke-ListSharepointQuota.ps1 | 4 +- .../Public/Entrypoints/Invoke-ListSignIns.ps1 | 16 +- .../Entrypoints/Invoke-ListStandards.ps1 | 4 +- .../Invoke-ListTenantAllowBlockList.ps1 | 4 +- .../Invoke-ListmailboxPermissions.ps1 | 16 +- .../Invoke-PublicPhishingCheck.ps1 | 16 +- .../Invoke-RemoveTenantAllowBlockList.ps1 | 4 +- .../CIPPCore/Public/Get-CIPPHttpFunctions.ps1 | 37 + .../CIPPCore/Public/Invoke-RemoveAPDevice.ps1 | 4 +- Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 | 4 +- .../CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 | 4 +- .../Public/Invoke-RemoveCATemplate.ps1 | 4 +- .../CIPPCore/Public/Invoke-RemoveContact.ps1 | 4 +- .../Public/Invoke-RemoveExConnector.ps1 | 8 +- .../Invoke-RemoveExConnectorTemplate.ps1 | 4 +- .../Public/Invoke-RemoveGroupTemplate.ps1 | 4 +- .../Public/Invoke-RemoveIntuneTemplate.ps1 | 4 +- .../CIPPCore/Public/Invoke-RemovePolicy.ps1 | 4 +- .../Public/Invoke-RemoveQueuedApp.ps1 | 4 +- .../Public/Invoke-RemoveSpamfilter.ps1 | 4 +- .../Invoke-RemoveSpamfilterTemplate.ps1 | 4 +- .../CIPPCore/Public/Invoke-RemoveStandard.ps1 | 4 +- .../Public/Invoke-RemoveStandardTemplate.ps1 | 4 +- .../Public/Invoke-RemoveTransportRule.ps1 | 4 +- .../Invoke-RemoveTransportRuleTemplate.ps1 | 4 +- Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 | 4 +- .../Public/Invoke-RemoveWebhookAlert.ps1 | 8 +- 270 files changed, 2092 insertions(+), 1581 deletions(-) rename Modules/CIPPCore/Public/Entrypoints/HTTP Functions/{Tenant/Administration/Alerts => Security}/Invoke-ExecAlertsList.ps1 (97%) delete mode 100644 Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices copy.ps1 create mode 100644 Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 index d04193b88d3a..ef4357efefd5 100644 --- a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 +++ b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 @@ -2,6 +2,8 @@ function Invoke-ListCippQueue { <# .FUNCTIONALITY Entrypoint + .ROLE + CIPP.Core.Read #> param($Request = $null, $TriggerMetadata = $null) diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 index 32c577f6d356..656aa592c8a7 100644 --- a/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 +++ b/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 @@ -2,6 +2,8 @@ function Invoke-RemoveCippQueue { <# .FUNCTIONALITY Entrypoint + .ROLE + CIPP.Core.ReadWrite #> param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 index 1e1ecbfc0fcc..81a079c2401d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAddAlert { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 index 6028762273c6..0e5581ffb476 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 @@ -2,6 +2,8 @@ function Invoke-ExecDurableFunctions { <# .FUNCTIONALITY Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding(SupportsShouldProcess = $true)] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 index 4998a8447406..053395d7d293 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecEditTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -11,7 +13,7 @@ Function Invoke-ExecEditTemplate { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - try { + try { $Table = Get-CippTable -tablename 'templates' $Table.Force = $true $guid = $request.body.guid @@ -33,7 +35,7 @@ Function Invoke-ExecEditTemplate { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Edited template $($Request.body.name) with GUID $GUID" -Sev 'Debug' } $body = [pscustomobject]@{ 'Results' = 'Successfully saved the template' } - + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to edit template: $($_.Exception.Message)" -Sev 'Error' $body = [pscustomobject]@{'Results' = "Editing template failed: $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 index 3410320f99a8..6c252b12c28c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGeoIPLookup { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 index d6efbbe307f0..0989b2c5e843 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 @@ -2,6 +2,8 @@ function Invoke-ExecPartnerWebhook { <# .FUNCTIONALITY Entrypoint + .ROLE + CIPP.Core.ReadWrite #> Param($Request, $TriggerMetadata) 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 d0bbaea27dfc..53a0321cfb8a 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-GetCippAlerts { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -45,9 +47,9 @@ Function Invoke-GetCippAlerts { if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1') { $Alerts.add( @{Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this ' - link = 'https://docs.cipp.app/setup/installation/runfrompackage' - type = 'warning' - }) + link = 'https://docs.cipp.app/setup/installation/runfrompackage' + type = 'warning' + }) } if ($Rows) { $Rows | ForEach-Object { $alerts.add($_) } } $Alerts = @($Alerts) @@ -56,7 +58,7 @@ Function Invoke-GetCippAlerts { # Write to the Azure Functions log stream. - + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 index b92ecb48d6e6..1a2e0912cd87 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-GetVersion { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1 index 44dbfa761030..50860f6e034b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-AddScheduledItem.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddScheduledItem { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Scheduler.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 index 71aa6aa536fe..d0f3869560a2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListScheduledItems { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Scheduler.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 index 629760a2ca68..257902f03726 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveScheduledItem { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Scheduler.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -21,7 +23,7 @@ Function Invoke-RemoveScheduledItem { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @{ Results = 'Task removed successfully.' } + Body = @{ Results = 'Task removed successfully.' } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 index 93a72e2e296d..4f51b3525989 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAccessChecks { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 index db587ae67959..066f1e665601 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAddTrustedIP { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 index 4a29002ad122..ea00cbb12691 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecBackendURLs { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 index 4703972094e4..356b1643834f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecCPVPermissions { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 index 41768a704af5..a4d54f0b9eb6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecDnsConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 index c20795dcb97c..7b40efffe84c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecExcludeLicenses { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 index ca3e85feed9a..177aa425b86f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecExcludeTenant { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionMapping.ps1 index e848d7df1669..77b8e277c780 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionMapping.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionMapping.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecExtensionMapping { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Extension.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionSync.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionSync.ps1 index 3abce0100b91..2f069988996a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionSync.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionSync.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecExtensionSync { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Extension.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 index afbdfacc402c..7c2f271c13a5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 @@ -1,50 +1,51 @@ - using namespace System.Net +using namespace System.Net - Function Invoke-ExecExtensionTest { +Function Invoke-ExecExtensionTest { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Extension.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" -$Table = Get-CIPPTable -TableName Extensionsconfig -$Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json) -# Interact with query parameters or the body of the request. -try { - switch ($Request.query.extensionName) { - "HaloPSA" { - $token = Get-HaloToken -configuration $Configuration.HaloPSA - $Results = [pscustomobject]@{"Results" = "Successfully Connected to HaloPSA" } + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json) + # Interact with query parameters or the body of the request. + try { + switch ($Request.query.extensionName) { + 'HaloPSA' { + $token = Get-HaloToken -configuration $Configuration.HaloPSA + $Results = [pscustomobject]@{'Results' = 'Successfully Connected to HaloPSA' } } - "Gradient" { - $GradientToken = Get-GradientToken -Configuration $Configuration.Gradient - $ExistingIntegrations = Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization' -Method GET -Headers $GradientToken - if ($ExistingIntegrations.Status -ne "active") { - $ActivateRequest = Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization/status/active' -Method PATCH -Headers $GradientToken - } - $Results = [pscustomobject]@{"Results" = "Succesfully Connected to Gradient" } + 'Gradient' { + $GradientToken = Get-GradientToken -Configuration $Configuration.Gradient + $ExistingIntegrations = Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization' -Method GET -Headers $GradientToken + if ($ExistingIntegrations.Status -ne 'active') { + $ActivateRequest = Invoke-RestMethod -Uri 'https://app.usegradient.com/api/vendor-api/organization/status/active' -Method PATCH -Headers $GradientToken + } + $Results = [pscustomobject]@{'Results' = 'Succesfully Connected to Gradient' } } - "CIPP-API" { - $Results = [pscustomobject]@{"Results" = "You cannot test the CIPP-API from CIPP. Please check the documentation on how to test the CIPP-API." } + 'CIPP-API' { + $Results = [pscustomobject]@{'Results' = 'You cannot test the CIPP-API from CIPP. Please check the documentation on how to test the CIPP-API.' } } - "NinjaOne" { - $token = Get-NinjaOneToken -configuration $Configuration.NinjaOne - $Results = [pscustomobject]@{"Results" = "Succesfully Connected to NinjaOne" } + 'NinjaOne' { + $token = Get-NinjaOneToken -configuration $Configuration.NinjaOne + $Results = [pscustomobject]@{'Results' = 'Succesfully Connected to NinjaOne' } } - } -} -catch { - $Results = [pscustomobject]@{"Results" = "Failed to connect: $($_.Exception.Message) $($_.InvocationInfo.ScriptLineNumber)" } -} + } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to connect: $($_.Exception.Message) $($_.InvocationInfo.ScriptLineNumber)" } + } -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Results - }) + }) - } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionsConfig.ps1 index 50675339a8f8..fd3b8764959d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionsConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecExtensionsConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Extension.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 index 567e6dc3a1c4..aa1e92027101 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecMaintenanceScripts { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -17,7 +19,7 @@ Function Invoke-ExecMaintenanceScripts { $ReplacementStrings = @{ '##TENANTID##' = $env:TenantID '##RESOURCEGROUP##' = $env:WEBSITE_RESOURCE_GROUP - '##FUNCTIONAPP##' = $env:WEBSITE_SITE_NAME + '##FUNCTIONAPP##' = $env:WEBSITE_SITE_NAME '##SUBSCRIPTION##' = (($env:WEBSITE_OWNER_NAME).split('+') | Select-Object -First 1) '##TOKENIP##' = $AccessTokenDetails.IPAddress } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 index f1f39d9bcc90..23fbd238f807 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecNotificationConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 index b7a2a621fb64..a7d2ba3511bb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecPartnerMode { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.SuperAdmin.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -29,7 +31,7 @@ Function Invoke-ExecPartnerMode { }) } - + if ($request.query.action -eq 'ListCurrent') { $CurrentState = Get-CIPPAzDataTableEntity @Table $CurrentState = if (!$CurrentState) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 index 78e27e7f01f3..346920fb6a24 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecPasswordConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -16,7 +18,7 @@ Function Invoke-ExecPasswordConfig { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $results = try { + $results = try { if ($Request.Query.List) { @{ passwordType = $PasswordType.passwordType } } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 index 0342d10f68c5..b3aafb0f21f3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 @@ -3,14 +3,16 @@ using namespace System.Net Function Invoke-ExecRestoreBackup { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.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' - try { + try { foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag)) { Write-Host ($line) $Table = Get-CippTable -tablename $line.table @@ -23,7 +25,7 @@ Function Invoke-ExecRestoreBackup { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' $body = [pscustomobject]@{ - 'Results' = 'Succesfully restored backup.' + 'Results' = 'Succesfully restored backup.' } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 index a237798e8e01..08bb5ec54673 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 @@ -3,14 +3,16 @@ using namespace System.Net Function Invoke-ExecRunBackup { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.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' - try { + try { if ($request.query.Selected) { $BackupTables = $request.query.Selected -split ',' } else { @@ -31,7 +33,7 @@ Function Invoke-ExecRunBackup { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' $body = [pscustomobject]@{ - 'Results' = 'Created backup' + 'Results' = 'Created backup' backup = $CSVfile } } catch { 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 97e293d285ce..2b1b9b9dc28c 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSAMSetup { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddContact.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddContact.ps1 index ebd0d9be935b..c52e2e60ffbd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddContact.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddContact.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddContact { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Contact.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -31,8 +33,7 @@ Function Invoke-AddContact { $body = [pscustomobject]@{'Results' = 'Successfully added a contact.' } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($contactobj.tenantid) -message "Created contact $($contactobj.displayname) with id $($GraphRequest.id) for " -Sev 'Info' - } - catch { + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($contactobj.tenantid) -message "Contact creation API failed. $($_.Exception.Message)" -Sev 'Error' $body = [pscustomobject]@{'Results' = "Failed to create contact. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 index b3246cea773d..d1a29a85a67d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddExConnector { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -17,7 +19,7 @@ Function Invoke-AddExConnector { $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value $Result = foreach ($Tenantfilter in $tenants) { try { - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams "Successfully created Connector for $Tenantfilter." Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Created Connector for $($Tenantfilter)" -sev 'Info' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnectorTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnectorTemplate.ps1 index 73cf56b8d910..222c01f420ff 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnectorTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnectorTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddExConnectorTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -15,8 +17,8 @@ Function Invoke-AddExConnectorTemplate { try { $GUID = (New-Guid).GUID - $Select = if ($Request.body.cippconnectortype -eq 'outbound') { - @( + $Select = if ($Request.body.cippconnectortype -eq 'outbound') { + @( 'name', 'AllAcceptedDomains', 'CloudServicesMailEnabled', 'Comment', 'Confirm', 'ConnectorSource', 'ConnectorType', 'Enabled', 'IsTransportRuleScoped', 'RecipientDomains', 'RouteAllMessagesViaOnPremises', 'SenderRewritingEnabled', 'SmartHosts', 'TestMode', 'TlsDomain', 'TlsSettings', 'UseMXRecord' ) } @@ -28,7 +30,7 @@ Function Invoke-AddExConnectorTemplate { $JSON = ([pscustomobject]$Request.body | Select-Object $Select) | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties + $_ | Select-Object -Property $NonEmptyProperties } $JSON = ($JSON | Select-Object @{n = 'name'; e = { $_.name } }, * | ConvertTo-Json -Depth 10) $Table = Get-CippTable -tablename 'templates' 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 c3017c7cf881..20af9ebdd475 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddSharedMailbox { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -40,7 +42,7 @@ Function Invoke-AddSharedMailbox { try { if ($Aliases) { - + 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 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 789b3eaffe9d..deb78b344897 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 @@ -3,12 +3,14 @@ using namespace System.Net Function Invoke-AddSpamFilter { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.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' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 index 9aeef51f243c..37cf34b88916 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddSpamFilterTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -12,7 +14,7 @@ Function Invoke-AddSpamFilterTemplate { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' Write-Host ($request | ConvertTo-Json -Compress) - try { + try { $GUID = (New-Guid).GUID $JSON = if ($request.body.PowerShellCommand) { Write-Host 'PowerShellCommand' @@ -21,7 +23,7 @@ Function Invoke-AddSpamFilterTemplate { else { ([pscustomobject]$Request.body | Select-Object name, AddXHeaderValue, AdminDisplayName, AllowedSenderDomains, AllowedSenders, BlockedSenderDomains, BlockedSenders, BulkQuarantineTag, BulkSpamAction, BulkThreshold, Confirm, DownloadLink, EnableEndUserSpamNotifications, EnableLanguageBlockList, EnableRegionBlockList, EndUserSpamNotificationCustomFromAddress, EndUserSpamNotificationCustomFromName, EndUserSpamNotificationCustomSubject, EndUserSpamNotificationFrequency, EndUserSpamNotificationLanguage, EndUserSpamNotificationLimit, HighConfidencePhishAction, HighConfidencePhishQuarantineTag, HighConfidenceSpamAction, HighConfidenceSpamQuarantineTag, IncreaseScoreWithBizOrInfoUrls, IncreaseScoreWithImageLinks, IncreaseScoreWithNumericIps, IncreaseScoreWithRedirectToOtherPort, InlineSafetyTipsEnabled, LanguageBlockList, MarkAsSpamBulkMail, MarkAsSpamEmbedTagsInHtml, MarkAsSpamEmptyMessages, MarkAsSpamFormTagsInHtml, MarkAsSpamFramesInHtml, MarkAsSpamFromAddressAuthFail, MarkAsSpamJavaScriptInHtml, MarkAsSpamNdrBackscatter, MarkAsSpamObjectTagsInHtml, MarkAsSpamSensitiveWordList, MarkAsSpamSpfRecordHardFail, MarkAsSpamWebBugsInHtml, ModifySubjectValue, PhishQuarantineTag, PhishSpamAction, PhishZapEnabled, QuarantineRetentionPeriod, RecommendedPolicyType, RedirectToRecipients, RegionBlockList, SpamAction, SpamQuarantineTag, SpamZapEnabled, TestModeAction, TestModeBccToRecipients ) | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties + $_ | Select-Object -Property $NonEmptyProperties } } $JSON = ($JSON | Select-Object @{n = 'name'; e = { $_.name } }, @{n = 'comments'; e = { $_.comments } }, * | ConvertTo-Json -Depth 10) @@ -34,7 +36,7 @@ Function Invoke-AddSpamFilterTemplate { } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created Spam Filter Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' $body = [pscustomobject]@{'Results' = 'Successfully added template' } - + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create Spam Filter Template: $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 index 64c394ee2852..acd265572aa5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddTransportRule { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -11,7 +13,7 @@ Function Invoke-AddTransportRule { $APIName = $TriggerMetadata.FunctionName 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, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications + $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value $Result = foreach ($Tenantfilter in $tenants) { @@ -28,7 +30,7 @@ Function Invoke-AddTransportRule { $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-TransportRule' -cmdParams $RequestParams -useSystemMailbox $true "Successfully created transport rule for $tenantfilter." } - + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Created transport rule for $($tenantfilter)" -sev Info } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 index 6028c15578b6..0f7fb738e6ff 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddTransportTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -12,7 +14,7 @@ Function Invoke-AddTransportTemplate { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' Write-Host ($request | ConvertTo-Json -Compress) - try { + try { $GUID = (New-Guid).GUID $JSON = if ($request.body.PowerShellCommand) { Write-Host 'PowerShellCommand' @@ -21,7 +23,7 @@ Function Invoke-AddTransportTemplate { else { ([pscustomobject]$Request.body | Select-Object Name, ActivationDate, ADComparisonAttribute, ADComparisonOperator, AddManagerAsRecipientType, AddToRecipients, AnyOfCcHeader, AnyOfCcHeaderMemberOf, AnyOfRecipientAddressContainsWords, AnyOfRecipientAddressMatchesPatterns, AnyOfToCcHeader, AnyOfToCcHeaderMemberOf, AnyOfToHeader, AnyOfToHeaderMemberOf, ApplyClassification, ApplyHtmlDisclaimerFallbackAction, ApplyHtmlDisclaimerLocation, ApplyHtmlDisclaimerText, ApplyOME, ApplyRightsProtectionCustomizationTemplate, ApplyRightsProtectionTemplate, AttachmentContainsWords, AttachmentExtensionMatchesWords, AttachmentHasExecutableContent, AttachmentIsPasswordProtected, AttachmentIsUnsupported, AttachmentMatchesPatterns, AttachmentNameMatchesPatterns, AttachmentProcessingLimitExceeded, AttachmentPropertyContainsWords, AttachmentSizeOver, BetweenMemberOf1, BetweenMemberOf2, BlindCopyTo, Comments, Confirm, ContentCharacterSetContainsWords, CopyTo, DeleteMessage, DlpPolicy, DomainController, Enabled, ExceptIfADComparisonAttribute, ExceptIfADComparisonOperator, ExceptIfAnyOfCcHeader, ExceptIfAnyOfCcHeaderMemberOf, ExceptIfAnyOfRecipientAddressContainsWords, ExceptIfAnyOfRecipientAddressMatchesPatterns, ExceptIfAnyOfToCcHeader, ExceptIfAnyOfToCcHeaderMemberOf, ExceptIfAnyOfToHeader, ExceptIfAnyOfToHeaderMemberOf, ExceptIfAttachmentContainsWords, ExceptIfAttachmentExtensionMatchesWords, ExceptIfAttachmentHasExecutableContent, ExceptIfAttachmentIsPasswordProtected, ExceptIfAttachmentIsUnsupported, ExceptIfAttachmentMatchesPatterns, ExceptIfAttachmentNameMatchesPatterns, ExceptIfAttachmentProcessingLimitExceeded, ExceptIfAttachmentPropertyContainsWords, ExceptIfAttachmentSizeOver, ExceptIfBetweenMemberOf1, ExceptIfBetweenMemberOf2, ExceptIfContentCharacterSetContainsWords, ExceptIfFrom, ExceptIfFromAddressContainsWords, ExceptIfFromAddressMatchesPatterns, ExceptIfFromMemberOf, ExceptIfFromScope, ExceptIfHasClassification, ExceptIfHasNoClassification, ExceptIfHasSenderOverride, ExceptIfHeaderContainsMessageHeader, ExceptIfHeaderContainsWords, ExceptIfHeaderMatchesMessageHeader, ExceptIfHeaderMatchesPatterns, ExceptIfManagerAddresses, ExceptIfManagerForEvaluatedUser, ExceptIfMessageContainsDataClassifications, ExceptIfMessageSizeOver, ExceptIfMessageTypeMatches, ExceptIfRecipientADAttributeContainsWords, ExceptIfRecipientADAttributeMatchesPatterns, ExceptIfRecipientAddressContainsWords, ExceptIfRecipientAddressMatchesPatterns, ExceptIfRecipientDomainIs, ExceptIfRecipientInSenderList, ExceptIfSCLOver, ExceptIfSenderADAttributeContainsWords, ExceptIfSenderADAttributeMatchesPatterns, ExceptIfSenderDomainIs, ExceptIfSenderInRecipientList, ExceptIfSenderIpRanges, ExceptIfSenderManagementRelationship, ExceptIfSentTo, ExceptIfSentToMemberOf, ExceptIfSentToScope, ExceptIfSubjectContainsWords, ExceptIfSubjectMatchesPatterns, ExceptIfSubjectOrBodyContainsWords, ExceptIfSubjectOrBodyMatchesPatterns, ExceptIfWithImportance, ExpiryDate, From, FromAddressContainsWords, FromAddressMatchesPatterns, FromMemberOf, FromScope, GenerateIncidentReport, GenerateNotification, HasClassification, HasNoClassification, HasSenderOverride, HeaderContainsMessageHeader, HeaderContainsWords, HeaderMatchesMessageHeader, HeaderMatchesPatterns, IncidentReportContent, IncidentReportOriginalMail, LogEventText, ManagerAddresses, ManagerForEvaluatedUser, MessageContainsDataClassifications, MessageSizeOver, MessageTypeMatches, Mode, ModerateMessageByManager, ModerateMessageByUser, NotifySender, PrependSubject, Quarantine, RecipientADAttributeContainsWords, RecipientADAttributeMatchesPatterns, RecipientAddressContainsWords, RecipientAddressMatchesPatterns, RecipientAddressType, RecipientDomainIs, RecipientInSenderList, RedirectMessageTo, RejectMessageEnhancedStatusCode, RejectMessageReasonText, RemoveHeader, RemoveOME, RemoveOMEv2, RemoveRMSAttachmentEncryption, RouteMessageOutboundConnector, RouteMessageOutboundRequireTls, RuleErrorAction, RuleSubType, SCLOver, SenderADAttributeContainsWords, SenderADAttributeMatchesPatterns, SenderAddressLocation, SenderDomainIs, SenderInRecipientList, SenderIpRanges, SenderManagementRelationship, SentTo, SentToMemberOf, SentToScope, SetAuditSeverity, SetHeaderName, SetHeaderValue, SetSCL, SmtpRejectMessageRejectStatusCode, SmtpRejectMessageRejectText, StopRuleProcessing, SubjectContainsWords, SubjectMatchesPatterns, SubjectOrBodyContainsWords, SubjectOrBodyMatchesPatterns, UseLegacyRegex, WithImportance ) | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties + $_ | Select-Object -Property $NonEmptyProperties } } $JSON = ($JSON | Select-Object @{n = 'name'; e = { $_.name } }, @{n = 'comments'; e = { $_.comments } }, * | ConvertTo-Json -Depth 10) @@ -34,7 +36,7 @@ Function Invoke-AddTransportTemplate { } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created Transport Rule Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' $body = [pscustomobject]@{'Results' = 'Successfully added template' } - + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create Transport Rule Template: $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 index 9042e7fdfa0a..b1c622f621fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditExConnector { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 index 9f98d280f511..1c638ab96ea1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditSpamFilter { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 index 20f93fd4014f..8d968077db70 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditTransportRule { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 index cb16432e8937..ed59a074c1ac 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecConverttoSharedMailbox { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecCopyForSent.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecCopyForSent.ps1 index a039be57dfba..4aadbd74c563 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecCopyForSent.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecCopyForSent.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecCopyForSent { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecDisableEmailForward.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecDisableEmailForward.ps1 index 12c57868e68d..d2894b583ee4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecDisableEmailForward.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecDisableEmailForward.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecDisableEmailForward { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 index 346deef09dcc..eebb7139649d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecEditCalendarPermissions { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditMailboxPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditMailboxPermissions.ps1 index 97200abfc763..d017f8ae65a4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditMailboxPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditMailboxPermissions.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecEditMailboxPermissions { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -17,11 +19,11 @@ Function Invoke-ExecEditMailboxPermissions { $Results = [System.Collections.ArrayList]@() $RemoveFullAccess = ($Request.body.RemoveFullAccess).value - foreach ($RemoveUser in $RemoveFullAccess) { + foreach ($RemoveUser in $RemoveFullAccess) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-mailboxpermission' -cmdParams @{Identity = $userid; user = $RemoveUser; accessRights = @('FullAccess'); } $results.add("Removed $($removeuser) from $($username) Shared Mailbox permissions") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $($RemoveUser) from $($username) Shared Mailbox permission" -Sev 'Info' -tenant $TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Removed $($RemoveUser) from $($username) Shared Mailbox permission" -Sev 'Info' -tenant $TenantFilter } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME-message "Could not remove mailbox permissions for $($removeuser) on $($username)" -Sev 'Error' -tenant $TenantFilter $results.add("Could not remove $($removeuser) shared mailbox permissions for $($username). Error: $($_.Exception.Message)") @@ -29,7 +31,7 @@ Function Invoke-ExecEditMailboxPermissions { } $AddFullAccess = ($Request.body.AddFullAccess).value - foreach ($UserAutomap in $AddFullAccess) { + foreach ($UserAutomap in $AddFullAccess) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-MailboxPermission' -cmdParams @{Identity = $userid; user = $UserAutomap; accessRights = @('FullAccess'); automapping = $true } $results.add( "Granted $($UserAutomap) access to $($username) Mailbox with automapping") @@ -42,7 +44,7 @@ Function Invoke-ExecEditMailboxPermissions { } $AddFullAccessNoAutoMap = ($Request.body.AddFullAccessNoAutoMap).value - foreach ($UserNoAutomap in $AddFullAccessNoAutoMap) { + foreach ($UserNoAutomap in $AddFullAccessNoAutoMap) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-MailboxPermission' -cmdParams @{Identity = $userid; user = $UserNoAutomap; accessRights = @('FullAccess'); automapping = $false } $results.add( "Granted $UserNoAutomap access to $($username) Mailbox without automapping") @@ -55,7 +57,7 @@ Function Invoke-ExecEditMailboxPermissions { $AddSendAS = ($Request.body.AddSendAs).value - foreach ($UserSendAs in $AddSendAS) { + foreach ($UserSendAs in $AddSendAS) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-RecipientPermission' -cmdParams @{Identity = $userid; Trustee = $UserSendAs; accessRights = @('SendAs') } $results.add( "Granted $UserSendAs access to $($username) with Send As permissions") @@ -68,7 +70,7 @@ Function Invoke-ExecEditMailboxPermissions { $RemoveSendAs = ($Request.body.RemoveSendAs).value - foreach ($UserSendAs in $RemoveSendAs) { + foreach ($UserSendAs in $RemoveSendAs) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-RecipientPermission' -cmdParams @{Identity = $userid; Trustee = $UserSendAs; accessRights = @('SendAs') } $results.add( "Removed $UserSendAs from $($username) with Send As permissions") @@ -81,7 +83,7 @@ Function Invoke-ExecEditMailboxPermissions { $AddSendOnBehalf = ($Request.body.AddSendOnBehalf).value - foreach ($UserSendOnBehalf in $AddSendOnBehalf) { + foreach ($UserSendOnBehalf in $AddSendOnBehalf) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; add = $UserSendOnBehalf }; } $results.add( "Granted $UserSendOnBehalf access to $($username) with Send On Behalf Permissions") @@ -94,7 +96,7 @@ Function Invoke-ExecEditMailboxPermissions { $RemoveSendOnBehalf = ($Request.body.RemoveSendOnBehalf).value - foreach ($UserSendOnBehalf in $RemoveSendOnBehalf) { + foreach ($UserSendOnBehalf in $RemoveSendOnBehalf) { try { $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; GrantSendonBehalfTo = @{'@odata.type' = '#Exchange.GenericHashTable'; remove = $UserSendOnBehalf }; } $results.add( "Removed $UserSendOnBehalf from $($username) Send on Behalf Permissions") diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 index f9b05a8f662a..9ddf5aa7b523 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecEmailForward { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -23,12 +25,12 @@ Function Invoke-ExecEmailForward { $results = "Forwarding all email for $($username) to $($ForwardingAddress) and not keeping a copy" } elseif ($request.body.KeepCopy) { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set Forwarding for $($username) to $($ForwardingAddress) and keeping a copy" -Sev 'Info' -tenant $TenantFilter - $results = "Forwarding all email for $($username) to $($ForwardingAddress) and keeping a copy" + $results = "Forwarding all email for $($username) to $($ForwardingAddress) and keeping a copy" } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev 'Error' -tenant $TenantFilter $results = "Could not add forwarding for $($username). Error: $($_.Exception.Message)" - + } } @@ -40,12 +42,12 @@ Function Invoke-ExecEmailForward { $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and not keeping a copy" } elseif ($request.body.KeepCopy) { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Set forwarding for $($username) to $($ForwardingSMTPAddress) and keeping a copy" -Sev 'Info' -tenant $TenantFilter - $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and keeping a copy" + $results = "Forwarding all email for $($username) to $($ForwardingSMTPAddress) and keeping a copy" } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not add forwarding for $($username)" -Sev 'Error' -tenant $TenantFilter $results = "Could not add forwarding for $($username). Error: $($_.Exception.Message)" - + } } @@ -58,7 +60,7 @@ Function Invoke-ExecEmailForward { } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not disable Email forwarding for $($username)" -Sev 'Error' -tenant $TenantFilter $results = "Could not disable Email forwarding for $($username). Error: $($_.Exception.Message)" - + } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 index ac4cf5f8686b..f1dfb475b1cd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecEnableArchive { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 index c4f5be9d67f7..d66af4964171 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGroupsDelete { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 index d77c8a56d6e7..1f096507bd61 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGroupsDeliveryManagement { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,7 +20,7 @@ Function Invoke-ExecGroupsDeliveryManagement { # Interact with query parameters or the body of the request. Try { - $SetResults = Set-CIPPGroupAuthentication -ID $Request.query.id -GroupType $Request.query.GroupType -OnlyAllowInternalString $Request.query.OnlyAllowInternal -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $SetResults = Set-CIPPGroupAuthentication -ID $Request.query.id -GroupType $Request.query.GroupType -OnlyAllowInternalString $Request.query.OnlyAllowInternal -tenantFilter $Request.query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' $Results = [pscustomobject]@{'Results' = $SetResults } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 index 6307f2ef898d..caf559918240 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGroupsHideFromGAL { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -13,7 +15,7 @@ Function Invoke-ExecGroupsHideFromGAL { # Interact with query parameters or the body of the request. Try { - $GroupStatus = Set-CIPPGroupGAL -Id $Request.query.id -tenantFilter $Request.query.TenantFilter -GroupType $Request.query.groupType -HiddenString $Request.query.HidefromGAL -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $GroupStatus = Set-CIPPGroupGAL -Id $Request.query.id -tenantFilter $Request.query.TenantFilter -GroupType $Request.query.groupType -HiddenString $Request.query.HidefromGAL -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' $Results = [pscustomobject]@{'Results' = $GroupStatus } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 index 787bdd798e36..7dac7da9c2fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecHideFromGAL { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 index 483594d83889..a80a812b45d6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 @@ -2,7 +2,9 @@ using namespace System.Net Function Invoke-ExecMailTest { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 15f96d33503a..7b58b76afc7c 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecMailboxMobileDevices { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 index 8dc0bf5981f6..fb66074d979d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 @@ -1,7 +1,9 @@ function Invoke-ExecMailboxRestore { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> Param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 index 7f85df715207..e22301a7629c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecQuarantineManagement { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,9 +20,9 @@ Function Invoke-ExecQuarantineManagement { # Interact with query parameters or the body of the request. Try { - $tenantfilter = $Request.Query.TenantFilter + $tenantfilter = $Request.Query.TenantFilter $params = @{ - Identity = $request.query.ID + Identity = $request.query.ID AllowSender = [boolean]$Request.query.AllowSender ReleasetoAll = [boolean]$Request.query.type ActionType = $Request.query.type diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxQuota.ps1 index f2059365139c..a55f1a420a1b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxQuota.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxQuota.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSetMailboxQuota { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 index c0a004791254..fab2212d888c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSetOoO { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantine.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantine.ps1 index 4b1a1c68b57f..fcdf05d199fb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantine.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantine.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMailQuarantine { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 index 5ec6203892c4..434b5121d544 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMessageTrace { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Transport.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,10 +20,10 @@ Function Invoke-ListMessageTrace { StartDate = (Get-Date).AddDays( - $($request.query.days)).ToString('s') EndDate = (Get-Date).ToString('s') } - + if ($null -ne $request.query.recipient) { $Searchparams.Add('RecipientAddress', $($request.query.recipient)) } if ($null -ne $request.query.sender) { $Searchparams.Add('SenderAddress', $($request.query.sender)) } - $type = $request.query.Tracedetail + $type = $request.query.Tracedetail $trace = if ($Request.Query.Tracedetail) { New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MessageTraceDetail' -cmdParams $Searchparams Get-MessageTraceDetail -MessageTraceId $Request.Query.ID -RecipientAddress $request.query.recipient -erroraction stop | Select-Object Event, Action, Detail, @{ Name = 'Date'; Expression = { $_.Date.Tostring('s') } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 index b83c74d7dd42..dc3a35d2201c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListOoO { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListPhishPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListPhishPolicies.ps1 index 1b3d767f85fd..28e46a3b88c4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListPhishPolicies.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListPhishPolicies.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListPhishPolicies { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 index 29bc8bd8a01a..e995daa9231c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListRecipients { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -26,9 +28,9 @@ Function Invoke-ListRecipients { Select = $select } - $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ArchiveGuid, - @{ Name = 'UPN'; Expression = { $_.'PrimarySmtpAddress' } }, - @{ Name = 'mail'; Expression = { $_.'PrimarySmtpAddress' } }, + $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ArchiveGuid, + @{ Name = 'UPN'; Expression = { $_.'PrimarySmtpAddress' } }, + @{ Name = 'mail'; Expression = { $_.'PrimarySmtpAddress' } }, @{ Name = 'displayName'; Expression = { $_.'DisplayName' } } $StatusCode = [HttpStatusCode]::OK } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamFilterTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamFilterTemplates.ps1 index 9782073ffb25..e38c63bbedbf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamFilterTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamFilterTemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSpamFilterTemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -14,12 +16,12 @@ Function Invoke-ListSpamFilterTemplates { #List new policies $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'SpamfilterTemplate'" + $Filter = "PartitionKey eq 'SpamfilterTemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { $GUID = $_.RowKey - $data = $_.JSON | ConvertFrom-Json + $data = $_.JSON | ConvertFrom-Json $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID - $data + $data } if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamfilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamfilter.ps1 index 3e705b9f46a5..cb58d1a378f2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamfilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamfilter.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSpamfilter { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 index 18e9fb3959d2..283afe12e1ee 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTransportRules { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRulesTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRulesTemplates.ps1 index 1c42c21d9470..31fe9e6b04a9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRulesTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRulesTemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTransportRulesTemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -13,7 +15,7 @@ Function Invoke-ListTransportRulesTemplates { $Table = Get-CippTable -tablename 'templates' $Templates = Get-ChildItem 'Config\*.TransportRuleTemplate.json' | ForEach-Object { - + $Entity = @{ JSON = "$(Get-Content $_)" RowKey = "$($_.name)" @@ -26,12 +28,12 @@ Function Invoke-ListTransportRulesTemplates { #List new policies $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'TransportTemplate'" + $Filter = "PartitionKey eq 'TransportTemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { $GUID = $_.RowKey - $data = $_.JSON | ConvertFrom-Json + $data = $_.JSON | ConvertFrom-Json $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID - $data + $data } if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 index 7c94dbe33d81..f554fd228f7b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddChocoApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 index 5ecd0a49fcb9..663a490927e9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddMSPApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -21,37 +23,37 @@ Function Invoke-AddMSPApp { $Results = foreach ($Tenant in $tenants) { $InstallParams = [pscustomobject]$RMMApp.params switch ($rmmapp.RMMName.value) { - 'datto' { + 'datto' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -URL $($InstallParams.DattoURL) -GUID $($InstallParams.DattoGUID["$($tenant.customerId)"])" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } - 'ninja' { + 'ninja' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -InstallParam $($RMMApp.PackageName)" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } - 'Huntress' { + 'Huntress' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -OrgKey $($InstallParams.Orgkey["$($tenant.customerId)"]) -acctkey $($InstallParams.AccountKey)" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\install.ps1 -Uninstall' } - 'Immybot' { + 'Immybot' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -url $($InstallParams.ClientURL["$($tenant.customerId)"])" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } - 'syncro' { + 'syncro' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -URL $($InstallParams.ClientURL["$($tenant.customerId)"])" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } - 'NCentral' { + 'NCentral' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -InstallParam $($RMMApp.PackageName)" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } - 'automate' { + 'automate' { $installcommandline = "c:\windows\sysnative\windowspowershell\v1.0\powershell.exe -executionpolicy bypass .\install.ps1 -Server $($InstallParams.Server) -InstallerToken $($InstallParams.InstallerToken["$($tenant.customerId)"]) -LocationID $($InstallParams.LocationID["$($tenant.customerId)"])" $UninstallCommandLine = "c:\windows\sysnative\windowspowershell\v1.0\powershell.exe -executionpolicy bypass .\uninstall.ps1 -Server $($InstallParams.Server)" $DetectionScript = (Get-Content 'AddMSPApp\automate.detection.ps1' -Raw) -replace '##SERVER##', $InstallParams.Server $intuneBody.detectionRules[0].scriptContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($DetectionScript)) } - 'cwcommand' { + 'cwcommand' { $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -Url $($InstallParams.ClientURL["$($tenant.customerId)"])" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 index 865449257a89..e5a73e7dcb6c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddOfficeApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -61,14 +63,14 @@ Function Invoke-AddOfficeApp { 'updateChannel' = $request.body.updateChannel.value 'useSharedComputerActivation' = [bool]$request.body.SharedComputerActivation 'productIds' = $products - 'largeIcon' = @{ + 'largeIcon' = @{ 'type' = 'image/png' 'value' = 'iVBORw0KGgoAAAANSUhEUgAAAF0AAAAeCAMAAAEOZNKlAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJhUExURf////7z7/i9qfF1S/KCW/i+qv3q5P/9/PrQwfOMae1RG+s8AOxGDfBtQPWhhPvUx/759/zg1vWgg+9fLu5WIvKFX/rSxP728/nCr/FyR+tBBvOMaO1UH+1RHOs+AvSScP3u6f/+/v3s5vzg1+xFDO9kNPOOa/i7pvzj2/vWyes9Af76+Pzh2PrTxf/6+f7y7vOGYexHDv3t5+1SHfi8qPOIZPvb0O1NFuxDCe9hMPSVdPnFs/3q4/vaz/STcu5VIe5YJPWcfv718v/9/e1MFfF4T/F4TvF2TP3o4exECvF0SexIEPONavzn3/vZze1QGvF3Te5dK+5cKvrPwPrQwvKAWe1OGPexmexKEveulfezm/BxRfamiuxLE/apj/zf1e5YJfSXd/OHYv3r5feznPakiPze1P7x7f739f3w6+xJEfnEsvWdf/Wfge1LFPe1nu9iMvnDsfBqPOs/BPOIY/WZevJ/V/zl3fnIt/vTxuxHD+xEC+9mN+5ZJv749vBpO/KBWvBwRP/8+/SUc/etlPjArP/7+vOLZ/F7UvWae/708e1OF/aihvSWdvi8p+tABfSZefvVyPWihfSVde9lNvami+9jM/zi2fKEXvBuQvOKZvalifF5UPJ/WPSPbe9eLfrKuvvd0uxBB/7w7Pzj2vrRw/rOv+1PGfi/q/eymu5bKf3n4PnJuPBrPf3t6PWfgvWegOxCCO9nOO9oOfaskvSYePi5pPi2oPnGtO5eLPevlvKDXfrNvv739Pzd0/708O9gL+9lNfJ9VfrLu/OPbPnDsPBrPus+A/nArfarkQAAAGr5HKgAAADLdFJOU/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AvuakogAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAz5JREFUOE+tVTtu4zAQHQjppmWzwIJbEVCzpTpjbxD3grQHSOXKRXgCAT6EC7UBVAmp3KwBnmvfzNCyZTmxgeTZJsXx43B+HBHRE34ZkXgkerXFTheeiCkRrbB4UXmp4wSWz5raaQEMTM5TZwuiXoaKgV+6FsmkZQcSy0kA71yMTMGHanX+AzMMGLAQCxU1F/ZwjULPugazl82GM0NEKm/U8EqFwEkO3/EAT4grgl0nucwlk9pcpTTJ4VPA4g/Rb3yIRhhp507e9nTQmZ1OS5RO4sS7nIRPEeHXCHdkw9ZEW2yVE5oIS7peD58Avs7CN+PVCmHh21oOqBdjDzIs+FldPJ74TFESUSJEfVzy9U/dhu+AuOT6eBp6gGKyXEx8euO450ZE4CMfstMFT44broWw/itkYErWXRx+fFArt9Ca9os78TFed0LVIUsmIHrwbwaw3BEOnOk94qVpQ6Ka2HjxewJnfyd6jUtGDQLdWlzmYNYLeKbbGOucJsNabCq1Yub0o92rtR+i30V2dapxYVEePXcOjeCKPnYyit7BtKeNlZqHbr+gt7i+AChWA9RsRs03pxTQc67ouWpxyESvjK5Vs3DVSy3IpkxPm5X+wZoBi+MFHWW69/w8FRhc7VBe6HAhMB2b8Q0XqDzTNZtXUMnKMjwKVaCrB/CSUL7WSx/HsdJC86lFGXwnioTeOMPjV+szlFvrZLA5VMVK4y+41l4e1xfx7Z88o4hkilRUH/qKqwNVlgDgpvYCpH3XwAy5eMCRnezIUxffVXoDql2rTHFDO+pjWnTWzAfrYXn6BFECblUpWGrvPZvBipETjS5ydM7tdXpH41ZCEbBNy/+wFZu71QO2t9pgT+iZEf657Q1vpN94PQNDxUHeKR103LV9nPVOtDikcNKO+2naCw7yKBhOe9Hm79pe8C4/CfC2wDjXnqC94kEeBU3WwN7dt/2UScXas7zDl5GpkY+M8WKv2J7fd4Ib2rGTk+jsC2cleEM7jI9veF7B0MBJrsZqfKd/81q9pR2NZfwJK2JzsmIT1Ns8jUH0UusQBpU8d2JzsHiXg1zXGLqxfitUNTDT/nUUeqDBp2HZVr+Ocqi/Ty3Rf4Jn82xxfSNtAAAAAElFTkSuQmCC' } } Write-Host ($ObjBody | ConvertTo-Json -Compress) $OfficeAppID = New-graphPostRequest -Uri 'https://graph.microsoft.com/beta/deviceAppManagement/mobileApps' -tenantid $tenant -Body (ConvertTo-Json -InputObject $ObjBody -Depth 10) -type POST - } else { + } else { "Office deployment already exists for $($Tenant)" Continue } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 index d59307524615..8097c6d328e2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddWinGetApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAssignApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAssignApp.ps1 index 4825fc8a9f81..74a83ce92927 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAssignApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAssignApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAssignApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -24,7 +26,7 @@ Function Invoke-ExecAssignApp { 'AllUsers' { @' {"mobileAppAssignments":[{"@odata.type":"#microsoft.graph.mobileAppAssignment","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"},"intent":"Required","settings":null}]} -'@ +'@ } 'AllDevices' { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 index 13e945aa16ed..0aa432beff14 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListApplicationQueue { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApps.ps1 index aca3cafdcd2f..d5c13112058f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApps.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApps.ps1 @@ -1,35 +1,37 @@ using namespace System.Net Function Invoke-ListApps { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps?`$top=999&`$filter=(microsoft.graph.managedApp/appAvailability%20eq%20null%20or%20microsoft.graph.managedApp/appAvailability%20eq%20%27lineOfBusiness%27%20or%20isAssigned%20eq%20true)&`$orderby=displayName&" -tenantid $TenantFilter - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - } + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps?`$top=999&`$filter=(microsoft.graph.managedApp/appAvailability%20eq%20null%20or%20microsoft.graph.managedApp/appAvailability%20eq%20%27lineOfBusiness%27%20or%20isAssigned%20eq%20true)&`$orderby=displayName&" -tenantid $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 index e85a43e1740b..4f9d60aa52df 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAppsRepository { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -39,7 +41,7 @@ Function Invoke-ListAppsRepository { description = $RepoPackage.summary.'#text' customRepo = $Repository created = Get-Date -Date $RepoPackage.properties.Created.'#text' -Format 'MM/dd/yyyy HH:mm:ss' - } + } } } else { $IsError = $true diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 index 262bb17f79bc..5e109b7d0a8c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddAPDevice { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 index 96208b3674f8..38c9161bbabd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddAutopilotConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 index f74ce07857d1..eaed0e5aba15 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddEnrollment { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 index 450e93ef642b..0ae4d1f13cb0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAssignAPDevice { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -15,7 +17,7 @@ Function Invoke-ExecAssignAPDevice { UserPrincipalName = $Request.body.UserPrincipalName addressableUserName = $Request.body.addressableUserName } | ConvertTo-Json - New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$($request.body.Device)/UpdateDeviceProperties" -tenantid $TenantFilter -body $body -method POST + New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$($request.body.Device)/UpdateDeviceProperties" -tenantid $TenantFilter -body $body -method POST $Results = "Successfully assigned device to $($Request.body.UserPrincipalName) for $($tenantfilter)" } catch { $Results = "Could not $($Request.body.UserPrincipalName) to $($Request.body.device) for $($tenantfilter) Error: $($_.Exception.Message)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ListAPDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ListAPDevices.ps1 index c2ec2c1f497b..ab840b320596 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ListAPDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ListAPDevices.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAPDevices { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,7 +20,7 @@ Function Invoke-ListAPDevices { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities?`$top=999" -tenantid $TenantFilter + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities?`$top=999" -tenantid $TenantFilter $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 index e38a8fd67769..7bb3f446bd11 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddDefenderDeployment { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -38,7 +40,7 @@ Function Invoke-AddDefenderDeployment { $Settings = switch ($PolicySettings) { { $_.ScanArchives } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowarchivescanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowarchivescanning_1'; settingValueTemplateReference = @{settingValueTemplateId = '9ead75d4-6f30-4bc5-8cc5-ab0f999d79f0' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '7c5c9cde-f74d-4d11-904f-de4c27f72d89' } } } + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowarchivescanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowarchivescanning_1'; settingValueTemplateReference = @{settingValueTemplateId = '9ead75d4-6f30-4bc5-8cc5-ab0f999d79f0' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '7c5c9cde-f74d-4d11-904f-de4c27f72d89' } } } } { $_.AllowBehavior } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowbehaviormonitoring' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowbehaviormonitoring_1'; settingValueTemplateReference = @{settingValueTemplateId = '905921da-95e2-4a10-9e30-fe5540002ce1' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '8eef615a-1aa0-46f4-a25a-12cbe65de5ab' } } } } { $_.AllowCloudProtection } { @@ -87,7 +89,7 @@ Function Invoke-AddDefenderDeployment { roleScopeTagIds = @('0') templateReference = @{templateId = '804339ad-1553-4478-a742-138fb5807418_1' } settings = $Settings - } + } $PolicyRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $PolBody if ($PolicySettings.AssignTo -ne 'None') { $AssignBody = if ($PolicySettings.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($PolicySettings.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } @@ -150,7 +152,7 @@ Function Invoke-AddDefenderDeployment { } $EDRSettings = switch ($EDR) { - { $_.SampleSharing } { + { $_.SampleSharing } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' settingInstance = @{ @@ -163,9 +165,9 @@ Function Invoke-AddDefenderDeployment { } settingInstanceTemplateReference = @{settingInstanceTemplateId = '6998c81e-2814-4f5e-b492-a6159128a97b' } } - } + } } - { $_.Telemetry } { + { $_.Telemetry } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' settingInstance = @{ @@ -178,10 +180,10 @@ Function Invoke-AddDefenderDeployment { } settingInstanceTemplateReference = @{settingInstanceTemplateId = '03de6095-07c4-4f35-be38-c1cd3bae4484' } } - } - + } + } - { $_.Config } { + { $_.Config } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' settingInstance = @{ @@ -193,11 +195,11 @@ Function Invoke-AddDefenderDeployment { settingValueTemplateReference = @{settingValueTemplateId = 'e5c7c98c-c854-4140-836e-bd22db59d651' } children = @(@{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' ; settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_onboarding_fromconnector' ; simpleSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSecretSettingValue' ; value = 'Microsoft ATP connector enabled'; valueState = 'NotEncrypted' } } ) } - + settingInstanceTemplateReference = @{settingInstanceTemplateId = '23ab0ea3-1b12-429a-8ed0-7390cf699160' } } - } - + } + } } $EDRbody = ConvertTo-Json -Depth 15 -Compress -InputObject @{ 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 b4c3471b4fca..1fe3b38b1825 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddIntuneTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 index ac6648f814dc..a00bc8c60e64 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddPolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditPolicy.ps1 index e30d3971cb00..066e83cf11df 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-EditPolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditPolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -16,7 +18,7 @@ Function Invoke-EditPolicy { $displayname = $request.body.Displayname $description = $request.body.Description $AssignTo = if ($request.body.Assignto -ne 'on') { $request.body.Assignto } - + $results = try { $CreateBody = '{"description":"' + $description + '","displayName":"' + $displayname + '","roleScopeTagIds":["0"]}' $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations('$ID')" -tenantid $tenant -type PATCH -body $CreateBody diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 index ae866ed3f485..8000d6f46d2f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAssignPolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -15,7 +17,7 @@ Function Invoke-ExecAssignPolicy { $ID = $request.query.id $displayname = $request.query.Displayname $AssignTo = if ($request.query.Assignto -ne 'on') { $request.query.Assignto } - + $results = try { if ($AssignTo) { $assign = Set-CIPPAssignedPolicy -PolicyId $ID -TenantFilter $tenant -GroupName $AssignTo -Type $Request.query.Type diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 index 90f9e86d4c6d..ca788cb979da 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecDeviceAction { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -14,10 +16,10 @@ Function Invoke-ExecDeviceAction { # Interact with query parameters or the body of the request. - try { + try { if ($Request.Query.Action -eq 'setDeviceName') { $ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress - } + } $ActionResult = New-CIPPDeviceAction -Action $Request.Query.Action -ActionBody $ActionBody -DeviceFilter $Request.Query.GUID -TenantFilter $Request.Query.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' -APINAME $APINAME $body = [pscustomobject]@{'Results' = "$ActionResult" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 index c58267717c20..f2850548e8c2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 @@ -1,30 +1,31 @@ - using namespace System.Net +using namespace System.Net - Function Invoke-ExecGetLocalAdminPassword { +Function Invoke-ExecGetLocalAdminPassword { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Device.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName + $APIName = $TriggerMetadata.FunctionName -try { - $GraphRequest = Get-CIPPLapsPassword -device $($request.query.guid) -tenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Body = [pscustomobject]@{"Results" = $GraphRequest } + try { + $GraphRequest = Get-CIPPLapsPassword -device $($request.query.guid) -tenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Body = [pscustomobject]@{'Results' = $GraphRequest } -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Body = [pscustomobject]@{"Results" = "Failed. $ErrorMessage" } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Body = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } -} + } -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) - } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 index 7190225450a5..46df4d780496 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGetRecoveryKey { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Device.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Reports/Invoke-ListDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Reports/Invoke-ListDevices.ps1 index 8587a32155e3..d4ed67595239 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Reports/Invoke-ListDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Reports/Invoke-ListDevices.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListDevices { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Device.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,7 +20,7 @@ Function Invoke-ListDevices { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter try { - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/managedDevices' -Tenantid $tenantfilter + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/managedDevices' -Tenantid $tenantfilter $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 index 25e64be478b3..14101947635f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecDeviceDelete { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Device.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 index 2a9d176a365e..f4dda9d8f50a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddGroup { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -46,14 +48,14 @@ Function Invoke-AddGroup { $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 = @{ + $Params = @{ Name = $groupobj.Displayname RecipientFilter = $groupobj.membershipRules PrimarySmtpAddress = $email } $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DynamicDistributionGroup' -cmdParams $params } else { - $Params = @{ + $Params = @{ Name = $groupobj.Displayname Alias = $groupobj.username Description = $groupobj.Description diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 index 85d10812a9c8..83d8e9a64743 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddGroupTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -12,7 +14,7 @@ Function Invoke-AddGroupTemplate { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $GUID = (New-Guid).GUID - try { + try { if (!$Request.body.displayname) { throw 'You must enter a displayname' } $object = [PSCustomObject]@{ 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 6990f6baa46f..122c4f118739 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditGroup { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -23,13 +25,13 @@ Function Invoke-EditGroup { $AddMembers | ForEach-Object { try { $member = $_ - + if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } - $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $Userobj.tenantid).id + $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $Userobj.tenantid).id $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $userobj.groupid; Member = $member; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)" -tenantid $Userobj.tenantid -type patch -body $addmemberbody -Verbose } @@ -67,7 +69,7 @@ Function Invoke-EditGroup { $RemoveMembers = ($userobj.Removemember).value try { if ($RemoveMembers) { - $RemoveMembers | ForEach-Object { + $RemoveMembers | ForEach-Object { $member = $_ if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { @@ -75,11 +77,11 @@ Function Invoke-EditGroup { New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid) - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/members/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/members/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE } Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Removed $member from $($userobj.groupName) group" -Sev 'Info' $null = $results.add("Success. Member $member has been removed from $($userobj.groupName)") - } + } } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to remove $RemoveMembers from $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' @@ -89,7 +91,7 @@ Function Invoke-EditGroup { $AddOwners = $userobj.Addowner.value try { if ($AddOwners) { - $AddOwners | ForEach-Object { + $AddOwners | ForEach-Object { try { $ID = 'https://graph.microsoft.com/beta/users/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid).id Write-Host $ID @@ -110,16 +112,16 @@ Function Invoke-EditGroup { $RemoveOwners = ($userobj.RemoveOwner).value try { if ($RemoveOwners) { - $RemoveOwners | ForEach-Object { + $RemoveOwners | ForEach-Object { try { $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid) - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Removed $($MemberInfo.UserPrincipalname) from $($userobj.displayname) group" -Sev 'Info' $null = $results.add("Success. Member $_ has been removed from $($userobj.groupName)") } catch { $null = $results.add("Failed to remove $_ from $($userobj.groupName): $($_.Exception.Message)") } - } + } } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to remove $RemoveMembers from $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' @@ -157,7 +159,7 @@ Function Invoke-EditGroup { $subscriberParams = @{ Identity = $userobj.Groupid; LinkType = 'subscribers'; Links = @($MemberSmtpAddresses) } New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-UnifiedGrouplinks' -cmdParams $subscriberParams -Anchor $userobj.mail - + $body = $results.add("Send Copies of team emails and events to team members inboxes for $($userobj.mail) enabled.") Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Send Copies of team emails and events to team members inboxes for $($userobj.mail) enabled." -Sev 'Info' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 index 462ba7df0545..43e1dc49d393 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddGuest { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -22,7 +24,7 @@ Function Invoke-AddGuest { 'InvitedUserEmailAddress' = $($userobj.mail) 'inviteRedirectUrl' = $($userobj.RedirectURL) 'sendInvitationMessage' = [boolean]$userobj.SendInvite - } + } } else { $BodyToship = [pscustomobject] @{ @@ -31,14 +33,14 @@ Function Invoke-AddGuest { 'sendInvitationMessage' = [boolean]$userobj.SendInvite 'inviteRedirectUrl' = 'https://myapps.microsoft.com' } - } + } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/invitations' -tenantid $Userobj.tenantid -type POST -body $BodyToship -verbose - if ($Userobj.sendInvite -eq 'true') { + if ($Userobj.sendInvite -eq 'true') { $results.add('Invited Guest. Invite Email sent') Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Invited Guest $($userobj.displayname) with Email Invite " -Sev 'Info' } - else { + else { $results.add('Invited Guest. No Invite Email was sent') Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Invited Guest $($userobj.displayname) with no Email Invite " -Sev 'Info' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 index 861ea01e85c4..5a4b4f95e08c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddUser { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 index 31c3fbbaa687..8169512aaeee 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddUserBulk { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -37,7 +39,7 @@ Function Invoke-AddUserBulk { } } $body = [pscustomobject] @{ - 'Results' = @($results) + 'Results' = @($results) 'Username' = $UserprincipalName 'Password' = $password 'CopyFrom' = $copyFromResults diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 index cb925b1cda70..39e018d223df 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditUser { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECCheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECCheck.ps1 index 7413636f7061..52aab6d770f5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECCheck.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECCheck.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecBECCheck { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 index b863aeac8f06..cfbf2078aa27 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecBECRemediate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -24,9 +26,9 @@ Function Invoke-ExecBECRemediate { $RuleDisabled = 0 New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'get-inboxrule' -cmdParams @{Mailbox = $username } | ForEach-Object { $null = New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'Disable-InboxRule' -cmdParams @{Confirm = $false; Identity = $_.Identity } - "Disabled Inbox Rule $($_.Identity) for $username" + "Disabled Inbox Rule $($_.Identity) for $username" $RuleDisabled ++ - } + } if ($RuleDisabled) { "Disabled $RuleDisabled Inbox Rules for $username" } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecClrImmId.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecClrImmId.ps1 index 3506522f2c8c..9241f5feae7d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecClrImmId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecClrImmId.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecClrImmId { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 index 9919b0564510..3ae22c37ffa7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 @@ -1,28 +1,30 @@ using namespace System.Net Function Invoke-ExecCreateTAP { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Interact with query parameters or the body of the request. - try { - $TAP = New-CIPPTAP -userid $Request.query.ID -TenantFilter $Request.query.tenantfilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{'Results' = "$TAP" } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } + # Interact with query parameters or the body of the request. + try { + $TAP = New-CIPPTAP -userid $Request.query.ID -TenantFilter $Request.query.tenantfilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = [pscustomobject]@{'Results' = "$TAP" } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } 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 3e32878e726d..69ac4dd83ec8 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 @@ -1,26 +1,28 @@ using namespace System.Net Function Invoke-ExecDisableUser { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - try { + $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)" } - } + $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)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 index 02516f3148bf..7142cb3ca837 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecOffboardUser { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -38,7 +40,7 @@ Function Invoke-ExecOffboardUser { Invoke-CIPPOffboardingJob -Username $Username -TenantFilter $Tenantfilter -Options $Request.body -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' } $StatusCode = [HttpStatusCode]::OK - + } catch { $StatusCode = [HttpStatusCode]::Forbidden $body = $_.Exception.message @@ -48,6 +50,6 @@ Function Invoke-ExecOffboardUser { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode Body = $Body - }) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboard_Mailboxpermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboard_Mailboxpermissions.ps1 index 18e70672635d..02e60ca462d0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboard_Mailboxpermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboard_Mailboxpermissions.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecOffboard_Mailboxpermissions { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 index 2f820ab4a068..ddc282908b68 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecOneDriveShortCut { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetMFA.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetMFA.ps1 index 457e8abcba1c..1667958aa7a1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetMFA.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetMFA.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecResetMFA { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -29,7 +31,7 @@ Function Invoke-ExecResetMFA { http://provisioning.microsoftonline.com/IProvisioningWebService/SetUserurn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])$($DataBlob)9450afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version47$TrackingGuidhttps://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion16$($tenantid)$($Request.query.id)*0001-01-01T00:00:00Enabled "@ $SetMFA = (Invoke-RestMethod -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -Method post -Body $MSOLXML -ContentType 'application/soap+xml; charset=utf-8') - + $Results = [pscustomobject]@{'Results' = 'Successfully completed request. User must supply MFA at next logon' } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Reset Multi factor authentication settings for $($Request.query.id)" -Sev 'Info' } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 index 0d16795f9104..c9be1da38759 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecResetPass { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 bab48ef09239..5c5c56fe568f 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 @@ -1,29 +1,31 @@ using namespace System.Net Function Invoke-ExecRevokeSessions { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # 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' - $Results = [pscustomobject]@{'Results' = $RevokeSessions } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } + # 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' + $Results = [pscustomobject]@{'Results' = $RevokeSessions } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 index aeeb61d4f9c8..3970db4890e6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSendPush { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -46,7 +48,7 @@ Function Invoke-ExecSendPush { # Create a serivce principal if needed if (!$SPID) { - + $SPBody = [pscustomobject]@{ appId = $MFAAppID } @@ -107,7 +109,7 @@ Function Invoke-ExecSendPush { $Body = "Authentication Failed! Does the user have Push/Phone call MFA configured? Errorcode: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" $colour = 'danger' } - + } $Results = [pscustomobject]@{'Results' = $Body; colour = $colour } @@ -117,6 +119,6 @@ Function Invoke-ExecSendPush { StatusCode = [HttpStatusCode]::OK Body = $Results }) - + } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 index 1557184a8bb6..dd0ced4e4e68 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserConditionalAccessPolicies { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -41,7 +43,7 @@ Function Invoke-ListUserConditionalAccessPolicies { # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) + Body = @($GraphRequest) }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserCounts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserCounts.ps1 index 137a9c8cc902..d67251b461e0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserCounts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserCounts.ps1 @@ -1,45 +1,47 @@ using namespace System.Net Function Invoke-ListUserCounts { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - if ($Request.Query.TenantFilter -eq 'AllTenants') { - $users = 'Not Supported' - $LicUsers = 'Not Supported' - $GAs = 'Not Supported' - $Guests = 'Not Supported' - } else { - try { $Users = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Users = 'Not available' } - try { $LicUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=assignedLicenses/`$count ne 0" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Licusers = 'Not available' } - try { $GAs = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members?`$count=true" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Gas = 'Not available' } - try { $guests = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=userType eq 'Guest'" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Guests = 'Not available' } - } - $StatusCode = [HttpStatusCode]::OK - $Counts = @{ - Users = $users - LicUsers = $LicUsers - Gas = $Gas - Guests = $guests - } + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($Request.Query.TenantFilter -eq 'AllTenants') { + $users = 'Not Supported' + $LicUsers = 'Not Supported' + $GAs = 'Not Supported' + $Guests = 'Not Supported' + } else { + try { $Users = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Users = 'Not available' } + try { $LicUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=assignedLicenses/`$count ne 0" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Licusers = 'Not available' } + try { $GAs = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/roleTemplateId=62e90394-69f5-4237-9190-012177145e10/members?`$count=true" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Gas = 'Not available' } + try { $guests = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$count=true&`$top=1&`$filter=userType eq 'Guest'" -CountOnly -ComplexFilter -tenantid $TenantFilter } catch { $Guests = 'Not available' } + } + $StatusCode = [HttpStatusCode]::OK + $Counts = @{ + Users = $users + LicUsers = $LicUsers + Gas = $Gas + Guests = $guests + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Counts - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Counts + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserDevices.ps1 index 0bbcb27b4422..0c36e75712fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserDevices.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserDevices { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 index fff7eb222d9c..26676aec5623 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserGroups.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserGroups { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -20,7 +22,7 @@ Function Invoke-ListUserGroups { $UserID = $Request.Query.UserID - $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&$orderby=displayName asc" + $URI = "https://graph.microsoft.com/beta/users/$UserID/memberOf/$/microsoft.graph.group?`$select=id,displayName,mailEnabled,securityEnabled,groupTypes,onPremisesSyncEnabled,mail,isAssignableToRole`&$orderby=displayName asc" Write-Host $URI $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object id, @{ Name = 'DisplayName'; Expression = { $_.displayName } }, diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 index 22f5665696c4..152323e21b4e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserMailboxDetails { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -23,7 +25,7 @@ Function Invoke-ListUserMailboxDetails { $TenantFilter = $Request.Query.TenantFilter try { $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) - $base64IdentityParam = [Convert]::ToBase64String($Bytes) + $base64IdentityParam = [Convert]::ToBase64String($Bytes) $CASRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true $MailRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true $FetchParam = @{ @@ -32,7 +34,7 @@ Function Invoke-ListUserMailboxDetails { $MailboxDetailedRequest = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams $FetchParam try { if ($MailboxDetailedRequest.ArchiveStatus -eq 'Active') { - $ArchiveEnabled = $True + $ArchiveEnabled = $True } else { $ArchiveEnabled = $False } @@ -68,7 +70,7 @@ Function Invoke-ListUserMailboxDetails { } $StatsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/Exchange.GetMailboxStatistics()" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline + $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline } catch { Write-Error "Failed Fetching Data $($_.Exception.message): $($_.InvocationInfo.ScriptLineNumber)" @@ -79,16 +81,16 @@ Function Invoke-ListUserMailboxDetails { if ($perm.Trustee) { $perm | Where-Object Trustee | ForEach-Object { [PSCustomObject]@{ User = $_.Trustee - AccessRights = $_.accessRights -join ', ' + AccessRights = $_.accessRights -join ', ' } } - + } if ($perm.PermissionList) { $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ User = $_.User AccessRights = $_.PermissionList.accessRights -join ', ' - } + } } } } @@ -98,10 +100,10 @@ Function Invoke-ListUserMailboxDetails { } elseif ($MailboxDetailedRequest.ForwardingSmtpAddress -and $MailboxDetailedRequest.ForwardingAddress) { $MailboxDetailedRequest.ForwardingAddress + ' ' + $MailboxDetailedRequest.ForwardingSmtpAddress } else { - $MailboxDetailedRequest.ForwardingSmtpAddress + $MailboxDetailedRequest.ForwardingSmtpAddress } - if ($ArchiveSize) { + if ($ArchiveSize) { $GraphRequest = [ordered]@{ ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward ForwardingAddress = $ForwardingAddress diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 index 4a0a433fc1d4..eade83ccee64 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserMailboxRules { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 index bd596e0a379a..757784ad320d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserPhoto { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSettings.ps1 index 50781d922e7b..85b59ec479fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSettings.ps1 @@ -3,7 +3,9 @@ using namespace System.Net function Invoke-ListUserSettings { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 index d421b79441d5..32c2cc24f28a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUserSigninLogs { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -19,7 +21,7 @@ Function Invoke-ListUserSigninLogs { $TenantFilter = $Request.Query.TenantFilter $UserID = $Request.Query.UserID try { - $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$UserID')&`$top=50&`$orderby=createdDateTime desc" + $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$UserID')&`$top=50&`$orderby=createdDateTime desc" Write-Host $URI $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'Date'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } }, id, diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 index 8431d441a320..b85dde08e21f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListUsers { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -72,11 +74,11 @@ Function Invoke-ListUsers { Id = $AuditlogsLogon.errorNumber Status = $AuditlogsLogon.ResultStatus } - $GraphRequest = $GraphRequest | Select-Object *, + $GraphRequest = $GraphRequest | Select-Object *, @{ Name = 'LastSigninApplication'; Expression = { $LastSignIn.AppDisplayName } }, @{ Name = 'LastSigninDate'; Expression = { $($LastSignIn.CreatedDateTime | Out-String) } }, @{ Name = 'LastSigninStatus'; Expression = { $AuditlogsLogon.operation } }, - @{ Name = 'LastSigninResult'; Expression = { $LastSignIn.status } }, + @{ Name = 'LastSigninResult'; Expression = { $LastSignIn.status } }, @{ Name = 'LastSigninFailureReason'; Expression = { if ($LastSignIn.Id -eq 0) { 'Sucessfully signed in' } else { $LastSignIn.Id } } } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuth.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuth.ps1 index bf831b65cc9b..9cdbce1b86c8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuth.ps1 @@ -3,12 +3,14 @@ using namespace System.Net Function Invoke-ListBasicAuth { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.AuditLog.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - + # Write to the Azure Functions log stream. 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' @@ -25,7 +27,7 @@ Function Invoke-ListBasicAuth { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&filter=$($filters)" -tenantid $TenantFilter -erroraction stop | Select-Object userPrincipalName, clientAppUsed, Status | Sort-Object -Unique -Property userPrincipalName $response = $GraphRequest Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Retrieved basic authentication report' -Sev 'Debug' -tenant $TenantFilter - + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuthAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuthAllTenants.ps1 index e4be4bafbb02..26d93e02b387 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuthAllTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListBasicAuthAllTenants.ps1 @@ -3,13 +3,15 @@ using namespace System.Net Function Invoke-ListBasicAuthAllTenants { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.AuditLog.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - - Get-Tenants | ForEach-Object -Parallel { + + Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName Import-Module '.\Modules\AzBobbyTables' Import-Module '.\Modules\CIPPCore' @@ -36,7 +38,7 @@ Function Invoke-ListBasicAuthAllTenants { RowKey = $domainName PartitionKey = 'basicauth' } - } + } $Table = Get-CIPPTable -TableName cachebasicauth Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAlertsList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsList.ps1 similarity index 97% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAlertsList.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsList.ps1 index 1b6141e1fcda..f3580ec3fc19 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAlertsList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsList.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAlertsList { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Security.Alert.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -26,7 +28,7 @@ Function Invoke-ExecAlertsList { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $TenantFilter + $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $TenantFilter $AlertsObj = foreach ($Alert In $alerts) { @{ Tenant = $TenantFilter @@ -42,7 +44,7 @@ Function Invoke-ExecAlertsList { } } - $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending + $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending [PSCustomObject]@{ NewAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'newAlert' } | Measure-Object | Select-Object -ExpandProperty Count @@ -79,7 +81,7 @@ Function Invoke-ExecAlertsList { InvolvedUsers = $AlertInfo.userStates } } - $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending + $DisplayableAlerts = New-FlatArray $AlertsObj | Where-Object { $_.Id -ne $null } | Sort-Object -Property EventDateTime -Descending [PSCustomObject]@{ NewAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'newAlert' } | Measure-Object | Select-Object -ExpandProperty Count InProgressAlertsCount = $DisplayableAlerts | Where-Object { $_.Status -eq 'inProgress' } | Measure-Object | Select-Object -ExpandProperty Count @@ -103,6 +105,6 @@ Function Invoke-ExecAlertsList { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode Body = $Body - }) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsListAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsListAllTenants.ps1 index fc14d337dc28..cbab4f74d8ad 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsListAllTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecAlertsListAllTenants.ps1 @@ -3,20 +3,22 @@ using namespace System.Net Function Invoke-ExecAlertsListAllTenants { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Security.Alert.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - - Get-Tenants | ForEach-Object -Parallel { + + Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName Import-Module '.\Modules\AzBobbyTables' Import-Module '.\Modules\CIPPCore' $Table = Get-CIPPTable -TableName 'cachealertsandincidents' try { - $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $domainName + $Alerts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/alerts' -tenantid $domainName foreach ($Alert in $Alerts) { $GUID = (New-Guid).Guid $alertJson = $Alert | ConvertTo-Json @@ -33,7 +35,7 @@ Function Invoke-ExecAlertsListAllTenants { } catch { $GUID = (New-Guid).Guid $AlertText = ConvertTo-Json -InputObject @{ - Title = "Could not connect to tenant to retrieve data: $($_.Exception.Message)" + Title = "Could not connect to tenant to retrieve data: $($_.Exception.Message)" Id = '' Category = '' EventDateTime = '' @@ -46,7 +48,7 @@ Function Invoke-ExecAlertsListAllTenants { } } $GraphRequest = @{ - Alert = [string]$AlertText + Alert = [string]$AlertText RowKey = [string]$GUID PartitionKey = 'alert' Tenant = $domainName diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 index e3bb573809ef..184f629f2b2c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecIncidentsList { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Security.Incident.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -16,7 +18,7 @@ Function Invoke-ExecIncidentsList { $GraphRequest = if ($TenantFilter -ne 'AllTenants') { $incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $Request.Query.TenantFilter -AsApp $true - foreach ($incident in $incidents) { + foreach ($incident in $incidents) { [PSCustomObject]@{ Tenant = $Request.Query.TenantFilter Id = $incident.id @@ -33,7 +35,7 @@ Function Invoke-ExecIncidentsList { Tags = ($IncidentObj.tags -join ', ') Comments = $incident.comments } - } + } } else { $Table = Get-CIPPTable -TableName cachealertsandincidents $Filter = "PartitionKey eq 'Incident'" @@ -45,8 +47,8 @@ Function Invoke-ExecIncidentsList { } } else { $incidents = $Rows - foreach ($incident in $incidents) { - $IncidentObj = $incident.Incident | ConvertFrom-Json + foreach ($incident in $incidents) { + $IncidentObj = $incident.Incident | ConvertFrom-Json [PSCustomObject]@{ Tenant = $incident.Tenant Id = $IncidentObj.id @@ -63,7 +65,7 @@ Function Invoke-ExecIncidentsList { Tags = ($IncidentObj.tags -join ', ') Comments = @($IncidentObj.comments) } - } + } } } } catch { @@ -79,6 +81,6 @@ Function Invoke-ExecIncidentsList { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode Body = $Body - }) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsListAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsListAllTenants.ps1 index 25e24aa519ec..73421bb577fd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsListAllTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsListAllTenants.ps1 @@ -3,13 +3,15 @@ using namespace System.Net Function Invoke-ExecIncidentsListAllTenants { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Security.Incident.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - - Get-Tenants | ForEach-Object -Parallel { + + Get-Tenants | ForEach-Object -Parallel { $domainName = $_.defaultDomainName Import-Module '.\Modules\AzBobbyTables' Import-Module '.\Modules\CIPPCore' @@ -17,7 +19,7 @@ Function Invoke-ExecIncidentsListAllTenants { try { $incidents = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/incidents' -tenantid $domainName -AsApp $true - $GraphRequest = foreach ($incident in $incidents) { + $GraphRequest = foreach ($incident in $incidents) { $GUID = (New-Guid).Guid $GraphRequest = @{ Incident = [string]($incident | ConvertTo-Json -Depth 10) @@ -26,7 +28,7 @@ Function Invoke-ExecIncidentsListAllTenants { Tenant = [string]$domainName } Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } + } } catch { $GUID = (New-Guid).Guid @@ -43,7 +45,7 @@ Function Invoke-ExecIncidentsListAllTenants { severity = 'CIPP' } $GraphRequest = @{ - Incident = [string]$AlertText + Incident = [string]$AlertText RowKey = [string]$GUID PartitionKey = 'Incident' Tenant = [string]$domainName diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityAlert.ps1 index 1a13261e7c03..da3bc31ab858 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityAlert.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSetSecurityAlert { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Security.Alert.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -16,7 +18,7 @@ Function Invoke-ExecSetSecurityAlert { $AlertFilter = $Request.Query.GUID $Status = $Request.Query.Status $AssignBody = '{"status":"' + $Status + '","vendorInformation":{"provider":"' + $Request.query.provider + '","vendor":"' + $Request.query.vendor + '"}}' - try { + try { $GraphRequest = New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/alerts/$AlertFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Set alert $AlertFilter to status $Status" -Sev 'Info' $body = [pscustomobject]@{'Results' = "Set status for alert to $Status" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityIncident.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityIncident.ps1 index 64b2ad0b6bcf..b1065f721a29 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityIncident.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecSetSecurityIncident.ps1 @@ -1,79 +1,81 @@ using namespace System.Net Function Invoke-ExecSetSecurityIncident { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Security.Incident.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $first = '' - # Interact with query parameters or the body of the request. - $tenantfilter = $Request.Query.TenantFilter - $IncidentFilter = $Request.Query.GUID - $Status = $Request.Query.Status - $Assigned = $Request.Query.Assigned - $Classification = $Request.Query.Classification - $Determination = $Request.Query.Determination - $Redirected = $Request.Query.Redirected -as [int] - $BodyBuild - $AssignBody = '{' + $first = '' + # Interact with query parameters or the body of the request. + $tenantfilter = $Request.Query.TenantFilter + $IncidentFilter = $Request.Query.GUID + $Status = $Request.Query.Status + $Assigned = $Request.Query.Assigned + $Classification = $Request.Query.Classification + $Determination = $Request.Query.Determination + $Redirected = $Request.Query.Redirected -as [int] + $BodyBuild + $AssignBody = '{' - try { - # We won't update redirected incidents because the incident it is redirected to should instead be updated - if ($Redirected -lt 1) { - # Set received status - if ($null -ne $Status) { - $AssignBody += $first + '"status":"' + $Status + '"' - $BodyBuild += $first + 'Set status for incident to ' + $Status - $first = ', ' - } + try { + # We won't update redirected incidents because the incident it is redirected to should instead be updated + if ($Redirected -lt 1) { + # Set received status + if ($null -ne $Status) { + $AssignBody += $first + '"status":"' + $Status + '"' + $BodyBuild += $first + 'Set status for incident to ' + $Status + $first = ', ' + } - # Set received classification and determination - if ($null -ne $Classification) { - if ($null -eq $Determination) { - # Maybe some poindexter tries to send a classification without a determination - throw - } + # Set received classification and determination + if ($null -ne $Classification) { + if ($null -eq $Determination) { + # Maybe some poindexter tries to send a classification without a determination + throw + } - $AssignBody += $first + '"classification":"' + $Classification + '", "determination":"' + $Determination + '"' - $BodyBuild += $first + 'Set classification & determination for incident to ' + $Classification + ' ' + $Determination - $first = ', ' - } + $AssignBody += $first + '"classification":"' + $Classification + '", "determination":"' + $Determination + '"' + $BodyBuild += $first + 'Set classification & determination for incident to ' + $Classification + ' ' + $Determination + $first = ', ' + } - # Set received asignee - if ($null -ne $Assigned) { - $AssignBody += $first + '"assignedTo":"' + $Assigned + '"' - if ($null -eq $Status) { - $BodyBuild += $first + 'Set assigned for incident to ' + $Assigned - } - $first = ', ' - } + # Set received asignee + if ($null -ne $Assigned) { + $AssignBody += $first + '"assignedTo":"' + $Assigned + '"' + if ($null -eq $Status) { + $BodyBuild += $first + 'Set assigned for incident to ' + $Assigned + } + $first = ', ' + } - $AssignBody += '}' + $AssignBody += '}' - $ResponseBody = [pscustomobject]@{'Results' = $BodyBuild } - New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/incidents/$IncidentFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody -asApp $true - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Update incident $IncidentFilter with values $Assignbody" -Sev 'Info' - } else { - $ResponseBody = [pscustomobject]@{'Results' = 'Cannot update redirected incident' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Refuse to pdate incident $IncidentFilter with values $Assignbody because it is redirected to another incident" -Sev 'Info' - } + $ResponseBody = [pscustomobject]@{'Results' = $BodyBuild } + New-Graphpostrequest -uri "https://graph.microsoft.com/beta/security/incidents/$IncidentFilter" -type PATCH -tenantid $TenantFilter -body $Assignbody -asApp $true + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Update incident $IncidentFilter with values $Assignbody" -Sev 'Info' + } else { + $ResponseBody = [pscustomobject]@{'Results' = 'Cannot update redirected incident' } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Refuse to pdate incident $IncidentFilter with values $Assignbody because it is redirected to another incident" -Sev 'Info' + } - $body = $ResponseBody - } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to update alert $($AlertFilter): $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to update incident: $($_.Exception.Message)" } - } + $body = $ResponseBody + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Failed to update alert $($AlertFilter): $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Failed to update incident: $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 index 34b9bda58208..ea3412dd22b4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddTeam { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Teams.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,7 +20,7 @@ Function Invoke-AddTeam { $Owners = ($userobj.owner).Split([Environment]::NewLine) | Where-Object { $_ -ne $null -or $_ -ne '' } try { - + $Owners = $Owners | ForEach-Object { $OwnerID = "https://graph.microsoft.com/beta/users('" + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$_" -tenantid $Userobj.tenantid).id + "')" @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 index 0a031a0af5d3..c52f4c1b1409 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSetSharePointMember { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Sharepoint.Site.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 398f070db9ee..542dfb665b9f 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,26 +1,28 @@ using namespace System.Net Function Invoke-ExecSharePointOwner { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Sharepoint.Site.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $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 - $Results = [pscustomobject]@{'Results' = "$State" } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } + $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 + $Results = [pscustomobject]@{'Results' = "$State" } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSharepointSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSharepointSettings.ps1 index e769c7ee9879..2b04807cd4e1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSharepointSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSharepointSettings.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSharepointSettings { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Sharepoint.Admin.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -21,7 +23,7 @@ Function Invoke-ListSharepointSettings { $USERToGet = $Request.query.usertoGet $body = '{"isResharingByExternalUsersEnabled": "False"}' $Request = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -Type patch -Body $body -ContentType 'application/json' - + Write-LogMessage -API 'Standards' -tenant $tenantFilter -message 'Disabled Password Expiration' -sev Info # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 index 48f3f8badb80..7b5ac0cd37b7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSites { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Sharepoint.Site.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -20,7 +22,7 @@ Function Invoke-ListSites { $type = $request.query.Type $UserUPN = $request.query.UserUPN try { - $Result = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv + $Result = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv if ($UserUPN) { $ParsedRequest = $Result | Where-Object { $_.'Owner Principal Name' -eq $UserUPN } @@ -37,7 +39,7 @@ Function Invoke-ListSites { @{ Name = 'Template'; Expression = { $_.'Root Web Template' } }, @{ Name = 'siteid'; Expression = { $_.'site Id' } } - #Temporary workaround for url as report is broken. + #Temporary workaround for url as report is broken. #This API is so stupid its great. $URLs = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/sites/getAllSites?$select=SharePointIds' -asapp $true -tenantid $TenantFilter).SharePointIds diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeams.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeams.ps1 index c5969ad1d8ae..743568fe8bed 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeams.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeams.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTeams { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Teams.Group.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -37,7 +39,7 @@ Function Invoke-ListTeams { Members = @($Members) Owners = @($owners) InstalledApps = @($AppsList) - } + } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsActivity.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsActivity.ps1 index 944fb90c7bf7..426131cc047d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsActivity.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsActivity.ps1 @@ -3,12 +3,14 @@ using namespace System.Net Function Invoke-ListTeamsActivity { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Teams.Activity.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - + # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 index ef5e1ca9d3d2..ec33ee67e86e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTeamsVoice { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Teams.Voice.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -24,11 +26,11 @@ Function Invoke-ListTeamsVoice { $CompleteRequest = $_ | Select-Object *, 'AssignedTo' $CompleteRequest.AcquisitionDate = $CompleteRequest.AcquisitionDate -split 'T' | Select-Object -First 1 - if ($CompleteRequest.TargetId -eq '00000000-0000-0000-0000-000000000000') { + if ($CompleteRequest.TargetId -eq '00000000-0000-0000-0000-000000000000') { $CompleteRequest.AssignedTo = 'Unassigned' } else { $CompleteRequest.AssignedTo = ($users | Where-Object -Property Id -EQ $CompleteRequest.TargetId).userPrincipalName - + } $CompleteRequest } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 index ab279d752d81..2cbba9b5fa42 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddAlert { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 index 4cbcff576e97..8c884978d21f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAlertsQueue { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -15,7 +17,7 @@ Function Invoke-ListAlertsQueue { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' $WebhookTable = Get-CIPPTable -TableName 'WebhookRules' - $WebhookRules = Get-CIPPAzDataTableEntity @WebhookTable + $WebhookRules = Get-CIPPAzDataTableEntity @WebhookTable $ScheduledTasks = Get-CIPPTable -TableName 'ScheduledTasks' $ScheduledTasks = Get-CIPPAzDataTableEntity @ScheduledTasks | Where-Object { $_.hidden -eq $true } @@ -29,7 +31,7 @@ Function Invoke-ListAlertsQueue { $TaskEntry = [PSCustomObject]@{ Tenants = ($Task.Tenants | ConvertFrom-Json -ErrorAction SilentlyContinue).fullValue.defaultDomainName -join ',' Conditions = $TranslatedConditions - Actions = $TranslatedActions + Actions = $TranslatedActions LogType = $Task.type EventType = 'Audit log Alert' RowKey = $Task.RowKey @@ -37,7 +39,7 @@ Function Invoke-ListAlertsQueue { RepeatsEvery = 'When received' } $AllTasksArrayList.Add($TaskEntry) - } + } foreach ($Task in $ScheduledTasks) { $TaskEntry = [PSCustomObject]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListWebhookAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListWebhookAlert.ps1 index d585504f4254..1741ed98fcaf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListWebhookAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListWebhookAlert.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListWebhookAlert { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 a65084e28bdc..d4633158b895 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 @@ -79,7 +79,7 @@ function Invoke-PublicWebhooks { Conditions = $_.Conditions Actions = $_.Actions LogType = $_.Type - } + } } if (!$Configuration.Tenants) { Write-Host 'No tenants found for this webhook, probably an old entry. Skipping.' @@ -99,22 +99,22 @@ function Invoke-PublicWebhooks { $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 } + $Data.ExtendedProperties | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } } - if ($Data.DeviceProperties) { + if ($Data.DeviceProperties) { $Data.CIPPDeviceProperties = ($Data.DeviceProperties | ConvertTo-Json) - $Data.DeviceProperties | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } + $Data.DeviceProperties | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } } - if ($Data.parameters) { + if ($Data.parameters) { $Data.CIPPParameters = ($Data.parameters | ConvertTo-Json) - $Data.parameters | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } + $Data.parameters | ForEach-Object { $data | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force -ErrorAction SilentlyContinue } } - if ($Data.ModifiedProperties) { + if ($Data.ModifiedProperties) { $Data.CIPPModifiedProperties = ($Data.ModifiedProperties | ConvertTo-Json) - $Data.ModifiedProperties | ForEach-Object { $data | Add-Member -NotePropertyName "$($_.Name)" -NotePropertyValue "$($_.NewValue)" -Force -ErrorAction SilentlyContinue } + $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 @@ -150,7 +150,7 @@ function Invoke-PublicWebhooks { $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 @@ -165,12 +165,12 @@ function Invoke-PublicWebhooks { #Filter data based on conditions. $Where = $Configuration | ForEach-Object { $conditions = $_.Conditions | ConvertFrom-Json | Where-Object { $_.Input.value -ne '' } - $actions = $_.Actions + $actions = $_.Actions $conditionStrings = foreach ($condition in $conditions) { - $value = if ($condition.Input.value -is [array]) { + $value = if ($condition.Input.value -is [array]) { $arrayAsString = $condition.Input.value | ForEach-Object { - "'$_'" - } + "'$_'" + } "@($($arrayAsString -join ', '))" } else { "'$($condition.Input.value)'" } "`$(`$_.$($condition.Property.label)) -$($condition.Operator.value) $value" @@ -184,9 +184,9 @@ function Invoke-PublicWebhooks { clause = $finalCondition expectedAction = $actions } - + } - Write-Host "Webhook: The list of operations in the data are $($ProcessedData.operation -join ', ')" + 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)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 index 7552c2afe222..3a52f5dacdfd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveQueuedAlert { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -24,7 +26,7 @@ Function Invoke-RemoveQueuedAlert { $Alert = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity @Table -Entity $Alert Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' - + $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to remove from queue $ID. $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 index ef76692431bb..08124ad41683 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 @@ -4,6 +4,8 @@ function Invoke-ExecAddMultiTenantApp { <# .FUNCTIONALITY Entrypoint + .ROLE + Tenant.Application.ReadWrite #> param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApproval.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApproval.ps1 index 561d060eb99b..b79ef41afb72 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApproval.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAppApproval.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecAppApproval { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Application.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -16,7 +18,7 @@ Function Invoke-ExecAppApproval { Write-Host "$($Request.query.ID)" # Interact with query parameters or the body of the request. - $applicationid = if ($request.query.applicationid) { $request.query.applicationid } else { $env:ApplicationID } + $applicationid = if ($request.query.applicationid) { $request.query.applicationid } else { $env:ApplicationID } $Results = get-tenants | ForEach-Object { [PSCustomObject]@{ defaultDomainName = $_.defaultDomainName diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecAddSPN.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecAddSPN.ps1 index de779bfe083d..b52867e7f0da 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecAddSPN.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecAddSPN.ps1 @@ -1,29 +1,31 @@ using namespace System.Net Function Invoke-ExecAddSPN { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Administration.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Interact with query parameters or the body of the request. - $Body = if ($Request.Query.Enable) { '{"accountEnabled":"true"}' } else { '{"accountEnabled":"false"}' } - try { - $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -tenantid $ENV:TenantID -type POST -Body "{ `"appId`": `"2832473f-ec63-45fb-976f-5d45a7d4bb91`" }" -NoAuthCheck $true - $Results = [pscustomobject]@{'Results' = "Successfully completed request. Add your GDAP migration permissions to your SAM application here: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/CallAnAPI/appId/$($ENV:ApplicationID)/isMSAApp/ " } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed to add SPN. Please manually execute 'New-AzureADServicePrincipal -AppId 2832473f-ec63-45fb-976f-5d45a7d4bb91' The error was $($_.Exception.Message)" } - } + # Interact with query parameters or the body of the request. + $Body = if ($Request.Query.Enable) { '{"accountEnabled":"true"}' } else { '{"accountEnabled":"false"}' } + try { + $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -tenantid $ENV:TenantID -type POST -Body "{ `"appId`": `"2832473f-ec63-45fb-976f-5d45a7d4bb91`" }" -NoAuthCheck $true + $Results = [pscustomobject]@{'Results' = "Successfully completed request. Add your GDAP migration permissions to your SAM application here: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/CallAnAPI/appId/$($ENV:ApplicationID)/isMSAApp/ " } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to add SPN. Please manually execute 'New-AzureADServicePrincipal -AppId 2832473f-ec63-45fb-976f-5d45a7d4bb91' The error was $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 index 7b02b9aa1f74..adcb580e45cf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecOffboardTenant { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Administration.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -23,7 +25,7 @@ Function Invoke-ExecOffboardTenant { try { try { $domains = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/domains?`$select=id" -tenantid $env:TenantID -NoAuthCheck:$true).id - $CSPGuestUsers = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/users?`$select=id,mail&`$filter=userType eq 'Guest' and $(($domains | ForEach-Object { "endswith(mail, '$_')" }) -join ' or ')&`$count=true" -tenantid $Tenantfilter -ComplexFilter) + $CSPGuestUsers = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/users?`$select=id,mail&`$filter=userType eq 'Guest' and $(($domains | ForEach-Object { "endswith(mail, '$_')" }) -join ' or ')&`$count=true" -tenantid $Tenantfilter -ComplexFilter) } catch { $errors.Add("Failed to retrieve guest users: $($_.Exception.message)") } @@ -57,28 +59,28 @@ Function Invoke-ExecOffboardTenant { } catch { throw "Failed to retrieve CSP domains: $($_.Exception.message)" } - + try { # Get /organization data $orgContacts = New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/organization?`$select=id,marketingNotificationEmails,securityComplianceNotificationMails,technicalNotificationMails" -tenantid $TenantFilter - + } catch { throw "Failed to retrieve CSP domains: $($_.Exception.message)" } } catch { $errors.Add("$($_.Exception.message)") } - + # foreach through the properties we want to check/update @('marketingNotificationEmails','securityComplianceNotificationMails','technicalNotificationMails') | ForEach-Object { $property = $_ $propertyContacts = $orgContacts.($($property)) - + if ($propertyContacts -AND ($domains -notcontains ($propertyContacts | ForEach-Object { $_.Split("@")[1] }))) { $newPropertyContent = [System.Collections.Generic.List[object]]($propertyContacts | Where-Object { $domains -notcontains $_.Split("@")[1] }) - + $patchContactBody = if (!($newPropertyContent)) { "{ `"$($property)`" : [] }" } else { [pscustomobject]@{ $property = $newPropertyContent } | ConvertTo-Json } - + try { New-GraphPostRequest -type PATCH -body $patchContactBody -Uri "https://graph.microsoft.com/v1.0/organization/$($orgContacts.id)" -tenantid $Tenantfilter -ContentType "application/json" $results.Add("Succesfully removed notification contacts from $($property): $(($propertyContacts | Where-Object { $domains -contains $_.Split("@")[1] }))") @@ -91,9 +93,9 @@ Function Invoke-ExecOffboardTenant { } } # Add logic for privacyProfile later - rvdwegen - + } - + if ($request.body.RemoveVendorApps) { $request.body.RemoveVendorApps | ForEach-Object { try { @@ -104,7 +106,7 @@ Function Invoke-ExecOffboardTenant { #$results.Add("Failed to removed app $($_.displayName)") $errors.Add("Failed to removed app $($_.label)") } - } + } } # All customer tenant specific actions ALWAYS have to be completed before this action! diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 index 84492fe68a70..10c11f90575a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 @@ -4,6 +4,8 @@ function Invoke-ExecOnboardTenant { <# .FUNCTIONALITY Entrypoint + .ROLE + Tenant.Administration.ReadWrite #> param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListAppConsentRequests.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListAppConsentRequests.ps1 index 9cfc10853e23..7e8a8603896d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListAppConsentRequests.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListAppConsentRequests.ps1 @@ -3,14 +3,16 @@ using namespace System.Net function Invoke-ListAppConsentRequests { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Administration.Read #> param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName $TenantFilter = $Request.Query.TenantFilter Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - + try { if ($Request.Query.TenantFilter -eq 'AllTenants') { throw 'AllTenants is not yet supported' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 index c3fbd33947af..f8821c051a8a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 @@ -1,4 +1,10 @@ function Invoke-ListTenantOnboarding { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Administration.Read + #> Param( $Request, $TriggerMetadata diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-UpdateSecureScore.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-UpdateSecureScore.ps1 index b1ffb9bee098..26bc7332a928 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-UpdateSecureScore.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-UpdateSecureScore.ps1 @@ -1,33 +1,35 @@ using namespace System.Net Function Invoke-ExecUpdateSecureScore { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Administration.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Interact with query parameters or the body of the request. - $Body = @{ - comment = $request.body.reason - state = $request.body.resolutionType - vendorInformation = $request.body.vendorInformation - } - try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/security/secureScoreControlProfiles/$($Request.body.ControlName)" -tenantid $Request.body.TenantFilter -type PATCH -Body $($Body | ConvertTo-Json -Compress) - $Results = [pscustomobject]@{'Results' = "Succesfully set control to $($body.state) " } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed to set Control to $($body.state) $($_.Exception.Message)" } - } + # Interact with query parameters or the body of the request. + $Body = @{ + comment = $request.body.reason + state = $request.body.resolutionType + vendorInformation = $request.body.vendorInformation + } + try { + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/security/secureScoreControlProfiles/$($Request.body.ControlName)" -tenantid $Request.body.TenantFilter -type PATCH -Body $($Body | ConvertTo-Json -Compress) + $Results = [pscustomobject]@{'Results' = "Succesfully set control to $($body.state) " } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed to set Control to $($body.state) $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 index 77db47a5ff51..fe98eae2eee1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditTenant { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -30,11 +32,11 @@ Function Invoke-EditTenant { if ($tenantObjectId) { try { $bodyToPatch = '{"displayName":"' + $tenantDisplayName + '","defaultDomainName":"' + $tenantDefaultDomainName + '"}' - $patchTenant = (Invoke-RestMethod -Method PATCH -Uri "https://graph.windows.net/myorganization/contracts/$($tenantObjectId.objectId)?api-version=1.6" -Body $bodyToPatch -ContentType 'application/json' -Headers $AADGraphtoken -ErrorAction Stop) + $patchTenant = (Invoke-RestMethod -Method PATCH -Uri "https://graph.windows.net/myorganization/contracts/$($tenantObjectId.objectId)?api-version=1.6" -Body $bodyToPatch -ContentType 'application/json' -Headers $AADGraphtoken -ErrorAction Stop) $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $tenantDefaultDomainName try { $TenantsTable = Get-CippTable -tablename Tenants - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter + $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter $Tenant.displayName = $tenantDisplayName Update-AzDataTableEntity @TenantsTable -Entity $Tenant } @@ -44,7 +46,7 @@ Function Invoke-EditTenant { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Edited tenant $tenantDisplayName" -Sev 'Info' $results = "Successfully amended details for $($Tenant.displayName) $AddedText" } - catch { + catch { $results = "Failed to amend details for $tenantDisplayName : $($_.Exception.Message)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Failed amending details $tenantDisplayName. Error:$($_.Exception.Message)" -Sev 'Error' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 index 9aa191e2e44f..001c8ac2cbcd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTenantDetails { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -44,6 +46,6 @@ Function Invoke-ListTenantDetails { StatusCode = [HttpStatusCode]::OK Body = $Body }) - + } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 index 3c183a98af86..3ecb43be0920 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTenants { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 index 547828a337f4..7ced88078c10 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddCAPolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 index b6de2ac40ed3..b0f64582c5c4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddCATemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -12,14 +14,14 @@ Function Invoke-AddCATemplate { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.Query.TenantFilter - try { + try { $GUID = (New-Guid).GUID $JSON = if ($request.body.rawjson) { ConvertFrom-Json -InputObject ([pscustomobject]$request.body.rawjson) } else { ([pscustomobject]$Request.body) | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties + $_ | Select-Object -Property $NonEmptyProperties } } @@ -85,7 +87,7 @@ Function Invoke-AddCATemplate { } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created CA Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' $body = [pscustomobject]@{'Results' = 'Successfully added template' } - + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create CA Template: $($_.Exception.Message)" -Sev 'Error' $body = [pscustomobject]@{'Results' = "Intune Template Deployment failed: $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 index 578b196ed014..47dd98aa75dd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddNamedLocation { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-EditCAPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-EditCAPolicy.ps1 index fb804f8fbfe1..e3baf6e4a607 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-EditCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-EditCAPolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-EditCAPolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 index 137c55a9c28b..9bdd61686269 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCACheck.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecCaCheck { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -42,7 +44,7 @@ Function Invoke-ExecCaCheck { $JSONBody = $ConditionalAccessWhatIfDefinition | ConvertTo-Json -Depth 10 Write-Host $JSONBody $Request = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/evaluate' -tenantid $tenant -type POST -body $JsonBody -AsApp $true - $Request + $Request } catch { "Failed to execute check: $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCAExclusion.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCAExclusion.ps1 index 4dafed5af25a..86d06bf95796 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCAExclusion.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCAExclusion.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecCAExclusion { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -46,6 +48,6 @@ Function Invoke-ExecCAExclusion { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body - }) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 index 14ec616c0616..7f4be467dd3a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListCAtemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -29,11 +31,11 @@ Function Invoke-ListCAtemplates { #List new policies $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'CATemplate'" + $Filter = "PartitionKey eq 'CATemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { $data = $_.JSON | ConvertFrom-Json -Depth 100 $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force - $data + $data } | Sort-Object -Property displayName if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property GUID -EQ $Request.query.id } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 index c093a8c4f009..337fc9c46ace 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 @@ -1,458 +1,455 @@ - using namespace System.Net +using namespace System.Net - Function Invoke-ListConditionalAccessPolicies { +Function Invoke-ListConditionalAccessPolicies { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName -Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug" + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' -function Get-LocationNameFromId { - [CmdletBinding()] - param ( - [Parameter()] - $ID, - - [Parameter(Mandatory = $true)] - $Locations - ) - if ($id -eq 'All') { - return 'All' - } - $DisplayName = $Locations | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName - if ([string]::IsNullOrEmpty($displayName)) { - return $ID - } - else { - return $DisplayName - } -} - -function Get-RoleNameFromId { - [CmdletBinding()] - param ( - [Parameter()] - $ID, - - [Parameter(Mandatory = $true)] - $RoleDefinitions - ) - if ($id -eq 'All') { - return 'All' - } - $DisplayName = $RoleDefinitions | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName - if ([string]::IsNullOrEmpty($displayName)) { - return $ID - } - else { - return $DisplayName - } -} + function Get-LocationNameFromId { + [CmdletBinding()] + param ( + [Parameter()] + $ID, -function Get-UserNameFromId { - [CmdletBinding()] - param ( - [Parameter()] - $ID, - - [Parameter(Mandatory = $true)] - $Users - ) - if ($id -eq 'All') { - return 'All' - } - $DisplayName = $Users | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName - if ([string]::IsNullOrEmpty($displayName)) { - return $ID - } - else { - return $DisplayName + [Parameter(Mandatory = $true)] + $Locations + ) + if ($id -eq 'All') { + return 'All' + } + $DisplayName = $Locations | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName + if ([string]::IsNullOrEmpty($displayName)) { + return $ID + } else { + return $DisplayName + } } -} -function Get-GroupNameFromId { - param ( - [Parameter()] - $ID, + function Get-RoleNameFromId { + [CmdletBinding()] + param ( + [Parameter()] + $ID, - [Parameter(Mandatory = $true)] - $Groups - ) - if ($id -eq 'All') { - return 'All' - } - $DisplayName = $Groups | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName - if ([string]::IsNullOrEmpty($displayName)) { - return "No Data" - } - else { - return $DisplayName + [Parameter(Mandatory = $true)] + $RoleDefinitions + ) + if ($id -eq 'All') { + return 'All' + } + $DisplayName = $RoleDefinitions | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName + if ([string]::IsNullOrEmpty($displayName)) { + return $ID + } else { + return $DisplayName + } } -} -function Get-ApplicationNameFromId { - [CmdletBinding()] - param ( - [Parameter()] - $ID, - - [Parameter(Mandatory = $true)] - $Applications - ) - if ($id -eq 'All') { - return 'All' - } - switch ($id) { - 00000004-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.Lync' } - 00000006-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.Office365Portal' } - 00000003-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.SharePoint ' } - 00000005-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.Workflow' } - 00000009-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.AnalysisServices' } - 00000002-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.Exchange' } - 00000007-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.ExchangeOnlineProtection' } - 00000002-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.ActiveDirectory' } - 8fca0a66-c008-4564-a876-ab3ae0fd5cff { $return = 'Microsoft.SMIT' } - 0000000b-0000-0000-c000-000000000000 { $return = 'Microsoft.SellerDashboard' } - 0000000f-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.GraphExplorer' } - 0000000c-0000-0000-c000-000000000000 { $return = 'Microsoft App Access Panel' } - 00000013-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.Portal' } - 00000010-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.GraphStore' } - 93ee9413-cf4c-4d4e-814b-a91ff20a01bd { $return = 'Workflow' } - aa9ecb1e-fd53-4aaa-a8fe-7a54de2c1334 { $return = 'Microsoft.Office365.Configure' } - 797f4846-ba00-4fd7-ba43-dac1f8f63013 { $return = 'Windows Azure Service Management API' } - 00000005-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.YammerEnterprise' } - 601d4e27-7bb3-4dee-8199-90d47d527e1c { $return = 'Microsoft.Office365.ChangeManagement' } - 6f82282e-0070-4e78-bc23-e6320c5fa7de { $return = 'Microsoft.DiscoveryService' } - 0f698dd4-f011-4d23-a33e-b36416dcb1e6 { $return = 'Microsoft.OfficeClientService' } - 67e3df25-268a-4324-a550-0de1c7f97287 { $return = 'Microsoft.OfficeWebAppsService' } - ab27a73e-a3ba-4e43-8360-8bcc717114d8 { $return = 'Microsoft.OfficeModernCalendar' } - aedca418-a84d-430d-ab84-0b1ef06f318f { $return = 'Workflow' } - 595d87a1-277b-4c0a-aa7f-44f8a068eafc { $return = 'Microsoft.SupportTicketSubmission' } - e3583ad2-c781-4224-9b91-ad15a8179ba0 { $return = 'Microsoft.ExtensibleRealUserMonitoring' } - b645896d-566e-447e-8f7f-e2e663b5d182 { $return = 'OpsDashSharePointApp' } - 48229a4a-9f1d-413a-8b96-4c02462c0360 { $return = 'OpsDashSharePointApp' } - 48717084-a59c-4306-9dc4-3f618dbecdf9 { $return = '"Napa" Office 365 Development Tools' } - c859ff33-eb41-4ba6-8093-a2c5153bbd7c { $return = 'Workflow' } - 67cad61c-3411-48d7-ab73-561c64f11ed6 { $return = 'Workflow' } - 914ed757-9257-4200-b68e-a2bed2f12c5a { $return = 'RbacBackfill' } - 499b84ac-1321-427f-aa17-267ca6975798 { $return = 'Microsoft.VisualStudio.Online' } - b2590339-0887-4e94-93aa-13357eb510d7 { $return = 'Workflow' } - 0000001b-0000-0000-c000-000000000000 { $return = 'Microsoft Power BI Information Service' } - 89f80565-bfac-4c01-9535-9f0eba332ffe { $return = 'Power BI' } - 433895fb-4ec7-45c3-a53c-c44d10f80d5b { $return = 'Compromised Account Service' } - d7c17728-4f1e-4a1e-86cf-7e0adf3fe903 { $return = 'Workflow' } - 17ef6d31-381f-4783-b186-7b440a3c85c1 { $return = 'Workflow' } - 00000012-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.RMS' } - 81ce94d4-9422-4c0d-a4b9-3250659366ce { $return = 'Workflow' } - 8d3a7d3c-c034-4f19-a2ef-8412952a9671 { $return = 'MicrosoftOffice' } - 0469d4cd-df37-4d93-8a61-f8c75b809164 { $return = 'Microsoft Policy Administration Service' } - 31d3f3f5-7267-45a8-9549-affb00110054 { $return = 'Windows Azure RemoteApp Service' } - 4e004241-32db-46c2-a86f-aaaba29bea9c { $return = 'Workflow' } - 748d098e-7a3b-436d-8b0a-006a58b29647 { $return = 'Workflow' } - dbf08535-1d3b-4f89-bf54-1d48dd613a61 { $return = 'Workflow' } - ed9fe1ef-25a4-482f-9981-2b60f91e2448 { $return = 'Workflow' } - 8ad28d50-ee26-42fc-8a29-e41ea38461f2 { $return = 'Office365RESTAPIExplorer.Office365App' } - 38285dce-a13d-4107-9b04-3016b941bb3a { $return = 'BasicDataOperationsREST' } - 92bb96c8-321c-47f9-bcc5-8849490c2b07 { $return = 'BasicSelfHostedAppREST' } - 488a57a0-00e2-4817-8c8d-cf8a15a994d2 { $return = 'WindowsFormsApplication2.Office365App' } - 11c174dc-1945-4a9a-a36b-c79a0f246b9b { $return = 'AzureApplicationInsights' } - e6acb561-0d94-4287-bd3a-3169f421b112 { $return = 'Tutum' } - 7b77b3a2-8490-49e1-8842-207cd0899af9 { $return = 'Nearpod' } - 0000000a-0000-0000-c000-000000000000 { $return = 'Microsoft.Intune' } - 93625bc8-bfe2-437a-97e0-3d0060024faa { $return = 'SelfServicePasswordReset' } - dee7ba80-6a55-4f3b-a86c-746a9231ae49 { $return = 'MicrosoftAppPlatEMA' } - 803ee9ca-3f7f-4824-bd6e-0b99d720c35c { $return = 'Azure Media Service' } - 2d4d3d8e-2be3-4bef-9f87-7875a61c29de { $return = 'OneNote' } - 8d40666e-5abf-45f6-a5e7-b7192d6d56ed { $return = 'Workflow' } - 262044b1-e2ce-469f-a196-69ab7ada62d3 { $return = 'Backup Management Service' } - 087a2c70-c89e-463f-8dd3-e3959eabb1a9 { $return = 'Microsoft Profile Service Platform Service' } - 7cd684f4-8a78-49b0-91ec-6a35d38739ba { $return = 'Azure Logic Apps' } - c5393580-f805-4401-95e8-94b7a6ef2fc2 { $return = 'Office 365 Management APIs' } - 96231a05-34ce-4eb4-aa6a-70759cbb5e83 { $return = 'MicrosoftAzureRedisCache' } - b8340c3b-9267-498f-b21a-15d5547fd85e { $return = 'Hyper-V Recovery Manager' } - abfa0a7c-a6b6-4736-8310-5855508787cd { $return = 'Microsoft.Azure.WebSites' } - c44b4083-3bb0-49c1-b47d-974e53cbdf3c { $return = 'IbizaPortal' } - 905fcf26-4eb7-48a0-9ff0-8dcc7194b5ba { $return = 'Sway' } - b10686fd-6ba8-49f2-a3cd-67e4d2f52ac8 { $return = 'NovoEd' } - c606301c-f764-4e6b-aa45-7caaaea93c9a { $return = 'OfficeStore' } - 569e8598-685b-4ba2-8bff-5bced483ac46 { $return = 'Evercontact' } - 20a23a2f-8c32-4de7-8063-8c8f909602c0 { $return = 'Workflow' } - aaf214cc-8013-4b95-975f-13203ae36039 { $return = 'Power BI Tiles' } - d88a361a-d488-4271-a13f-a83df7dd99c2 { $return = 'IDML Graph Resolver Service and CAD' } - dff9b531-6290-4620-afce-26826a62a4e7 { $return = 'DocuSign' } - 01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9 { $return = 'Device Registration Service' } - 3290e3f7-d3ac-4165-bcef-cf4874fc4270 { $return = 'Smartsheet' } - a4ee6867-8640-4495-b1fd-8b26037a5bd3 { $return = 'Workflow' } - aa0e3dd4-df02-478d-869e-fc61dd71b6e8 { $return = 'Workflow' } - 0f6edad5-48f2-4585-a609-d252b1c52770 { $return = 'AIGraphClient' } - 0c8139b5-d545-4448-8d2b-2121bb242680 { $return = 'BillingExtension' } - 475226c6-020e-4fb2-8a90-7a972cbfc1d4 { $return = 'KratosAppsService' } - 39624784-6cbe-4a60-afbe-9f46d10fdb27 { $return = 'SkypeForBusinessRemotePowershell' } - 8bdebf23-c0fe-4187-a378-717ad86f6a53 { $return = 'ResourceHealthRP' } - c161e42e-d4df-4a3d-9b42-e7a3c31f59d4 { $return = 'MicrosoftIntuneAPI' } - 9cb77803-d937-493e-9a3b-4b49de3f5a74 { $return = 'MicrosoftIntuneServiceDiscovery' } - ddbf3205-c6bd-46ae-8127-60eb93363864 { $return = 'Microsoft Azure Batch' } - 80ccca67-54bd-44ab-8625-4b79c4dc7775 { $return = 'ComplianceCenter' } - 0a5f63c0-b750-4f38-a71c-4fc0d58b89e2 { $return = 'Microsoft Mobile Application Management' } - e1335bb1-2aec-4f92-8140-0e6e61ae77e5 { $return = 'CIWebService' } - 75018fbe-21fe-4a57-b63c-83252b5eaf16 { $return = 'TeamImprover - Team Organization Chart' } - a393296b-5695-4463-97cb-9fa8638a494a { $return = 'My SharePoint Sites' } - fe217466-5583-431c-9531-14ff7268b7b3 { $return = 'Microsoft Education' } - 5bfe8a29-054e-4348-9e7a-3981b26b125f { $return = 'Bing Places for Business' } - eaf8a961-f56e-47eb-9ffd-936e22a554ef { $return = 'DevilFish' } - 4b4b1d56-1f03-47d9-a0a3-87d4afc913c9 { $return = 'Wunderlist' } - 00000003-0000-0000-c000-000000000000 { $return = 'Microsoft Graph' } - 60e6cd67-9c8c-4951-9b3c-23c25a2169af { $return = 'Compute Resource Provider' } - 507bc9da-c4e2-40cb-96a7-ac90df92685c { $return = 'Office365Reports' } - 09abbdfd-ed23-44ee-a2d9-a627aa1c90f3 { $return = 'ProjectWorkManagement' } - 28ec9756-deaf-48b2-84d5-a623b99af263 { $return = 'Office Personal Assistant at Work Service' } - 9e4a5442-a5c9-4f6f-b03f-5b9fcaaf24b1 { $return = 'OfficeServicesManager' } - 3138fe80-4087-4b04-80a6-8866c738028a { $return = 'SharePoint Notification Service' } - d2a0a418-0aac-4541-82b2-b3142c89da77 { $return = 'MicrosoftAzureOperationalInsights' } - 2cf9eb86-36b5-49dc-86ae-9a63135dfa8c { $return = 'AzureTrafficManagerandDNS' } - 32613fc5-e7ac-4894-ac94-fbc39c9f3e4a { $return = 'OAuth Sandbox' } - 925eb0d0-da50-4604-a19f-bd8de9147958 { $return = 'Groupies Web Service' } - e4ab13ed-33cb-41b4-9140-6e264582cf85 { $return = 'Azure SQL Database Backup To Azure Backup Vault' } - ad230543-afbe-4bb4-ac4f-d94d101704f8 { $return = 'Apiary for Power BI' } - 11cd3e2e-fccb-42ad-ad00-878b93575e07 { $return = 'Automated Call Distribution' } - de17788e-c765-4d31-aba4-fb837cfff174 { $return = 'Skype for Business Management Reporting and Analytics' } - 65d91a3d-ab74-42e6-8a2f-0add61688c74 { $return = 'Microsoft Approval Management' } - 5225545c-3ebd-400f-b668-c8d78550d776 { $return = 'Office Agent Service' } - 1cda9b54-9852-4a5a-96d4-c2ab174f9edf { $return = 'O365Account' } - 4747d38e-36c5-4bc3-979b-b0ef74df54d1 { $return = 'PushChannel' } - b97b6bd4-a49f-4a0c-af18-af507d1da76c { $return = 'Office Shredding Service' } - d4ebce55-015a-49b5-a083-c84d1797ae8c { $return = 'Microsoft Intune Enrollment' } - 5b20c633-9a48-4a5f-95f6-dae91879051f { $return = 'Azure Information Protection' } - 441509e5-a165-4363-8ee7-bcf0b7d26739 { $return = 'EnterpriseAgentPlatform' } - e691bce4-6612-4025-b94c-81372a99f77e { $return = 'Boomerang' } - 8edd93e1-2103-40b4-bd70-6e34e586362d { $return = 'Windows Azure Security Resource Provider' } - 94c63fef-13a3-47bc-8074-75af8c65887a { $return = 'Office Delve' } - e95d8bee-4725-4f59-910d-94d415da51b9 { $return = 'Skype for Business Name Dictionary Service' } - e3c5dbcd-bb5f-4bda-b943-adc7a5bbc65e { $return = 'Workflow' } - 8602e328-9b72-4f2d-a4ae-1387d013a2b3 { $return = 'Azure API Management' } - 8b3391f4-af01-4ee8-b4ea-9871b2499735 { $return = 'O365 Secure Score' } - c26550d6-bc82-4484-82ca-ac1c75308ca3 { $return = 'Office 365 YammerOnOls' } - 33be1cef-03fb-444b-8fd3-08ca1b4d803f { $return = 'OneDrive Web' } - dcad865d-9257-4521-ad4d-bae3e137b345 { $return = 'Microsoft SharePoint Online - SharePoint Home' } - b2cc270f-563e-4d8a-af47-f00963a71dcd { $return = 'OneProfile Service' } - 4660504c-45b3-4674-a709-71951a6b0763 { $return = 'Microsoft Invitation Acceptance Portal' } - ba23cd2a-306c-48f2-9d62-d3ecd372dfe4 { $return = 'OfficeGraph' } - d52485ee-4609-4f6b-b3a3-68b6f841fa23 { $return = 'On-Premises Data Gateway Connector' } - 996def3d-b36c-4153-8607-a6fd3c01b89f { $return = 's 365 for Financials' } - b6b84568-6c01-4981-a80f-09da9a20bbed { $return = 'Microsoft Invoicing' } - 9d3e55ba-79e0-4b7c-af50-dc460b81dca1 { $return = 'Microsoft Azure Data Catalog' } - 4345a7b9-9a63-4910-a426-35363201d503 { $return = 'O365 Suite UX' } - ac815d4a-573b-4174-b38e-46490d19f894 { $return = 'Workflow' } - bb8f18b0-9c38-48c9-a847-e1ef3af0602d { $return = 'Microsoft.Azure.ActiveDirectoryIUX' } - cc15fd57-2c6c-4117-a88c-83b1d56b4bbe { $return = 'Microsoft Teams Services' } - 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 { $return = 'Skype Teams' } - 1fec8e78-bce4-4aaf-ab1b-5451cc387264 { $return = 'Microsoft Teams' } - 6d32b7f8-782e-43e0-ac47-aaad9f4eb839 { $return = 'Permission Service O365' } - cdccd920-384b-4a25-897d-75161a4b74c1 { $return = 'Skype Teams Firehose' } - 1c0ae35a-e2ec-4592-8e08-c40884656fa5 { $return = 'Skype Team Substrate connector' } - cf6c77f8-914f-4078-baef-e39a5181158b { $return = 'Skype Teams Settings Store' } - 64f79cb9-9c82-4199-b85b-77e35b7dcbcb { $return = 'Microsoft Teams Bots' } - b7912db9-aa33-4820-9d4f-709830fdd78f { $return = 'ConnectionsService' } - 82f77645-8a66-4745-bcdf-9706824f9ad0 { $return = 'PowerApps Runtime Service' } - 6204c1d1-4712-4c46-a7d9-3ed63d992682 { $return = 'Microsoft Flow Portal' } - 7df0a125-d3be-4c96-aa54-591f83ff541c { $return = 'Microsoft Flow Service' } - 331cc017-5973-4173-b270-f0042fddfd75 { $return = 'PowerAppsService' } - 0a0e9e37-25e3-47d4-964c-5b8237cad19a { $return = 'CloudSponge' } - df09ff61-2178-45d8-888c-4210c1c7b0b2 { $return = 'O365 UAP Processor' } - 8338dec2-e1b3-48f7-8438-20c30a534458 { $return = 'ViewPoint' } - 00000001-0000-0000-c000-000000000000 { $return = 'Azure ESTS Service' } - 394866fc-eedb-4f01-8536-3ff84b16be2a { $return = 'Microsoft People Cards Service' } - 0a0a29f9-0a25-49c7-94bf-c53c3f8fa69d { $return = 'Cortana Experience with O365' } - bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4 { $return = 'CPIM Service' } - 0004c632-673b-4105-9bb6-f3bbd2a927fe { $return = 'PowerApps and Flow' } - d3ce4cf8-6810-442d-b42e-375e14710095 { $return = 'Graph Explorer' } - 3aa5c166-136f-40eb-9066-33ac63099211 { $return = 'O365 Customer Monitoring' } - d6fdaa33-e821-4211-83d0-cf74736489e1 { $return = 'Microsoft Service Trust' } - ef4a2a24-4b4e-4abf-93ba-cc11c5bd442c { $return = 'Edmodo' } - b692184e-b47f-4706-b352-84b288d2d9ee { $return = 'Microsoft.MileIQ.RESTService' } - a25dbca8-4e60-48e5-80a2-0664fdb5c9b6 { $return = 'Microsoft.MileIQ' } - f7069a8d-9edc-4300-b365-ae53c9627fc4 { $return = 'Microsoft.MileIQ.Dashboard' } - 02e3ae74-c151-4bda-b8f0-55fbf341de08 { $return = 'Application Registration Portal' } - 1f5530b3-261a-47a9-b357-ded261e17918 { $return = 'Azure Multi-Factor Auth Connector' } - 981f26a1-7f43-403b-a875-f8b09b8cd720 { $return = 'Azure Multi-Factor Auth Client' } - 6ea8091b-151d-447a-9013-6845b83ba57b { $return = 'AD Hybrid Health' } - fc68d9e5-1f76-45ef-99aa-214805418498 { $return = 'Azure AD Identity Protection' } - 01fc33a7-78ba-4d2f-a4b7-768e336e890e { $return = 'MS-PIM' } - a6aa9161-5291-40bb-8c5c-923b567bee3b { $return = 'Storage Resource Provider' } - 4e9b8b9a-1001-4017-8dd1-6e8f25e19d13 { $return = 'Adobe Acrobat' } - 159b90bb-bb28-4568-ad7c-adad6b814a2f { $return = 'LastPass' } - b4bddae8-ab25-483e-8670-df09b9f1d0ea { $return = 'Signup' } - aa580612-c342-4ace-9055-8edee43ccb89 { $return = 'Microsoft StaffHub' } - 51133ff5-8e0d-4078-bcca-84fb7f905b64 { $return = 'Microsoft Teams Mailhook' } - ab3be6b7-f5df-413d-ac2d-abf1e3fd9c0b { $return = 'Microsoft Teams Graph Service' } - b1379a75-ce5e-4fa3-80c6-89bb39bf646c { $return = 'Microsoft Teams Chat Aggregator' } - 48af08dc-f6d2-435f-b2a7-069abd99c086 { $return = 'Connectors' } - d676e816-a17b-416b-ac1a-05ad96f43686 { $return = 'Workflow' } - cfa8b339-82a2-471a-a3c9-0fc0be7a4093 { $return = 'Azure Key Vault' } - c2f89f53-3971-4e09-8656-18eed74aee10 { $return = 'calendly' } - 6da466b6-1d13-4a2c-97bd-51a99e8d4d74 { $return = 'Exchange Office Graph Client for AAD - Interactive' } - 0eda3b13-ddc9-4c25-b7dd-2f6ea073d6b7 { $return = 'Microsoft Flow CDS Integration Service' } - eacba838-453c-4d3e-8c6a-eb815d3469a3 { $return = 'Microsoft Flow CDS Integration Service TIP1' } - 4ac7d521-0382-477b-b0f8-7e1d95f85ca2 { $return = 'SQL Server Analysis Services Azure' } - b4114287-89e4-4209-bd99-b7d4919bcf64 { $return = 'OfficeDelve' } - 4580fd1d-e5a3-4f56-9ad1-aab0e3bf8f76 { $return = 'Call Recorder' } - a855a166-fd92-4c76-b60d-a791e0762432 { $return = 'Microsoft Teams VSTS' } - c37c294f-eec8-47d2-b3e2-fc3daa8f77d3 { $return = 'Workflow' } - fc75330b-179d-49af-87dd-3b1acf6827fa { $return = 'AzureAutomationAADPatchS2S' } - 766d89a4-d6a6-444d-8a5e-e1a18622288a { $return = 'OneDrive' } - f16c4a38-5aff-4549-8199-ee7d3c5bd8dc { $return = 'Workflow' } - 4c4f550b-42b2-4a16-93f9-fdb9e01bb6ed { $return = 'Targeted Messaging Service' } - 765fe668-04e7-42ba-aec0-2c96f1d8b652 { $return = 'Exchange Office Graph Client for AAD - Noninteractive' } - 0130cc9f-7ac5-4026-bd5f-80a08a54e6d9 { $return = 'Azure Data Warehouse Polybase' } - a1cf9e0a-fe14-487c-beb9-dd3360921173 { $return = 'Meetup' } - 76cd24bf-a9fc-4344-b1dc-908275de6d6d { $return = 'Azure SQL Virtual Network to Network Resource Provider' } - 9f505dbd-a32c-4685-b1c6-72e4ef704cb0 { $return = 'Amazon Alexa' } - 1e2ca66a-c176-45ea-a877-e87f7231e0ee { $return = 'Microsoft B2B Admin Worker' } - 2634dd23-5e5a-431c-81ca-11710d9079f4 { $return = 'Microsoft Stream Service' } - cf53fce8-def6-4aeb-8d30-b158e7b1cf83 { $return = 'Microsoft Stream Portal' } - c9a559d2-7aab-4f13-a6ed-e7e9c52aec87 { $return = 'Microsoft Forms' } - 978877ea-b2d6-458b-80c7-05df932f3723 { $return = 'Microsoft Teams AuditService' } - dbc36ae1-c097-4df9-8d94-343c3d091a76 { $return = 'Service Encryption' } - fa7ff576-8e31-4a58-a5e5-780c1cd57caa { $return = 'OneNote' } - cb4dc29f-0bf4-402a-8b30-7511498ed654 { $return = 'Power BI Premium' } - f5aeb603-2a64-4f37-b9a8-b544f3542865 { $return = 'Microsoft Teams RetentionHook Service' } - da109bdd-abda-4c06-8808-4655199420f8 { $return = 'Glip Contacts' } - 76c7f279-7959-468f-8943-3954880e0d8c { $return = 'Azure SQL Managed Instance to Microsoft.Network' } - 3a9ddf38-83f3-4ea1-a33a-ecf934644e2d { $return = 'Protected Message Viewer' } - 5635d99c-c364-4411-90eb-764a511b5fdf { $return = 'Responsive Banner Slider' } - a43e5392-f48b-46a4-a0f1-098b5eeb4757 { $return = 'Cloudsponge' } - d73f4b35-55c9-48c7-8b10-651f6f2acb2e { $return = 'MCAPI Authorization Prod' } - 166f1b03-5b19-416f-a94b-1d7aa2d247dc { $return = 'Office Hive' } - b815ce1c-748f-4b1e-9270-a42c1fa4485a { $return = 'Workflow' } - bd7b778b-4aa8-4cde-8d90-8aeb821c0bd2 { $return = 'Workflow' } - 9d06afd9-66c9-49a6-b385-ea7509332b0b { $return = 'O365SBRM Service' } - 9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7 { $return = 'Bing' } - 57fb890c-0dab-4253-a5e0-7188c88b2bb4 { $return = 'SharePoint Online Client' } - 45c10911-200f-4e27-a666-9e9fca147395 { $return = 'drawio' } - b73f62d0-210b-4396-a4c5-ea50c4fab79b { $return = 'Skype Business Voice Fraud Detection and Prevention' } - bc59ab01-8403-45c6-8796-ac3ef710b3e3 { $return = 'Outlook Online Add-in App' } - 035f9e1d-4f00-4419-bf50-bf2d87eb4878 { $return = 'Azure Monitor Restricted' } - 7c33bfcb-8d33-48d6-8e60-dc6404003489 { $return = 'Network Watcher' } - a0be0c72-870e-46f0-9c49-c98333a996f7 { $return = 'AzureDnsFrontendApp' } - 1e3e4475-288f-4018-a376-df66fd7fac5f { $return = 'NetworkTrafficAnalyticsService' } - 7557eb47-c689-4224-abcf-aef9bd7573df { $return = 'Skype for Business' } - c39c9bac-9d1f-4dfb-aa29-27f6365e5cb7 { $return = 'Azure Advisor' } - 2087bd82-7206-4c0a-b305-1321a39e5926 { $return = 'Microsoft To-Do' } - f8d98a96-0999-43f5-8af3-69971c7bb423 { $return = 'iOS Accounts' } - c27373d3-335f-4b45-8af9-fe81c240d377 { $return = 'P2P Server' } - 5c2ffddc-f1d7-4dc3-926e-3c1bd98e32bd { $return = 'RITS Dev' } - 982bda36-4632-4165-a46a-9863b1bbcf7d { $return = 'O365 Demeter' } - 98c8388a-4e86-424f-a176-d1288462816f { $return = 'OfficeFeedProcessors' } - bf9fc203-c1ff-4fd4-878b-323642e462ec { $return = 'Jarvis Transaction Service' } - 257601fd-462f-4a21-b623-7f719f0f90f4 { $return = 'Centralized Deployment' } - 2a486b53-dbd2-49c0-a2bc-278bdfc30833 { $return = 'Cortana at Work Service' } - 22d7579f-06c2-4baa-89d2-e844486adb9d { $return = 'Cortana at Work Bing Services' } - 4c8f074c-e32b-4ba7-b072-0f39d71daf51 { $return = 'IPSubstrate' } - a164aee5-7d0a-46bb-9404-37421d58bdf7 { $return = 'Microsoft Teams AuthSvc' } - 354b5b6d-abd6-4736-9f51-1be80049b91f { $return = 'Microsoft Mobile Application Management Backend' } - 82b293b2-d54d-4d59-9a95-39c1c97954a7 { $return = 'Tasks in a Box' } - fdc83783-b652-4258-a622-66bc85f1a871 { $return = 'FedExPackageTracking' } - d0597157-f0ae-4e23-b06c-9e65de434c4f { $return = 'Microsoft Teams Task Service' } - f5c26e74-f226-4ae8-85f0-b4af0080ac9e { $return = 'Application Insights API' } - 57c0fc58-a83a-41d0-8ae9-08952659bdfd { $return = 'Azure Cosmos DB Virtual Network To Network Resource Provider' } - 744e50be-c4ff-4e90-8061-cd7f1fabac0b { $return = 'LinkedIn Microsoft Graph Connector' } - 823dfde0-1b9a-415a-a35a-1ad34e16dd44 { $return = 'Microsoft Teams Wiki Images Migration' } - 3ab9b3bc-762f-4d62-82f7-7e1d653ce29f { $return = 'Microsoft Volume Licensing' } - 44eb7794-0e11-42b6-800b-dc31874f9f60 { $return = 'Alignable' } - c58637bb-e2e1-4312-8a00-04b5ffcd3403 { $return = 'SharePoint Online Client Extensibility' } - 62b732f7-fc71-40bc-b27d-35efcb0509de { $return = 'Microsoft Teams AadSync' } - 07978fee-621a-42df-82bb-3eabc6511c26 { $return = 'SurveyMonkey' } - 47ee738b-3f1a-4fc7-ab11-37e4822b007e { $return = 'Azure AD Application Proxy' } - 00000007-0000-0000-c000-000000000000 { $return = 'Dynamics CRM Online' } - 913c6de4-2a4a-4a61-a9ce-945d2b2ce2e0 { $return = 'Dynamics Lifecycle services' } - f217ad13-46b8-4c5b-b661-876ccdf37302 { $return = 'Attach OneDrive files to Asana' } - 00000008-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.DataMarket' } - 9b06ebd4-9068-486b-bdd2-dac26b8a5a7a { $return = 'Microsoft.DynamicsMarketing' } - e8ab36af-d4be-4833-a38b-4d6cf1cfd525 { $return = 'Microsoft Social Engagement' } - 8909aac3-be91-470c-8a0b-ff09d669af91 { $return = 'Microsoft Parature Dynamics CRM' } - 71234da4-b92f-429d-b8ec-6e62652e50d7 { $return = 'Microsoft Customer Engagement Portal' } - b861dbcc-a7ef-4219-a005-0e4de4ea7dcf { $return = 'Data Export Service for Microsoft Dynamics 365' } - 2db8cb1d-fb6c-450b-ab09-49b6ae35186b { $return = 'Microsoft Dynamics CRM Learning Path' } - 2e49aa60-1bd3-43b6-8ab6-03ada3d9f08b { $return = 'Dynamics Data Integration' } - } + function Get-UserNameFromId { + [CmdletBinding()] + param ( + [Parameter()] + $ID, - if ([string]::IsNullOrEmpty($return)) { - $return = $Applications | Where-Object { $_.Appid -eq $ID } | Select-Object -ExpandProperty DisplayName + [Parameter(Mandatory = $true)] + $Users + ) + if ($id -eq 'All') { + return 'All' + } + $DisplayName = $Users | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName + if ([string]::IsNullOrEmpty($displayName)) { + return $ID + } else { + return $DisplayName + } } - if ([string]::IsNullOrEmpty($return)) { - $return = $Applications | Where-Object { $_.ID -eq $ID } | Select-Object -ExpandProperty DisplayName - } + function Get-GroupNameFromId { + param ( + [Parameter()] + $ID, - if ([string]::IsNullOrEmpty($return)) { - $return = '' + [Parameter(Mandatory = $true)] + $Groups + ) + if ($id -eq 'All') { + return 'All' + } + $DisplayName = $Groups | Where-Object { $_.id -eq $ID } | Select-Object -ExpandProperty DisplayName + if ([string]::IsNullOrEmpty($displayName)) { + return 'No Data' + } else { + return $DisplayName + } } - return $return -} + function Get-ApplicationNameFromId { + [CmdletBinding()] + param ( + [Parameter()] + $ID, + + [Parameter(Mandatory = $true)] + $Applications + ) + if ($id -eq 'All') { + return 'All' + } + switch ($id) { + 00000004-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.Lync' } + 00000006-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.Office365Portal' } + 00000003-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.SharePoint ' } + 00000005-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.Workflow' } + 00000009-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.AnalysisServices' } + 00000002-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.Exchange' } + 00000007-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.ExchangeOnlineProtection' } + 00000002-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.ActiveDirectory' } + 8fca0a66-c008-4564-a876-ab3ae0fd5cff { $return = 'Microsoft.SMIT' } + 0000000b-0000-0000-c000-000000000000 { $return = 'Microsoft.SellerDashboard' } + 0000000f-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.GraphExplorer' } + 0000000c-0000-0000-c000-000000000000 { $return = 'Microsoft App Access Panel' } + 00000013-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.Portal' } + 00000010-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.GraphStore' } + 93ee9413-cf4c-4d4e-814b-a91ff20a01bd { $return = 'Workflow' } + aa9ecb1e-fd53-4aaa-a8fe-7a54de2c1334 { $return = 'Microsoft.Office365.Configure' } + 797f4846-ba00-4fd7-ba43-dac1f8f63013 { $return = 'Windows Azure Service Management API' } + 00000005-0000-0ff1-ce00-000000000000 { $return = 'Microsoft.YammerEnterprise' } + 601d4e27-7bb3-4dee-8199-90d47d527e1c { $return = 'Microsoft.Office365.ChangeManagement' } + 6f82282e-0070-4e78-bc23-e6320c5fa7de { $return = 'Microsoft.DiscoveryService' } + 0f698dd4-f011-4d23-a33e-b36416dcb1e6 { $return = 'Microsoft.OfficeClientService' } + 67e3df25-268a-4324-a550-0de1c7f97287 { $return = 'Microsoft.OfficeWebAppsService' } + ab27a73e-a3ba-4e43-8360-8bcc717114d8 { $return = 'Microsoft.OfficeModernCalendar' } + aedca418-a84d-430d-ab84-0b1ef06f318f { $return = 'Workflow' } + 595d87a1-277b-4c0a-aa7f-44f8a068eafc { $return = 'Microsoft.SupportTicketSubmission' } + e3583ad2-c781-4224-9b91-ad15a8179ba0 { $return = 'Microsoft.ExtensibleRealUserMonitoring' } + b645896d-566e-447e-8f7f-e2e663b5d182 { $return = 'OpsDashSharePointApp' } + 48229a4a-9f1d-413a-8b96-4c02462c0360 { $return = 'OpsDashSharePointApp' } + 48717084-a59c-4306-9dc4-3f618dbecdf9 { $return = '"Napa" Office 365 Development Tools' } + c859ff33-eb41-4ba6-8093-a2c5153bbd7c { $return = 'Workflow' } + 67cad61c-3411-48d7-ab73-561c64f11ed6 { $return = 'Workflow' } + 914ed757-9257-4200-b68e-a2bed2f12c5a { $return = 'RbacBackfill' } + 499b84ac-1321-427f-aa17-267ca6975798 { $return = 'Microsoft.VisualStudio.Online' } + b2590339-0887-4e94-93aa-13357eb510d7 { $return = 'Workflow' } + 0000001b-0000-0000-c000-000000000000 { $return = 'Microsoft Power BI Information Service' } + 89f80565-bfac-4c01-9535-9f0eba332ffe { $return = 'Power BI' } + 433895fb-4ec7-45c3-a53c-c44d10f80d5b { $return = 'Compromised Account Service' } + d7c17728-4f1e-4a1e-86cf-7e0adf3fe903 { $return = 'Workflow' } + 17ef6d31-381f-4783-b186-7b440a3c85c1 { $return = 'Workflow' } + 00000012-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.RMS' } + 81ce94d4-9422-4c0d-a4b9-3250659366ce { $return = 'Workflow' } + 8d3a7d3c-c034-4f19-a2ef-8412952a9671 { $return = 'MicrosoftOffice' } + 0469d4cd-df37-4d93-8a61-f8c75b809164 { $return = 'Microsoft Policy Administration Service' } + 31d3f3f5-7267-45a8-9549-affb00110054 { $return = 'Windows Azure RemoteApp Service' } + 4e004241-32db-46c2-a86f-aaaba29bea9c { $return = 'Workflow' } + 748d098e-7a3b-436d-8b0a-006a58b29647 { $return = 'Workflow' } + dbf08535-1d3b-4f89-bf54-1d48dd613a61 { $return = 'Workflow' } + ed9fe1ef-25a4-482f-9981-2b60f91e2448 { $return = 'Workflow' } + 8ad28d50-ee26-42fc-8a29-e41ea38461f2 { $return = 'Office365RESTAPIExplorer.Office365App' } + 38285dce-a13d-4107-9b04-3016b941bb3a { $return = 'BasicDataOperationsREST' } + 92bb96c8-321c-47f9-bcc5-8849490c2b07 { $return = 'BasicSelfHostedAppREST' } + 488a57a0-00e2-4817-8c8d-cf8a15a994d2 { $return = 'WindowsFormsApplication2.Office365App' } + 11c174dc-1945-4a9a-a36b-c79a0f246b9b { $return = 'AzureApplicationInsights' } + e6acb561-0d94-4287-bd3a-3169f421b112 { $return = 'Tutum' } + 7b77b3a2-8490-49e1-8842-207cd0899af9 { $return = 'Nearpod' } + 0000000a-0000-0000-c000-000000000000 { $return = 'Microsoft.Intune' } + 93625bc8-bfe2-437a-97e0-3d0060024faa { $return = 'SelfServicePasswordReset' } + dee7ba80-6a55-4f3b-a86c-746a9231ae49 { $return = 'MicrosoftAppPlatEMA' } + 803ee9ca-3f7f-4824-bd6e-0b99d720c35c { $return = 'Azure Media Service' } + 2d4d3d8e-2be3-4bef-9f87-7875a61c29de { $return = 'OneNote' } + 8d40666e-5abf-45f6-a5e7-b7192d6d56ed { $return = 'Workflow' } + 262044b1-e2ce-469f-a196-69ab7ada62d3 { $return = 'Backup Management Service' } + 087a2c70-c89e-463f-8dd3-e3959eabb1a9 { $return = 'Microsoft Profile Service Platform Service' } + 7cd684f4-8a78-49b0-91ec-6a35d38739ba { $return = 'Azure Logic Apps' } + c5393580-f805-4401-95e8-94b7a6ef2fc2 { $return = 'Office 365 Management APIs' } + 96231a05-34ce-4eb4-aa6a-70759cbb5e83 { $return = 'MicrosoftAzureRedisCache' } + b8340c3b-9267-498f-b21a-15d5547fd85e { $return = 'Hyper-V Recovery Manager' } + abfa0a7c-a6b6-4736-8310-5855508787cd { $return = 'Microsoft.Azure.WebSites' } + c44b4083-3bb0-49c1-b47d-974e53cbdf3c { $return = 'IbizaPortal' } + 905fcf26-4eb7-48a0-9ff0-8dcc7194b5ba { $return = 'Sway' } + b10686fd-6ba8-49f2-a3cd-67e4d2f52ac8 { $return = 'NovoEd' } + c606301c-f764-4e6b-aa45-7caaaea93c9a { $return = 'OfficeStore' } + 569e8598-685b-4ba2-8bff-5bced483ac46 { $return = 'Evercontact' } + 20a23a2f-8c32-4de7-8063-8c8f909602c0 { $return = 'Workflow' } + aaf214cc-8013-4b95-975f-13203ae36039 { $return = 'Power BI Tiles' } + d88a361a-d488-4271-a13f-a83df7dd99c2 { $return = 'IDML Graph Resolver Service and CAD' } + dff9b531-6290-4620-afce-26826a62a4e7 { $return = 'DocuSign' } + 01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9 { $return = 'Device Registration Service' } + 3290e3f7-d3ac-4165-bcef-cf4874fc4270 { $return = 'Smartsheet' } + a4ee6867-8640-4495-b1fd-8b26037a5bd3 { $return = 'Workflow' } + aa0e3dd4-df02-478d-869e-fc61dd71b6e8 { $return = 'Workflow' } + 0f6edad5-48f2-4585-a609-d252b1c52770 { $return = 'AIGraphClient' } + 0c8139b5-d545-4448-8d2b-2121bb242680 { $return = 'BillingExtension' } + 475226c6-020e-4fb2-8a90-7a972cbfc1d4 { $return = 'KratosAppsService' } + 39624784-6cbe-4a60-afbe-9f46d10fdb27 { $return = 'SkypeForBusinessRemotePowershell' } + 8bdebf23-c0fe-4187-a378-717ad86f6a53 { $return = 'ResourceHealthRP' } + c161e42e-d4df-4a3d-9b42-e7a3c31f59d4 { $return = 'MicrosoftIntuneAPI' } + 9cb77803-d937-493e-9a3b-4b49de3f5a74 { $return = 'MicrosoftIntuneServiceDiscovery' } + ddbf3205-c6bd-46ae-8127-60eb93363864 { $return = 'Microsoft Azure Batch' } + 80ccca67-54bd-44ab-8625-4b79c4dc7775 { $return = 'ComplianceCenter' } + 0a5f63c0-b750-4f38-a71c-4fc0d58b89e2 { $return = 'Microsoft Mobile Application Management' } + e1335bb1-2aec-4f92-8140-0e6e61ae77e5 { $return = 'CIWebService' } + 75018fbe-21fe-4a57-b63c-83252b5eaf16 { $return = 'TeamImprover - Team Organization Chart' } + a393296b-5695-4463-97cb-9fa8638a494a { $return = 'My SharePoint Sites' } + fe217466-5583-431c-9531-14ff7268b7b3 { $return = 'Microsoft Education' } + 5bfe8a29-054e-4348-9e7a-3981b26b125f { $return = 'Bing Places for Business' } + eaf8a961-f56e-47eb-9ffd-936e22a554ef { $return = 'DevilFish' } + 4b4b1d56-1f03-47d9-a0a3-87d4afc913c9 { $return = 'Wunderlist' } + 00000003-0000-0000-c000-000000000000 { $return = 'Microsoft Graph' } + 60e6cd67-9c8c-4951-9b3c-23c25a2169af { $return = 'Compute Resource Provider' } + 507bc9da-c4e2-40cb-96a7-ac90df92685c { $return = 'Office365Reports' } + 09abbdfd-ed23-44ee-a2d9-a627aa1c90f3 { $return = 'ProjectWorkManagement' } + 28ec9756-deaf-48b2-84d5-a623b99af263 { $return = 'Office Personal Assistant at Work Service' } + 9e4a5442-a5c9-4f6f-b03f-5b9fcaaf24b1 { $return = 'OfficeServicesManager' } + 3138fe80-4087-4b04-80a6-8866c738028a { $return = 'SharePoint Notification Service' } + d2a0a418-0aac-4541-82b2-b3142c89da77 { $return = 'MicrosoftAzureOperationalInsights' } + 2cf9eb86-36b5-49dc-86ae-9a63135dfa8c { $return = 'AzureTrafficManagerandDNS' } + 32613fc5-e7ac-4894-ac94-fbc39c9f3e4a { $return = 'OAuth Sandbox' } + 925eb0d0-da50-4604-a19f-bd8de9147958 { $return = 'Groupies Web Service' } + e4ab13ed-33cb-41b4-9140-6e264582cf85 { $return = 'Azure SQL Database Backup To Azure Backup Vault' } + ad230543-afbe-4bb4-ac4f-d94d101704f8 { $return = 'Apiary for Power BI' } + 11cd3e2e-fccb-42ad-ad00-878b93575e07 { $return = 'Automated Call Distribution' } + de17788e-c765-4d31-aba4-fb837cfff174 { $return = 'Skype for Business Management Reporting and Analytics' } + 65d91a3d-ab74-42e6-8a2f-0add61688c74 { $return = 'Microsoft Approval Management' } + 5225545c-3ebd-400f-b668-c8d78550d776 { $return = 'Office Agent Service' } + 1cda9b54-9852-4a5a-96d4-c2ab174f9edf { $return = 'O365Account' } + 4747d38e-36c5-4bc3-979b-b0ef74df54d1 { $return = 'PushChannel' } + b97b6bd4-a49f-4a0c-af18-af507d1da76c { $return = 'Office Shredding Service' } + d4ebce55-015a-49b5-a083-c84d1797ae8c { $return = 'Microsoft Intune Enrollment' } + 5b20c633-9a48-4a5f-95f6-dae91879051f { $return = 'Azure Information Protection' } + 441509e5-a165-4363-8ee7-bcf0b7d26739 { $return = 'EnterpriseAgentPlatform' } + e691bce4-6612-4025-b94c-81372a99f77e { $return = 'Boomerang' } + 8edd93e1-2103-40b4-bd70-6e34e586362d { $return = 'Windows Azure Security Resource Provider' } + 94c63fef-13a3-47bc-8074-75af8c65887a { $return = 'Office Delve' } + e95d8bee-4725-4f59-910d-94d415da51b9 { $return = 'Skype for Business Name Dictionary Service' } + e3c5dbcd-bb5f-4bda-b943-adc7a5bbc65e { $return = 'Workflow' } + 8602e328-9b72-4f2d-a4ae-1387d013a2b3 { $return = 'Azure API Management' } + 8b3391f4-af01-4ee8-b4ea-9871b2499735 { $return = 'O365 Secure Score' } + c26550d6-bc82-4484-82ca-ac1c75308ca3 { $return = 'Office 365 YammerOnOls' } + 33be1cef-03fb-444b-8fd3-08ca1b4d803f { $return = 'OneDrive Web' } + dcad865d-9257-4521-ad4d-bae3e137b345 { $return = 'Microsoft SharePoint Online - SharePoint Home' } + b2cc270f-563e-4d8a-af47-f00963a71dcd { $return = 'OneProfile Service' } + 4660504c-45b3-4674-a709-71951a6b0763 { $return = 'Microsoft Invitation Acceptance Portal' } + ba23cd2a-306c-48f2-9d62-d3ecd372dfe4 { $return = 'OfficeGraph' } + d52485ee-4609-4f6b-b3a3-68b6f841fa23 { $return = 'On-Premises Data Gateway Connector' } + 996def3d-b36c-4153-8607-a6fd3c01b89f { $return = 's 365 for Financials' } + b6b84568-6c01-4981-a80f-09da9a20bbed { $return = 'Microsoft Invoicing' } + 9d3e55ba-79e0-4b7c-af50-dc460b81dca1 { $return = 'Microsoft Azure Data Catalog' } + 4345a7b9-9a63-4910-a426-35363201d503 { $return = 'O365 Suite UX' } + ac815d4a-573b-4174-b38e-46490d19f894 { $return = 'Workflow' } + bb8f18b0-9c38-48c9-a847-e1ef3af0602d { $return = 'Microsoft.Azure.ActiveDirectoryIUX' } + cc15fd57-2c6c-4117-a88c-83b1d56b4bbe { $return = 'Microsoft Teams Services' } + 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 { $return = 'Skype Teams' } + 1fec8e78-bce4-4aaf-ab1b-5451cc387264 { $return = 'Microsoft Teams' } + 6d32b7f8-782e-43e0-ac47-aaad9f4eb839 { $return = 'Permission Service O365' } + cdccd920-384b-4a25-897d-75161a4b74c1 { $return = 'Skype Teams Firehose' } + 1c0ae35a-e2ec-4592-8e08-c40884656fa5 { $return = 'Skype Team Substrate connector' } + cf6c77f8-914f-4078-baef-e39a5181158b { $return = 'Skype Teams Settings Store' } + 64f79cb9-9c82-4199-b85b-77e35b7dcbcb { $return = 'Microsoft Teams Bots' } + b7912db9-aa33-4820-9d4f-709830fdd78f { $return = 'ConnectionsService' } + 82f77645-8a66-4745-bcdf-9706824f9ad0 { $return = 'PowerApps Runtime Service' } + 6204c1d1-4712-4c46-a7d9-3ed63d992682 { $return = 'Microsoft Flow Portal' } + 7df0a125-d3be-4c96-aa54-591f83ff541c { $return = 'Microsoft Flow Service' } + 331cc017-5973-4173-b270-f0042fddfd75 { $return = 'PowerAppsService' } + 0a0e9e37-25e3-47d4-964c-5b8237cad19a { $return = 'CloudSponge' } + df09ff61-2178-45d8-888c-4210c1c7b0b2 { $return = 'O365 UAP Processor' } + 8338dec2-e1b3-48f7-8438-20c30a534458 { $return = 'ViewPoint' } + 00000001-0000-0000-c000-000000000000 { $return = 'Azure ESTS Service' } + 394866fc-eedb-4f01-8536-3ff84b16be2a { $return = 'Microsoft People Cards Service' } + 0a0a29f9-0a25-49c7-94bf-c53c3f8fa69d { $return = 'Cortana Experience with O365' } + bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4 { $return = 'CPIM Service' } + 0004c632-673b-4105-9bb6-f3bbd2a927fe { $return = 'PowerApps and Flow' } + d3ce4cf8-6810-442d-b42e-375e14710095 { $return = 'Graph Explorer' } + 3aa5c166-136f-40eb-9066-33ac63099211 { $return = 'O365 Customer Monitoring' } + d6fdaa33-e821-4211-83d0-cf74736489e1 { $return = 'Microsoft Service Trust' } + ef4a2a24-4b4e-4abf-93ba-cc11c5bd442c { $return = 'Edmodo' } + b692184e-b47f-4706-b352-84b288d2d9ee { $return = 'Microsoft.MileIQ.RESTService' } + a25dbca8-4e60-48e5-80a2-0664fdb5c9b6 { $return = 'Microsoft.MileIQ' } + f7069a8d-9edc-4300-b365-ae53c9627fc4 { $return = 'Microsoft.MileIQ.Dashboard' } + 02e3ae74-c151-4bda-b8f0-55fbf341de08 { $return = 'Application Registration Portal' } + 1f5530b3-261a-47a9-b357-ded261e17918 { $return = 'Azure Multi-Factor Auth Connector' } + 981f26a1-7f43-403b-a875-f8b09b8cd720 { $return = 'Azure Multi-Factor Auth Client' } + 6ea8091b-151d-447a-9013-6845b83ba57b { $return = 'AD Hybrid Health' } + fc68d9e5-1f76-45ef-99aa-214805418498 { $return = 'Azure AD Identity Protection' } + 01fc33a7-78ba-4d2f-a4b7-768e336e890e { $return = 'MS-PIM' } + a6aa9161-5291-40bb-8c5c-923b567bee3b { $return = 'Storage Resource Provider' } + 4e9b8b9a-1001-4017-8dd1-6e8f25e19d13 { $return = 'Adobe Acrobat' } + 159b90bb-bb28-4568-ad7c-adad6b814a2f { $return = 'LastPass' } + b4bddae8-ab25-483e-8670-df09b9f1d0ea { $return = 'Signup' } + aa580612-c342-4ace-9055-8edee43ccb89 { $return = 'Microsoft StaffHub' } + 51133ff5-8e0d-4078-bcca-84fb7f905b64 { $return = 'Microsoft Teams Mailhook' } + ab3be6b7-f5df-413d-ac2d-abf1e3fd9c0b { $return = 'Microsoft Teams Graph Service' } + b1379a75-ce5e-4fa3-80c6-89bb39bf646c { $return = 'Microsoft Teams Chat Aggregator' } + 48af08dc-f6d2-435f-b2a7-069abd99c086 { $return = 'Connectors' } + d676e816-a17b-416b-ac1a-05ad96f43686 { $return = 'Workflow' } + cfa8b339-82a2-471a-a3c9-0fc0be7a4093 { $return = 'Azure Key Vault' } + c2f89f53-3971-4e09-8656-18eed74aee10 { $return = 'calendly' } + 6da466b6-1d13-4a2c-97bd-51a99e8d4d74 { $return = 'Exchange Office Graph Client for AAD - Interactive' } + 0eda3b13-ddc9-4c25-b7dd-2f6ea073d6b7 { $return = 'Microsoft Flow CDS Integration Service' } + eacba838-453c-4d3e-8c6a-eb815d3469a3 { $return = 'Microsoft Flow CDS Integration Service TIP1' } + 4ac7d521-0382-477b-b0f8-7e1d95f85ca2 { $return = 'SQL Server Analysis Services Azure' } + b4114287-89e4-4209-bd99-b7d4919bcf64 { $return = 'OfficeDelve' } + 4580fd1d-e5a3-4f56-9ad1-aab0e3bf8f76 { $return = 'Call Recorder' } + a855a166-fd92-4c76-b60d-a791e0762432 { $return = 'Microsoft Teams VSTS' } + c37c294f-eec8-47d2-b3e2-fc3daa8f77d3 { $return = 'Workflow' } + fc75330b-179d-49af-87dd-3b1acf6827fa { $return = 'AzureAutomationAADPatchS2S' } + 766d89a4-d6a6-444d-8a5e-e1a18622288a { $return = 'OneDrive' } + f16c4a38-5aff-4549-8199-ee7d3c5bd8dc { $return = 'Workflow' } + 4c4f550b-42b2-4a16-93f9-fdb9e01bb6ed { $return = 'Targeted Messaging Service' } + 765fe668-04e7-42ba-aec0-2c96f1d8b652 { $return = 'Exchange Office Graph Client for AAD - Noninteractive' } + 0130cc9f-7ac5-4026-bd5f-80a08a54e6d9 { $return = 'Azure Data Warehouse Polybase' } + a1cf9e0a-fe14-487c-beb9-dd3360921173 { $return = 'Meetup' } + 76cd24bf-a9fc-4344-b1dc-908275de6d6d { $return = 'Azure SQL Virtual Network to Network Resource Provider' } + 9f505dbd-a32c-4685-b1c6-72e4ef704cb0 { $return = 'Amazon Alexa' } + 1e2ca66a-c176-45ea-a877-e87f7231e0ee { $return = 'Microsoft B2B Admin Worker' } + 2634dd23-5e5a-431c-81ca-11710d9079f4 { $return = 'Microsoft Stream Service' } + cf53fce8-def6-4aeb-8d30-b158e7b1cf83 { $return = 'Microsoft Stream Portal' } + c9a559d2-7aab-4f13-a6ed-e7e9c52aec87 { $return = 'Microsoft Forms' } + 978877ea-b2d6-458b-80c7-05df932f3723 { $return = 'Microsoft Teams AuditService' } + dbc36ae1-c097-4df9-8d94-343c3d091a76 { $return = 'Service Encryption' } + fa7ff576-8e31-4a58-a5e5-780c1cd57caa { $return = 'OneNote' } + cb4dc29f-0bf4-402a-8b30-7511498ed654 { $return = 'Power BI Premium' } + f5aeb603-2a64-4f37-b9a8-b544f3542865 { $return = 'Microsoft Teams RetentionHook Service' } + da109bdd-abda-4c06-8808-4655199420f8 { $return = 'Glip Contacts' } + 76c7f279-7959-468f-8943-3954880e0d8c { $return = 'Azure SQL Managed Instance to Microsoft.Network' } + 3a9ddf38-83f3-4ea1-a33a-ecf934644e2d { $return = 'Protected Message Viewer' } + 5635d99c-c364-4411-90eb-764a511b5fdf { $return = 'Responsive Banner Slider' } + a43e5392-f48b-46a4-a0f1-098b5eeb4757 { $return = 'Cloudsponge' } + d73f4b35-55c9-48c7-8b10-651f6f2acb2e { $return = 'MCAPI Authorization Prod' } + 166f1b03-5b19-416f-a94b-1d7aa2d247dc { $return = 'Office Hive' } + b815ce1c-748f-4b1e-9270-a42c1fa4485a { $return = 'Workflow' } + bd7b778b-4aa8-4cde-8d90-8aeb821c0bd2 { $return = 'Workflow' } + 9d06afd9-66c9-49a6-b385-ea7509332b0b { $return = 'O365SBRM Service' } + 9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7 { $return = 'Bing' } + 57fb890c-0dab-4253-a5e0-7188c88b2bb4 { $return = 'SharePoint Online Client' } + 45c10911-200f-4e27-a666-9e9fca147395 { $return = 'drawio' } + b73f62d0-210b-4396-a4c5-ea50c4fab79b { $return = 'Skype Business Voice Fraud Detection and Prevention' } + bc59ab01-8403-45c6-8796-ac3ef710b3e3 { $return = 'Outlook Online Add-in App' } + 035f9e1d-4f00-4419-bf50-bf2d87eb4878 { $return = 'Azure Monitor Restricted' } + 7c33bfcb-8d33-48d6-8e60-dc6404003489 { $return = 'Network Watcher' } + a0be0c72-870e-46f0-9c49-c98333a996f7 { $return = 'AzureDnsFrontendApp' } + 1e3e4475-288f-4018-a376-df66fd7fac5f { $return = 'NetworkTrafficAnalyticsService' } + 7557eb47-c689-4224-abcf-aef9bd7573df { $return = 'Skype for Business' } + c39c9bac-9d1f-4dfb-aa29-27f6365e5cb7 { $return = 'Azure Advisor' } + 2087bd82-7206-4c0a-b305-1321a39e5926 { $return = 'Microsoft To-Do' } + f8d98a96-0999-43f5-8af3-69971c7bb423 { $return = 'iOS Accounts' } + c27373d3-335f-4b45-8af9-fe81c240d377 { $return = 'P2P Server' } + 5c2ffddc-f1d7-4dc3-926e-3c1bd98e32bd { $return = 'RITS Dev' } + 982bda36-4632-4165-a46a-9863b1bbcf7d { $return = 'O365 Demeter' } + 98c8388a-4e86-424f-a176-d1288462816f { $return = 'OfficeFeedProcessors' } + bf9fc203-c1ff-4fd4-878b-323642e462ec { $return = 'Jarvis Transaction Service' } + 257601fd-462f-4a21-b623-7f719f0f90f4 { $return = 'Centralized Deployment' } + 2a486b53-dbd2-49c0-a2bc-278bdfc30833 { $return = 'Cortana at Work Service' } + 22d7579f-06c2-4baa-89d2-e844486adb9d { $return = 'Cortana at Work Bing Services' } + 4c8f074c-e32b-4ba7-b072-0f39d71daf51 { $return = 'IPSubstrate' } + a164aee5-7d0a-46bb-9404-37421d58bdf7 { $return = 'Microsoft Teams AuthSvc' } + 354b5b6d-abd6-4736-9f51-1be80049b91f { $return = 'Microsoft Mobile Application Management Backend' } + 82b293b2-d54d-4d59-9a95-39c1c97954a7 { $return = 'Tasks in a Box' } + fdc83783-b652-4258-a622-66bc85f1a871 { $return = 'FedExPackageTracking' } + d0597157-f0ae-4e23-b06c-9e65de434c4f { $return = 'Microsoft Teams Task Service' } + f5c26e74-f226-4ae8-85f0-b4af0080ac9e { $return = 'Application Insights API' } + 57c0fc58-a83a-41d0-8ae9-08952659bdfd { $return = 'Azure Cosmos DB Virtual Network To Network Resource Provider' } + 744e50be-c4ff-4e90-8061-cd7f1fabac0b { $return = 'LinkedIn Microsoft Graph Connector' } + 823dfde0-1b9a-415a-a35a-1ad34e16dd44 { $return = 'Microsoft Teams Wiki Images Migration' } + 3ab9b3bc-762f-4d62-82f7-7e1d653ce29f { $return = 'Microsoft Volume Licensing' } + 44eb7794-0e11-42b6-800b-dc31874f9f60 { $return = 'Alignable' } + c58637bb-e2e1-4312-8a00-04b5ffcd3403 { $return = 'SharePoint Online Client Extensibility' } + 62b732f7-fc71-40bc-b27d-35efcb0509de { $return = 'Microsoft Teams AadSync' } + 07978fee-621a-42df-82bb-3eabc6511c26 { $return = 'SurveyMonkey' } + 47ee738b-3f1a-4fc7-ab11-37e4822b007e { $return = 'Azure AD Application Proxy' } + 00000007-0000-0000-c000-000000000000 { $return = 'Dynamics CRM Online' } + 913c6de4-2a4a-4a61-a9ce-945d2b2ce2e0 { $return = 'Dynamics Lifecycle services' } + f217ad13-46b8-4c5b-b661-876ccdf37302 { $return = 'Attach OneDrive files to Asana' } + 00000008-0000-0000-c000-000000000000 { $return = 'Microsoft.Azure.DataMarket' } + 9b06ebd4-9068-486b-bdd2-dac26b8a5a7a { $return = 'Microsoft.DynamicsMarketing' } + e8ab36af-d4be-4833-a38b-4d6cf1cfd525 { $return = 'Microsoft Social Engagement' } + 8909aac3-be91-470c-8a0b-ff09d669af91 { $return = 'Microsoft Parature Dynamics CRM' } + 71234da4-b92f-429d-b8ec-6e62652e50d7 { $return = 'Microsoft Customer Engagement Portal' } + b861dbcc-a7ef-4219-a005-0e4de4ea7dcf { $return = 'Data Export Service for Microsoft Dynamics 365' } + 2db8cb1d-fb6c-450b-ab09-49b6ae35186b { $return = 'Microsoft Dynamics CRM Learning Path' } + 2e49aa60-1bd3-43b6-8ab6-03ada3d9f08b { $return = 'Dynamics Data Integration' } + } -# Write to the Azure Functions log stream. -Write-Host "PowerShell HTTP trigger function processed a request." + if ([string]::IsNullOrEmpty($return)) { + $return = $Applications | Where-Object { $_.Appid -eq $ID } | Select-Object -ExpandProperty DisplayName + } -# Interact with query parameters or the body of the request. -$TenantFilter = $Request.Query.TenantFilter -try { - $ConditionalAccessPolicyOutput = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" -tenantid $tenantfilter - $AllNamedLocations = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations" -tenantid $tenantfilter - $AllApplications = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications" -tenantid $tenantfilter - $AllRoleDefinitions = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions" -tenantid $tenantfilter - $GroupListOutput = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups" -tenantid $tenantfilter - $UserListOutput = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users" -tenantid $tenantfilter | Select-Object * -ExcludeProperty *extensionAttribute* + if ([string]::IsNullOrEmpty($return)) { + $return = $Applications | Where-Object { $_.ID -eq $ID } | Select-Object -ExpandProperty DisplayName + } - $GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { - $temp = [PSCustomObject]@{ - id = $cap.id - displayName = $cap.displayName - customer = $cap.Customer - tenantID = $cap.TenantID - createdDateTime = $(if (![string]::IsNullOrEmpty($cap.createdDateTime)) { [datetime]$cap.createdDateTime | Get-Date -Format "yyyy-MM-dd HH:mm" }else { "" }) - modifiedDateTime = $(if (![string]::IsNullOrEmpty($cap.modifiedDateTime)) { [datetime]$cap.modifiedDateTime | Get-Date -Format "yyyy-MM-dd HH:mm" }else { "" }) - state = $cap.state - clientAppTypes = ($cap.conditions.clientAppTypes) -join "," - includePlatforms = ($cap.conditions.platforms.includePlatforms) -join "," - excludePlatforms = ($cap.conditions.platforms.excludePlatforms) -join "," - includeLocations = (Get-LocationNameFromId -Locations $AllNamedLocations -id $cap.conditions.locations.includeLocations) -join "," - excludeLocations = (Get-LocationNameFromId -Locations $AllNamedLocations -id $cap.conditions.locations.excludeLocations) -join "," - includeApplications = ($cap.conditions.applications.includeApplications | ForEach-Object { Get-ApplicationNameFromId -Applications $AllApplications -id $_ }) -join "," - excludeApplications = ($cap.conditions.applications.excludeApplications | ForEach-Object { Get-ApplicationNameFromId -Applications $AllApplications -id $_ }) -join "," - includeUserActions = ($cap.conditions.applications.includeUserActions | Out-String) - includeAuthenticationContextClassReferences = ($cap.conditions.applications.includeAuthenticationContextClassReferences | Out-String) - includeUsers = ($cap.conditions.users.includeUsers | ForEach-Object { Get-UserNameFromId -Users $UserListOutput -id $_ }) | Out-String - excludeUsers = ($cap.conditions.users.excludeUsers | ForEach-Object { Get-UserNameFromId -Users $UserListOutput -id $_ }) | Out-String - includeGroups = ($cap.conditions.users.includeGroups | ForEach-Object { Get-GroupNameFromId -Groups $GroupListOutput -id $_ }) | Out-String - excludeGroups = ($cap.conditions.users.excludeGroups | ForEach-Object { Get-GroupNameFromId -Groups $GroupListOutput -id $_ }) | Out-String - includeRoles = ($cap.conditions.users.includeRoles | ForEach-Object { Get-RoleNameFromId -RoleDefinitions $AllRoleDefinitions -id $_ }) | Out-String - excludeRoles = ($cap.conditions.users.excludeRoles | ForEach-Object { Get-RoleNameFromId -RoleDefinitions $AllRoleDefinitions -id $_ }) | Out-String - grantControlsOperator = ($cap.grantControls.operator) -join "," - builtInControls = ($cap.grantControls.builtInControls) -join "," - customAuthenticationFactors = ($cap.grantControls.customAuthenticationFactors) -join "," - termsOfUse = ($cap.grantControls.termsOfUse) -join "," - rawjson = ($cap | ConvertTo-Json -Depth 100) + if ([string]::IsNullOrEmpty($return)) { + $return = '' } - $temp + + return $return } - $StatusCode = [HttpStatusCode]::OK -} -catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage -} -# Associate values to output bindings by calling 'Push-OutputBinding'. -Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $ConditionalAccessPolicyOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter + $AllNamedLocations = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -tenantid $tenantfilter + $AllApplications = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/applications' -tenantid $tenantfilter + $AllRoleDefinitions = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions' -tenantid $tenantfilter + $GroupListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenantfilter + $UserListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users' -tenantid $tenantfilter | Select-Object * -ExcludeProperty *extensionAttribute* + + $GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { + $temp = [PSCustomObject]@{ + id = $cap.id + displayName = $cap.displayName + customer = $cap.Customer + tenantID = $cap.TenantID + createdDateTime = $(if (![string]::IsNullOrEmpty($cap.createdDateTime)) { [datetime]$cap.createdDateTime | Get-Date -Format 'yyyy-MM-dd HH:mm' }else { '' }) + modifiedDateTime = $(if (![string]::IsNullOrEmpty($cap.modifiedDateTime)) { [datetime]$cap.modifiedDateTime | Get-Date -Format 'yyyy-MM-dd HH:mm' }else { '' }) + state = $cap.state + clientAppTypes = ($cap.conditions.clientAppTypes) -join ',' + includePlatforms = ($cap.conditions.platforms.includePlatforms) -join ',' + excludePlatforms = ($cap.conditions.platforms.excludePlatforms) -join ',' + includeLocations = (Get-LocationNameFromId -Locations $AllNamedLocations -id $cap.conditions.locations.includeLocations) -join ',' + excludeLocations = (Get-LocationNameFromId -Locations $AllNamedLocations -id $cap.conditions.locations.excludeLocations) -join ',' + includeApplications = ($cap.conditions.applications.includeApplications | ForEach-Object { Get-ApplicationNameFromId -Applications $AllApplications -id $_ }) -join ',' + excludeApplications = ($cap.conditions.applications.excludeApplications | ForEach-Object { Get-ApplicationNameFromId -Applications $AllApplications -id $_ }) -join ',' + includeUserActions = ($cap.conditions.applications.includeUserActions | Out-String) + includeAuthenticationContextClassReferences = ($cap.conditions.applications.includeAuthenticationContextClassReferences | Out-String) + includeUsers = ($cap.conditions.users.includeUsers | ForEach-Object { Get-UserNameFromId -Users $UserListOutput -id $_ }) | Out-String + excludeUsers = ($cap.conditions.users.excludeUsers | ForEach-Object { Get-UserNameFromId -Users $UserListOutput -id $_ }) | Out-String + includeGroups = ($cap.conditions.users.includeGroups | ForEach-Object { Get-GroupNameFromId -Groups $GroupListOutput -id $_ }) | Out-String + excludeGroups = ($cap.conditions.users.excludeGroups | ForEach-Object { Get-GroupNameFromId -Groups $GroupListOutput -id $_ }) | Out-String + includeRoles = ($cap.conditions.users.includeRoles | ForEach-Object { Get-RoleNameFromId -RoleDefinitions $AllRoleDefinitions -id $_ }) | Out-String + excludeRoles = ($cap.conditions.users.excludeRoles | ForEach-Object { Get-RoleNameFromId -RoleDefinitions $AllRoleDefinitions -id $_ }) | Out-String + grantControlsOperator = ($cap.grantControls.operator) -join ',' + builtInControls = ($cap.grantControls.builtInControls) -join ',' + customAuthenticationFactors = ($cap.grantControls.customAuthenticationFactors) -join ',' + termsOfUse = ($cap.grantControls.termsOfUse) -join ',' + rawjson = ($cap | ConvertTo-Json -Depth 100) + } + $temp + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 index 89e2ecfb2bff..22f708cfb080 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListConditionalAccessPolicyChanges { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 index 61701c1d51a9..946eaddafaf0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 @@ -1,66 +1,68 @@ using namespace System.Net Function Invoke-ExecAddGDAPRole { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Groups = $Request.body.gdapRoles - $CustomSuffix = $Request.body.customSuffix - $Table = Get-CIPPTable -TableName 'GDAPRoles' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Groups = $Request.body.gdapRoles + $CustomSuffix = $Request.body.customSuffix + $Table = Get-CIPPTable -TableName 'GDAPRoles' - $Results = [System.Collections.Generic.List[string]]::new() - $ExistingGroups = New-GraphGetRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID + $Results = [System.Collections.Generic.List[string]]::new() + $ExistingGroups = New-GraphGetRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID - $RoleMappings = foreach ($group in $Groups) { - if ($CustomSuffix) { - $GroupName = "M365 GDAP $($Group.Name) - $CustomSuffix" - $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))$($CustomSuffix)" + $RoleMappings = foreach ($group in $Groups) { + if ($CustomSuffix) { + $GroupName = "M365 GDAP $($Group.Name) - $CustomSuffix" + $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))$($CustomSuffix)" + } else { + $GroupName = "M365 GDAP $($Group.Name)" + $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))" + } + try { + if ($GroupName -in $ExistingGroups.displayName) { + @{ + PartitionKey = 'Roles' + RowKey = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id + RoleName = $Group.Name + GroupName = $GroupName + GroupId = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id + roleDefinitionId = $group.ObjectId + } + $Results.Add("M365 GDAP $($Group.Name) already exists") } else { - $GroupName = "M365 GDAP $($Group.Name)" - $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))" + $BodyToship = [pscustomobject] @{'displayName' = $GroupName; 'description' = "This group is used to manage M365 partner tenants at the $($group.name) level."; securityEnabled = $true; mailEnabled = $false; mailNickname = $MailNickname } | ConvertTo-Json + $GraphRequest = New-GraphPostRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID -type POST -body $BodyToship -verbose + @{ + PartitionKey = 'Roles' + RowKey = $GraphRequest.Id + RoleName = $Group.Name + GroupName = $GroupName + GroupId = $GraphRequest.Id + roleDefinitionId = $group.ObjectId + } + $Results.Add("$GroupName added successfully") } - try { - if ($GroupName -in $ExistingGroups.displayName) { - @{ - PartitionKey = 'Roles' - RowKey = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id - RoleName = $Group.Name - GroupName = $GroupName - GroupId = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id - roleDefinitionId = $group.ObjectId - } - $Results.Add("M365 GDAP $($Group.Name) already exists") - } else { - $BodyToship = [pscustomobject] @{'displayName' = $GroupName; 'description' = "This group is used to manage M365 partner tenants at the $($group.name) level."; securityEnabled = $true; mailEnabled = $false; mailNickname = $MailNickname } | ConvertTo-Json - $GraphRequest = New-GraphPostRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID -type POST -body $BodyToship -verbose - @{ - PartitionKey = 'Roles' - RowKey = $GraphRequest.Id - RoleName = $Group.Name - GroupName = $GroupName - GroupId = $GraphRequest.Id - roleDefinitionId = $group.ObjectId - } - $Results.Add("$GroupName added successfully") - } - } catch { - $Results.Add("Could not create GDAP group $($GroupName): $($_.Exception.Message)") - } - } + } catch { + $Results.Add("Could not create GDAP group $($GroupName): $($_.Exception.Message)") + } + } - Add-CIPPAzDataTableEntity @Table -Entity $RoleMappings -Force + Add-CIPPAzDataTableEntity @Table -Entity $RoleMappings -Force - $body = @{Results = @($Results) } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) + $body = @{Results = @($Results) } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 index d0f1b5385e0c..f57c65330f6f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 @@ -1,23 +1,25 @@ using namespace System.Net Function Invoke-ExecAutoExtendGDAP { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Interact with query parameters or the body of the request. - $Results = Set-CIPPGDAPAutoExtend -RelationShipid $Request.query.ID + # Interact with query parameters or the body of the request. + $Results = Set-CIPPGDAPAutoExtend -RelationShipid $Request.query.ID - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ Results = $Results } - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = $Results } + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 index bdfe01455cd4..61164e8968be 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecDeleteGDAPRelationship { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 index 729c327b3528..23426c6f1a14 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 @@ -1,33 +1,35 @@ using namespace System.Net Function Invoke-ExecDeleteGDAPRoleMapping { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Table = Get-CIPPTable -TableName 'GDAPRoles' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Table = Get-CIPPTable -TableName 'GDAPRoles' - Write-Host $Table - try { - $Filter = "PartitionKey eq 'Roles' and RowKey eq '{0}'" -f $Request.Query.GroupId - $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter - Remove-AzDataTableEntity @Table -Entity $Entity - $Results = [pscustomobject]@{'Results' = 'Success. GDAP relationship mapping deleted' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "GDAP relationship mapping deleted for $($Request.Query.GroupId)" -Sev 'Info' + Write-Host $Table + try { + $Filter = "PartitionKey eq 'Roles' and RowKey eq '{0}'" -f $Request.Query.GroupId + $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter + Remove-AzDataTableEntity @Table -Entity $Entity + $Results = [pscustomobject]@{'Results' = 'Success. GDAP relationship mapping deleted' } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "GDAP relationship mapping deleted for $($Request.Query.GroupId)" -Sev 'Info' - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 index 4739df9c2df1..41e4fdd26e77 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 @@ -2,7 +2,9 @@ using namespace System.Net Function Invoke-ExecGDAPInvite { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInviteApproved.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInviteApproved.ps1 index 23565a19602e..7430ff9e1ce5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInviteApproved.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInviteApproved.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGDAPInviteApproved { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 index 319118877545..c6a60971f1c6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 @@ -2,7 +2,9 @@ using namespace System.Net Function Invoke-ExecGDAPRemoveGArole { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 index afc2bacfc630..218f0248f2cc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGDAPInvite { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 index 94f43d623abe..d3110cadd8ad 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGDAPQueue { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -14,7 +16,7 @@ Function Invoke-ListGDAPQueue { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $Table = Get-CIPPTable -TableName 'GDAPMigration' + $Table = Get-CIPPTable -TableName 'GDAPMigration' $QueuedApps = Get-CIPPAzDataTableEntity @Table $CurrentStandards = foreach ($QueueFile in $QueuedApps) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPRoles.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPRoles.ps1 index 0102748cb4f8..f39e16ebd1fc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPRoles.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPRoles.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGDAPRoles { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -14,7 +16,7 @@ Function Invoke-ListGDAPRoles { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $Table = Get-CIPPTable -TableName 'GDAPRoles' + $Table = Get-CIPPTable -TableName 'GDAPRoles' $Groups = Get-CIPPAzDataTableEntity @Table $MappedGroups = foreach ($Group in $Groups) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsDeploy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsDeploy.ps1 index 4a43292deba6..091d903054b7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsDeploy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsDeploy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddStandardsDeploy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 index 27c8774bae3c..8e5186727b8f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddStandardsTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -22,7 +24,7 @@ Function Invoke-AddStandardsTemplate { } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created CA Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' $body = [pscustomobject]@{'Results' = 'Successfully added template' } - + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-BestPracticeAnalyser_List.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-BestPracticeAnalyser_List.ps1 index e1930a1cbc04..5bf7c40a6741 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-BestPracticeAnalyser_List.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-BestPracticeAnalyser_List.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-BestPracticeAnalyser_List { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.BestPracticeAnalyser.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -13,7 +15,7 @@ Function Invoke-BestPracticeAnalyser_List { $Tenants = Get-Tenants $Table = get-cipptable 'cachebpa' - $Results = (Get-CIPPAzDataTableEntity @Table) | ForEach-Object { + $Results = (Get-CIPPAzDataTableEntity @Table) | ForEach-Object { $_.UnusedLicenseList = @(ConvertFrom-Json -ErrorAction silentlycontinue -InputObject $_.UnusedLicenseList) $_ } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardsRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardsRun.ps1 index c205bf24d57b..f200e4729272 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardsRun.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardsRun.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecStandardsRun { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 0e632d4fba35..abdce86f9df5 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 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListBPA { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.BestPracticeAnalyser.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 index 2185772864cd..7f7c110fcd9f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListBPATemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.BestPracticeAnalyser.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 76fe08536529..95077930211f 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 @@ -4,7 +4,9 @@ using namespace System.Net Function Invoke-ListDomainAnalyser { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.DomainAnalyser.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 index dfbd46514448..fb04e3d547ca 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListDomainHealth.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListDomainHealth { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.DomainAnalyser.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 index acc984d6e0ab..1b17d33131a2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-listStandardTemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -11,11 +13,11 @@ Function Invoke-listStandardTemplates { $APIName = $TriggerMetadata.FunctionName $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'StandardsTemplate'" + $Filter = "PartitionKey eq 'StandardsTemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { $data = $_.JSON | ConvertFrom-Json -Depth 100 $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force - $data + $data } | Sort-Object -Property displayName # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/invoke-DomainAnalyser_List.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/invoke-DomainAnalyser_List.ps1 index e1c7c345e511..1682b8b30cd1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/invoke-DomainAnalyser_List.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/invoke-DomainAnalyser_List.ps1 @@ -4,7 +4,9 @@ using namespace System.Net Function Invoke-DomainAnalyser_List { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.DomainAnalyser.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -19,7 +21,7 @@ Function Invoke-DomainAnalyser_List { try { # Extract json from table results $Results = foreach ($DomainAnalyserResult in (Get-CIPPAzDataTableEntity @DomainTable).DomainAnalyser) { - try { + try { if (![string]::IsNullOrEmpty($DomainAnalyserResult)) { $Object = $DomainAnalyserResult | ConvertFrom-Json -ErrorAction SilentlyContinue $Object diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 index f04c365c5ccf..01e72df98868 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecGraphExplorerPreset { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 index c94b9ecf1ea2..00c2cffc02e7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-AddTenantAllowBlockList { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -20,10 +22,10 @@ Function Invoke-AddTenantAllowBlockList { tenantid = $Request.body.tenantid cmdlet = 'New-TenantAllowBlockListItems' cmdParams = @{ - Entries = [string[]]$blocklistobj.entries - ListType = [string]$blocklistobj.listType - Notes = [string]$blocklistobj.notes - $blocklistobj.listMethod = [bool]$true + Entries = [string[]]$blocklistobj.entries + ListType = [string]$blocklistobj.listType + Notes = [string]$blocklistobj.notes + $blocklistobj.listMethod = [bool]$true } } @@ -43,10 +45,10 @@ Function Invoke-AddTenantAllowBlockList { # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ - 'Results' = $result - 'Request' = $ExoRequest - } - }) + StatusCode = [HttpStatusCode]::OK + Body = @{ + 'Results' = $result + 'Request' = $ExoRequest + } + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 index 3f78672c9894..4bafafd3d374 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 @@ -3,16 +3,18 @@ using namespace System.Net Function Invoke-ExecExtensionNinjaOneQueue { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Extension.NinjaOne.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) - + Switch ($QueueItem.NinjaAction) { 'StartAutoMapping' { Invoke-NinjaOneOrgMapping } - 'AutoMapTenant' { Invoke-NinjaOneOrgMappingTenant -QueueItem $QueueItem } + 'AutoMapTenant' { Invoke-NinjaOneOrgMappingTenant -QueueItem $QueueItem } 'SyncTenant' { Invoke-NinjaOneTenantSync -QueueItem $QueueItem } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index d3695a00742f..1adc1799debd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -1,26 +1,28 @@ using namespace System.Net Function Invoke-ExecListAppId { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ResponseURL = "$(($Request.headers.'x-ms-original-url').replace('/api/ExecListAppId','/api/ExecSAMSetup'))" + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $ResponseURL = "$(($Request.headers.'x-ms-original-url').replace('/api/ExecListAppId','/api/ExecSAMSetup'))" - $Results = @{ - applicationId = $ENV:ApplicationID - tenantId = $ENV:TenantID - refreshUrl = "https://login.microsoftonline.com/$ENV:TenantID/oauth2/v2.0/authorize?client_id=$ENV:ApplicationID&response_type=code&redirect_uri=$ResponseURL&response_mode=query&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access+profile+openid&state=1&prompt=select_account" - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + $Results = @{ + applicationId = $ENV:ApplicationID + tenantId = $ENV:TenantID + refreshUrl = "https://login.microsoftonline.com/$ENV:TenantID/oauth2/v2.0/authorize?client_id=$ENV:ApplicationID&response_type=code&redirect_uri=$ResponseURL&response_mode=query&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access+profile+openid&state=1&prompt=select_account" + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 index a78905f8386a..403e4e3dcdfa 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 @@ -1,30 +1,32 @@ using namespace System.Net Function Invoke-ExecRestoreDeleted { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.ReadWrite #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter - try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($Request.query.ID)/restore" -tenantid $TenantFilter -type POST -body '{}' -verbose - $Results = [pscustomobject]@{'Results' = 'Successfully completed request.' } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } + try { + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($Request.query.ID)/restore" -tenantid $TenantFilter -type POST -body '{}' -verbose + $Results = [pscustomobject]@{'Results' = 'Successfully completed request.' } + } catch { + $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 index 2b4fd7d70190..6c373d6deaf4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSchedulerBillingRun.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSchedulerBillingRun { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Scheduler.Billing.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 index b70f200aae55..e5293d373605 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSendOrgMessage.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSendOrgMessage { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -81,7 +83,7 @@ Function Invoke-ExecSendOrgMessage { } }) }) - }) + }) } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSyncAPDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSyncAPDevices.ps1 index 0d5b9b9e253d..98dae4f0f308 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSyncAPDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSyncAPDevices.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSyncAPDevices { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 index eda323666fa1..f16a350fc2c6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecUniversalSearch { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 index ab9092f13c1d..ec1381e24e45 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 @@ -3,7 +3,9 @@ using namespace System.Net function Invoke-ExecUserSettings { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.ReadWrite #> param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 index d9d49840c7b4..31c3e5dd4675 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAllTenantDeviceCompliance.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAllTenantDeviceCompliance { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.DeviceCompliance.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -19,18 +21,18 @@ Function Invoke-ListAllTenantDeviceCompliance { $TenantFilter = $Request.Query.TenantFilter try { if ($TenantFilter -eq 'AllTenants') { - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances' - $StatusCode = [HttpStatusCode]::OK + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances' + $StatusCode = [HttpStatusCode]::OK } else { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances?`$top=999&`$filter=organizationId eq '$TenantFilter'" + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedDeviceCompliances?`$top=999&`$filter=organizationId eq '$TenantFilter'" $StatusCode = [HttpStatusCode]::OK } - if ($GraphRequest.value.count -lt 1) { + if ($GraphRequest.value.count -lt 1) { $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' + $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' } - } catch { + } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 index 1b6723d21c17..93a95f880983 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAppStatus { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Device.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 index 43ae12082452..1b4c8f4a1440 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAutopilotconfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 index f1b1b0592e76..0a02e1814601 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListAzureADConnectStatus { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -41,10 +43,10 @@ Function Invoke-ListAzureADConnectStatus { $GraphRequest = foreach ($Type in $types) { New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Type)?`$select=$($selectlist -join ',')" -tenantid $TenantFilter | ForEach-Object { if ($_.id -ne $null) { - $_ | Add-Member -NotePropertyName ObjectType -NotePropertyValue $Type + $_ | Add-Member -NotePropertyName ObjectType -NotePropertyValue $Type $_ } - + } } $ObjectsInError = @($GraphRequest) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 index 3bbefa764b84..9112981dad14 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListCalendarPermissions { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 index 768417a1db23..98544c614be7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListContacts { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Contacts.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 index 5b5a244c7e72..78a4f1bcbbf0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListDefenderState { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -19,11 +21,11 @@ Function Invoke-ListDefenderState { $TenantFilter = $Request.Query.TenantFilter try { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsProtectionStates?`$top=999&`$filter=tenantId eq '$TenantFilter'" - if ($GraphRequest.tenantDisplayName.length -lt 1) { + if ($GraphRequest.tenantDisplayName.length -lt 1) { $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' + $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' } - } catch { + } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 index 2011f161abaf..01e7cacb254f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListDefenderTVM { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -40,7 +42,7 @@ Function Invoke-ListDefenderTVM { $StatusCode = [HttpStatusCode]::Forbidden $GroupObj = $ErrorMessage } - # Associate values to output bindings by calling 'Push-OutputBinding'. + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode Body = @($GroupObj) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 index 2f3488655fa0..26d68ac580b7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListDeletedItems { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -19,7 +21,7 @@ Function Invoke-ListDeletedItems { $TenantFilter = $Request.Query.TenantFilter $Types = 'Application', 'User', 'Device', 'Group' $GraphRequest = foreach ($Type in $Types) { - (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | Where-Object -Property '@odata.context' -NotLike '*graph.microsoft.com*' | Select-Object *, @{ Name = 'TargetType'; Expression = { $Type } } + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | Where-Object -Property '@odata.context' -NotLike '*graph.microsoft.com*' | Select-Object *, @{ Name = 'TargetType'; Expression = { $Type } } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 index f3a4d9f309c9..1d561c958f65 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListDeviceDetails { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Device.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -28,7 +30,7 @@ Function Invoke-ListDeviceDetails { $Found = $False if ($SeriaNumber -and $DeviceName) { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial' and deviceName eq '$DeviceName'" -Tenantid $tenantfilter - + if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { $Found = $True } @@ -75,7 +77,7 @@ Function Invoke-ListDeviceDetails { $DeviceGroups = Get-GraphBulkResultByID -Results $BulkResults -ID 'DeviceGroups' -Value $CompliancePolicies = Get-GraphBulkResultByID -Results $BulkResults -ID 'CompliancePolicies' -Value - $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' + $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' $Null = $GraphRequest | Add-Member -NotePropertyName 'DetectedApps' -NotePropertyValue ($DetectedApps.DetectedApps | Select-Object id, displayName, version) $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue ($CompliancePolicies | Select-Object id, displayname, UserPrincipalName, state) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 index 113b9d53a304..149eb8fa9a04 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 @@ -1,35 +1,37 @@ using namespace System.Net Function Invoke-ListDomains { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Administration.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter - try { - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Select-Object id, isdefault, isinitial | Sort-Object isdefault - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + try { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | Select-Object id, isdefault, isinitial | Sort-Object isdefault + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 index 897fcf53b3ed..8c96c119f2f0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListExConnectorTemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -14,14 +16,14 @@ Function Invoke-ListExConnectorTemplates { #List new policies $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'ExConnectorTemplate'" + $Filter = "PartitionKey eq 'ExConnectorTemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { $GUID = $_.RowKey $Direction = $_.direction - $data = $_.JSON | ConvertFrom-Json + $data = $_.JSON | ConvertFrom-Json $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID $data | Add-Member -NotePropertyName 'cippconnectortype' -NotePropertyValue $Direction - $data + $data } | Sort-Object -Property displayName if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 index 35b1863f45f8..95120eab6ac6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListExchangeConnectors { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 index 5e9cd48198c8..ddff3b174b6a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListExtensionsConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Extension.Config.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 index 55fb22f3f99e..f5c773792ce2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListExternalTenantInfo { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 index 2be8941920f1..64c465e799e9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 @@ -3,7 +3,9 @@ using namespace System.Net function Invoke-ListFunctionParameters { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 index 7a0ca462e60e..037801e25962 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListFunctionStats { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 index ddb0c55b1444..32afe59ac176 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGenericAllTenants { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 index 80012cd30de9..8cfed503e5cb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGenericTestFunction { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 index 100aa6a450ba..1212c03efee0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGraphExplorerPresets { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 index cd0f73a61f45..4177e3e24368 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 @@ -2,10 +2,9 @@ function Invoke-ListGraphRequest { <# .FUNCTIONALITY - Entrypoint - + Entrypoint .ROLE - Core.Read + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 index 205410cd9f92..6a6bc6b12248 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGroupTemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Group.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -17,9 +19,9 @@ Function Invoke-ListGroupTemplates { #List new policies $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'GroupTemplate'" + $Filter = "PartitionKey eq 'GroupTemplate'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $data = $_.JSON | ConvertFrom-Json + $data = $_.JSON | ConvertFrom-Json $data | Add-Member -MemberType NoteProperty -Name GUID -Value $_.RowKey -Force $data } | Sort-Object -Property displayName diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 index d25ccd2c6d9f..b59ceae2fd06 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListGroups { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Group.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -20,16 +22,16 @@ Function Invoke-ListGroups { $TenantFilter = $Request.Query.TenantFilter $selectstring = "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,grouptypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&`$expand=members(`$select=userPrincipalName)" - if ($Request.Query.GroupID) { + if ($Request.Query.GroupID) { $groupid = $Request.query.groupid $selectstring = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,userPrincipalName' } - if ($Request.Query.members) { + if ($Request.Query.members) { $members = 'members' $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' } - if ($Request.Query.owners) { + if ($Request.Query.owners) { $members = 'owners' $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 index 84b1b3cae514..f129aebe7df3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 @@ -1,49 +1,51 @@ using namespace System.Net Function Invoke-ListHaloClients { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Extension.HaloPSA.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - try { - $Table = Get-CIPPTable -TableName Extensionsconfig - $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).HaloPSA - $Token = Get-HaloToken -configuration $Configuration - $i = 1 - $RawHaloClients = do { - $Result = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Client?page_no=$i&page_size=999&pageinate=true" -ContentType 'application/json' -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } - $Result.clients | Select-Object * -ExcludeProperty logo - $i++ - $pagecount = [Math]::Ceiling($Result.record_count / 999) - } while ($i -le $pagecount) - $HaloClients = $RawHaloClients | ForEach-Object { - [PSCustomObject]@{ - label = $_.name - value = $_.id - } - } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $HaloClients = $ErrorMessage + # Interact with query parameters or the body of the request. + try { + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).HaloPSA + $Token = Get-HaloToken -configuration $Configuration + $i = 1 + $RawHaloClients = do { + $Result = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Client?page_no=$i&page_size=999&pageinate=true" -ContentType 'application/json' -Method GET -Headers @{Authorization = "Bearer $($token.access_token)" } + $Result.clients | Select-Object * -ExcludeProperty logo + $i++ + $pagecount = [Math]::Ceiling($Result.record_count / 999) + } while ($i -le $pagecount) + $HaloClients = $RawHaloClients | ForEach-Object { + [PSCustomObject]@{ + label = $_.name + value = $_.id + } } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $HaloClients = $ErrorMessage + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($HaloClients) - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($HaloClients) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIPWhitelist.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIPWhitelist.ps1 index 985473bc5bb8..bf031cfb22a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIPWhitelist.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIPWhitelist.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListIPWhitelist { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 index 3ce42719c362..559543a51a67 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 @@ -1,36 +1,38 @@ using namespace System.Net Function Invoke-ListInactiveAccounts { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - if ($TenantFilter -eq 'AllTenants') { $TenantFilter = (get-tenants).customerId } - try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/inactiveUsers?`$count=true" -tenantid $env:TenantId | Where-Object { $_.tenantId -in $TenantFilter } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" - } + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter -eq 'AllTenants') { $TenantFilter = (get-tenants).customerId } + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/inactiveUsers?`$count=true" -tenantid $env:TenantId | Where-Object { $_.tenantId -in $TenantFilter } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 index cb98c87d6e67..b7043311731c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneIntents.ps1 @@ -1,35 +1,37 @@ using namespace System.Net Function Invoke-ListIntuneIntents { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/Intents?`$expand=settings,categories" -tenantid $TenantFilter - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - } + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + try { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/Intents?`$expand=settings,categories" -tenantid $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 index 5429292d5a6c..dbccf5a4004e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListIntunePolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -46,7 +48,7 @@ Function Invoke-ListIntunePolicy { default { $_.'assignments@odata.context' } } if ($_.displayname -eq $null) { $_ | Add-Member -NotePropertyName displayName -NotePropertyValue $_.name } - $_ | Add-Member -NotePropertyName PolicyTypeName -NotePropertyValue $policyTypeName + $_ | Add-Member -NotePropertyName PolicyTypeName -NotePropertyValue $policyTypeName $_ | Add-Member -NotePropertyName URLName -NotePropertyValue $URLName $_ } | Where-Object { $_.DisplayName -ne $null } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 index d9c02d090fb2..c94431612970 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListIntuneTemplates { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -36,7 +38,7 @@ Function Invoke-ListIntuneTemplates { $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force $data } | Sort-Object -Property displayName - } + } if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property guid -EQ $Request.query.id } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 index 061146ae725f..09f488be2304 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListKnownIPDb { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 index ead6a0d2cd9d..1fc0f4ca57e9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListLicenses { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index a3963bd0bc94..688e3e81695c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListLogs { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 index 118ca8d4b050..e73aa9205517 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMFAUsers { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 index ef93210d4c25..4386157564d4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMailboxCAS { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices copy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices copy.ps1 deleted file mode 100644 index 8199d4204326..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices copy.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -using namespace System.Net - -Function Invoke-ListMailboxMobileDevices { - <# - .FUNCTIONALITY - Entrypoint - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $Mailbox = $Request.Query.Mailbox - - Write-Host $TenantFilter - Write-Host $Mailbox - - $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Mailbox) - $base64IdentityParam = [Convert]::ToBase64String($Bytes) - - try { - $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline | Select-Object @{ Name = 'clientType'; Expression = { $_.ClientType } }, - @{ Name = 'clientVersion'; Expression = { $_.ClientVersion } }, - @{ Name = 'deviceAccessState'; Expression = { $_.DeviceAccessState } }, - @{ Name = 'deviceFriendlyName'; Expression = { if ([string]::IsNullOrEmpty($_.DeviceFriendlyName)) { 'Unknown' }else { $_.DeviceFriendlyName } } }, - @{ Name = 'deviceModel'; Expression = { $_.DeviceModel } }, - @{ Name = 'deviceOS'; Expression = { $_.DeviceOS } }, - @{ Name = 'deviceType'; Expression = { $_.DeviceType } }, - @{ Name = 'firstSync'; Expression = { $_.FirstSyncTime.toString() } }, - @{ Name = 'lastSyncAttempt'; Expression = { $_.LastSyncAttemptTime.toString() } }, - @{ Name = 'lastSuccessSync'; Expression = { $_.LastSuccessSync.toString() } }, - @{ Name = 'status'; Expression = { $_.Status } }, - @{ Name = 'deviceID'; Expression = { $_.deviceID } }, - @{ Name = 'Guid'; Expression = { $_.Guid } } - - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 index 8199d4204326..d1bab545e7a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMailboxMobileDevices { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRestores.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRestores.ps1 index f47458585c09..35d44175e0a5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRestores.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRestores.ps1 @@ -1,4 +1,10 @@ function Invoke-ListMailboxRestores { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.Read + #> param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 index 696369dc8c38..e5bd0a1530c9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMailboxRules { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxStatistics.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxStatistics.ps1 index d1f1af749fb7..795812096c50 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxStatistics.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxStatistics.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMailboxStatistics { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 index c924a85ea1dd..7a125550426a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListMailboxes { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 index 0acac97628d5..c1fb2e5c731a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNamedLocations.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListNamedLocations { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -18,7 +20,7 @@ Function Invoke-ListNamedLocations { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter try { - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -Tenantid $tenantfilter | Select-Object *, + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -Tenantid $tenantfilter | Select-Object *, @{ name = 'rangeOrLocation' expression = { if ($_.ipRanges) { $_.ipranges.cidrAddress -join ', ' } else { $_.countriesAndRegions -join ', ' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 index 68545565ee6b..1f3426888c33 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListNotificationConfig { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 index 13fafdf39a2c..2183317e991d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 @@ -1,54 +1,56 @@ using namespace System.Net Function Invoke-ListOAuthApps { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Application.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - if ($TenantFilter -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $tenants = $TenantFilter } - - try { - $GraphRequest = foreach ($Tenant in $Tenants) { - try { - $ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=id,displayName,appid" -tenantid $Tenant - New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/oauth2PermissionGrants' -tenantid $Tenant | ForEach-Object { - $CurrentServicePrincipal = ($ServicePrincipals | Where-Object -Property id -EQ $_.clientId) - [PSCustomObject]@{ - Tenant = $Tenant - Name = $CurrentServicePrincipal.displayName - ApplicationID = $CurrentServicePrincipal.appid - ObjectID = $_.clientId - Scope = ($_.scope -join ',') - StartTime = $_.startTime - } - } - $StatusCode = [HttpStatusCode]::OK - } catch { - continue - } + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $tenants = $TenantFilter } + + try { + $GraphRequest = foreach ($Tenant in $Tenants) { + try { + $ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=id,displayName,appid" -tenantid $Tenant + New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/oauth2PermissionGrants' -tenantid $Tenant | ForEach-Object { + $CurrentServicePrincipal = ($ServicePrincipals | Where-Object -Property id -EQ $_.clientId) + [PSCustomObject]@{ + Tenant = $Tenant + Name = $CurrentServicePrincipal.displayName + ApplicationID = $CurrentServicePrincipal.appid + ObjectID = $_.clientId + Scope = ($_.scope -join ',') + StartTime = $_.startTime + } } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage + $StatusCode = [HttpStatusCode]::OK + } catch { + continue + } } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOrg.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOrg.ps1 index 20842ce9dafb..feb6de0d2f74 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOrg.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOrg.ps1 @@ -1,32 +1,34 @@ using namespace System.Net Function Invoke-ListOrg { - <# + <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Core.Read #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - if ($TenantFilter -eq 'AllTenants') { - - } else { - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $TenantFilter - } + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter -eq 'AllTenants') { - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $GraphRequest - }) + } else { + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $TenantFilter + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $GraphRequest + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 index 591b6b23d3bf..6ca16cfe8fd9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPartnerRelationships.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListPartnerRelationships { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Relationship.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 index 24c7020f0e31..96c4a6eeb13a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListPendingWebhooks { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 index 86062e4e80fa..0dfbeaa01642 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPotentialApps.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListPotentialApps { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 index 6eca5db05c5b..9f17fde986f1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListRoles { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Directory.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -21,7 +23,7 @@ Function Invoke-ListRoles { [System.Collections.Generic.List[PSCustomObject]]$Roles = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/directoryRoles?`$expand=members" -tenantid $TenantFilter $GraphRequest = foreach ($Role in $Roles) { - + #[System.Collections.Generic.List[PSCustomObject]]$Members = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directoryRoles/$($Role.id)/members?`$select=$($selectlist -join ',')" -tenantid $TenantFilter | Select-Object $SelectList $Members = if ($Role.members) { $role.members | ForEach-Object { " $($_.displayName) ($($_.userPrincipalName))" } } else { 'none' } [PSCustomObject]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 index 74148522dec5..6f586800d8d0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListRoomLists { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Room.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -20,9 +22,9 @@ Function Invoke-ListRoomLists { try { $params = @{ - uri = 'https://graph.microsoft.com/beta/places/microsoft.graph.roomlist' + uri = 'https://graph.microsoft.com/beta/places/microsoft.graph.roomlist' tenantid = $TenantFilter - AsApp = $true + AsApp = $true } $GraphRequest = New-GraphGetRequest @params diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRooms.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRooms.ps1 index 4e2f57124129..34074ce76c3c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRooms.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRooms.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListRooms { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Room.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 index 1c497fb40f9e..d9242a3e29a3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListServiceHealth { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Administration.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 index 683f05eed5a1..4467289996ab 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSharedMailboxAccountEnabled { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -27,18 +29,18 @@ Function Invoke-ListSharedMailboxAccountEnabled { if ($User.accountEnabled) { $User | Select-Object ` @{Name = 'UserPrincipalName'; Expression = { $User.UserPrincipalName } }, ` - @{Name = 'displayName'; Expression = { $User.displayName } }, - @{Name = 'givenName'; Expression = { $User.givenName } }, - @{Name = 'surname'; Expression = { $User.surname } }, + @{Name = 'displayName'; Expression = { $User.displayName } }, + @{Name = 'givenName'; Expression = { $User.givenName } }, + @{Name = 'surname'; Expression = { $User.surname } }, @{Name = 'accountEnabled'; Expression = { $User.accountEnabled } }, @{Name = 'id'; Expression = { $User.id } }, @{Name = 'onPremisesSyncEnabled'; Expression = { $User.onPremisesSyncEnabled } } - + } } } catch { - Write-LogMessage -API 'Tenant' -tenant $tenantfilter -message "Shared Mailbox Enabled Accounts on $($tenantfilter). Error: $($_.exception.message)" -sev 'Error' + Write-LogMessage -API 'Tenant' -tenant $tenantfilter -message "Shared Mailbox Enabled Accounts on $($tenantfilter). Error: $($_.exception.message)" -sev 'Error' } $GraphRequest = $EnabledUsersWithSharedMailbox diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 index 387d82b3f6dd..4b16ac630c80 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSharedMailboxStatistics { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 index b1a7dc2236ab..b8d7d8a50995 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListSharepointQuota { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Sharepoint.Admin.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 index debfb0931ac0..b58f472a7494 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 @@ -3,12 +3,14 @@ using namespace System.Net Function Invoke-ListSignIns { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.AuditLog.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) - + # Write to the Azure Functions log stream. 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' @@ -18,8 +20,8 @@ Function Invoke-ListSignIns { if ($Request.query.failedlogonOnly) { $FailedLogons = ' and (status/errorCode eq 50126)' } - - $filters = if ($Request.query.Filter) { + + $filters = if ($Request.query.Filter) { $request.query.filter } else { $currentTime = Get-Date -Format 'yyyy-MM-dd' @@ -30,12 +32,12 @@ Function Invoke-ListSignIns { Write-Host $Filters $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?api-version=beta&`$filter=$($filters)" -tenantid $TenantFilter -erroraction stop - $response = $GraphRequest | Select-Object *, + $response = $GraphRequest | Select-Object *, @{l = 'additionalDetails'; e = { $_.status.additionalDetails } } , @{l = 'errorCode'; e = { $_.status.errorCode } }, - @{l = 'locationcipp'; e = { "$($_.location.city) - $($_.location.countryOrRegion)" } } + @{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 - + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 index ef3e205c8467..dd39cb4ac683 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListStandards { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 index 63c59971f13c..d67651c0bc3f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListTenantAllowBlockList { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 index d855df71778b..41f16aba1e48 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ListmailboxPermissions { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -21,9 +23,9 @@ Function Invoke-ListmailboxPermissions { Write-Host "Tenant Filter: $TenantFilter" try { $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) - $base64IdentityParam = [Convert]::ToBase64String($Bytes) - $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($Request.Query.UserID)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline - $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline + $base64IdentityParam = [Convert]::ToBase64String($Bytes) + $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($Request.Query.UserID)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline + $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline $PermRequest3 = New-ExoRequest -Anchor $Request.Query.UserID -tenantid $Tenantfilter -cmdlet 'Get-Mailbox' -cmdParams @{Identity = $($Request.Query.UserID); } $GraphRequest = foreach ($Perm in $PermsRequest, $PermsRequest2.RecipientPermission, $PermRequest3) { @@ -34,20 +36,20 @@ Function Invoke-ListmailboxPermissions { Permissions = $_.accessRights } } - + } if ($perm.PermissionList) { $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ User = $_.User Permissions = $_.PermissionList.accessRights -join ', ' - } + } } } if ($perm.GrantSendonBehalfTo -ne $null) { $perm.GrantSendonBehalfTo | ForEach-Object { [PSCustomObject]@{ User = $_ Permissions = 'SendOnBehalf' - } + } } } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 index 37136c230bdd..105bdf0df0d8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 @@ -3,12 +3,12 @@ using namespace System.Net Function Invoke-PublicPhishingCheck { <# .FUNCTIONALITY - Entrypoint + Entrypoint #> [CmdletBinding()] param($Request, $TriggerMetadata) Write-Host ($request | ConvertTo-Json) - + # List valid referers $validList = @( 'https://login.microsoftonline.com', @@ -25,20 +25,20 @@ Function Invoke-PublicPhishingCheck { Write-Host 'Not being Phished, no issue' } else { $bytes = [Convert]::FromBase64String('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') - + $AlertMessage = If ($Request.headers.referer) { - "Potential Phishing page detected. Detected Information: Hosted at $($Request.headers.referer). Access by IP $($request.headers.'x-forwarded-for')" + "Potential Phishing page detected. Detected Information: Hosted at $($Request.headers.referer). Access by IP $($request.headers.'x-forwarded-for')" } else { - "Potential Phishing page detected. Detected Information: Access by IP $($request.headers.'x-forwarded-for')" + "Potential Phishing page detected. Detected Information: Access by IP $($request.headers.'x-forwarded-for')" } - Write-AlertMessage -message $AlertMessage -sev 'Alert' -tenant $Request.query.TenantId + Write-AlertMessage -message $AlertMessage -sev 'Alert' -tenant $Request.query.TenantId } - + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK ContentType = 'image/png' - Body = $bytes + Body = $bytes }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 index d9f99772b4d8..52807bdcc27f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveTenantAllowBlockList { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.SpamFilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 b/Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 new file mode 100644 index 000000000000..bc66128c7b68 --- /dev/null +++ b/Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 @@ -0,0 +1,37 @@ +function Get-CIPPHttpFunctions { + Param( + [switch]$ByRole, + [switch]$ByRoleGroup + ) + + try { + $Functions = Get-Command -Module CippCore | Where-Object { $_.Visibility -eq 'Public' -and $_.Name -match 'Invoke-*' } + $Results = foreach ($Function in $Functions) { + $Help = Get-Help $Function + if ($Help.Functionality -ne 'Entrypoint') { continue } + [PSCustomObject]@{ + Function = $Function.Name + Role = $Help.Role + } + } + + if ($ByRole.IsPresent -or $ByRoleGroup.IsPresent) { + $Results = $Results | Group-Object -Property Role | Select-Object -Property @{l = 'Permission'; e = { $_.Name -eq '' ? 'None' : $_.Name } }, Count, @{l = 'Functions'; e = { $_.Group.Function -replace 'Invoke-' } } + + if ($ByRoleGroup.IsPresent) { + $RoleGroup = @{} + foreach ($Permission in $Results) { + $PermSplit = $Permission.Permission -split '\.' + if ($PermSplit.Count -ne 3) { continue } + if ($RoleGroup[$PermSplit[0]] -eq $null) { $RoleGroup[$PermSplit[0]] = @{} } + if ($RoleGroup[$PermSplit[0]][$PermSplit[1]] -eq $null) { $RoleGroup[$PermSplit[0]][$PermSplit[1]] = @{} } + $RoleGroup[$PermSplit[0]][$PermSplit[1]][$PermSplit[2]] = $Permission.Functions + } + $Results = $RoleGroup + } + } + $Results + } catch { + "Function Error $($_.Exception.Message): $($_.InvocationInfo.PositionMessage)" + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 index 8639d495321d..1c474b20a44f 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveAPDevice { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Autopilot.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 index f0ca41db08a0..b154d77568eb 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 index 8cef68c26155..da878e3dbba2 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveCAPolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 index 318184576061..7ff2f2bf5df8 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveCATemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 index c4a47e9b182a..fc34c0073005 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveContact { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Contact.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 index f16befc4906b..79b201c068b4 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveExConnector { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -11,9 +13,9 @@ Function Invoke-RemoveExConnector { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Tenantfilter = $request.Query.tenantfilter - + try { - + $Params = @{ Identity = $request.query.GUID } $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Remove-$($Request.query.Type)Connector" -cmdParams $params -useSystemMailbox $true $Result = "Deleted $($Request.query.guid)" diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 index 3e78057683d9..b12df6a3d0aa 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveExConnectorTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Connector.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 index 2efd9d639307..85e4346a2b81 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveGroupTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.Group.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 index 4575cf0fe57a..f1b2c51ca2bf 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveIntuneTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 b/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 index 58cc90823d16..c7805fb46a48 100644 --- a/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemovePolicy { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.MEM.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 index add290577208..1e1d3fd4de14 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveQueuedApp { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Endpoint.Application.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 index e962aab4a7a4..a1b05e12c312 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveSpamfilter { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 index 8008d3b11a18..eaa19ff08df6 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveSpamfilterTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 index d3898d337a73..88d7f21e3212 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveStandard { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 index e95f74ecd11e..b7c11bd2d584 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveStandardTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Tenant.Standards.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 index b340f331903f..3a86c418314d 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveTransportRule { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 index 952796e819d8..3510d02b34a2 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveTransportRuleTemplate { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.TransportRule.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 index 386ab3e4be6b..040278ba9d80 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveUser { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Identity.User.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 index 0e9a92ac7868..e2a0b4d3bce2 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveWebhookAlert.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-RemoveWebhookAlert { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + CIPP.Alert.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -13,7 +15,7 @@ Function Invoke-RemoveWebhookAlert { $Table = get-cipptable -TableName 'SchedulerConfig' try { - $WebhookTable = Get-CIPPTable -TableName SchedulerConfig + $WebhookTable = Get-CIPPTable -TableName SchedulerConfig $WebhookRow = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq 'WebhookAlert'" | Where-Object -Property Tenant -EQ $Request.query.TenantFilter Write-Host "The webhook count is $($WebhookRow.count)" if ($WebhookRow.count -gt 1) { @@ -37,7 +39,7 @@ Function Invoke-RemoveWebhookAlert { } else { $Tenants = $Request.query.TenantFilter } - + $Results = foreach ($Tenant in $Tenants) { Remove-CIPPGraphSubscription -TenantFilter $Tenant -Type 'AuditLog' $Entity = $WebhookRow | Where-Object -Property RowKey -EQ $Request.query.ID From 551ba24c8b231ce8ce5a38185bdba69e3b07bf98 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 27 May 2024 11:25:20 -0400 Subject: [PATCH 025/138] switch BPA to fan out --- BestPracticeAnalyser_OrchestrationStarter/run.ps1 | 1 - BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 | 1 - 2 files changed, 2 deletions(-) diff --git a/BestPracticeAnalyser_OrchestrationStarter/run.ps1 b/BestPracticeAnalyser_OrchestrationStarter/run.ps1 index aba14651622b..0afc6fdc07e0 100644 --- a/BestPracticeAnalyser_OrchestrationStarter/run.ps1 +++ b/BestPracticeAnalyser_OrchestrationStarter/run.ps1 @@ -32,7 +32,6 @@ $InputObject = [PSCustomObject]@{ Batch = @($BPAReports) OrchestratorName = 'BPAOrchestrator' SkipLog = $true - DurableMode = 'Sequence' } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) diff --git a/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 b/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 index 6c34fc501c62..f111844160d4 100644 --- a/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 +++ b/BestPracticeAnalyser_OrchestrationStarterTimer/run.ps1 @@ -31,6 +31,5 @@ $InputObject = [PSCustomObject]@{ Batch = @($BPAReports) OrchestratorName = 'BPAOrchestrator' SkipLog = $true - DurableMode = 'Sequence' } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) From d7c2d73e5c283fc27d28ac7829e1371f3c03b8a6 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 28 May 2024 12:12:48 +0200 Subject: [PATCH 026/138] improvements to autopilot. --- .../Endpoint/Autopilot/Invoke-AddAPDevice.ps1 | 33 +++++++++++-------- .../GraphHelper/New-GraphPOSTRequest.ps1 | 10 ++++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 index 5e109b7d0a8c..b9ff114c5ffd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 @@ -18,25 +18,32 @@ Function Invoke-AddAPDevice { Write-Host 'PowerShell HTTP trigger function processed a request.' $TenantFilter = (Get-Tenants | Where-Object { $_.defaultDomainName -eq $Request.body.TenantFilter }).customerId $GroupName = if ($Request.body.Groupname) { $Request.body.Groupname } else { (New-Guid).GUID } + Write-Host $GroupName $rawDevices = $request.body.autopilotData $Devices = ConvertTo-Json @($rawDevices) - Write-Host $Devices $Result = try { $CurrentStatus = (New-GraphgetRequest -uri "https://api.partnercenter.microsoft.com/v1/customers/$tenantfilter/DeviceBatches" -scope 'https://api.partnercenter.microsoft.com/user_impersonation') - if ($groupname -in $CurrentStatus.items.id) { throw 'This device batch name already exists. Please try with another name.' } + if ($groupname -in $CurrentStatus.items.id) { throw 'This device batch name already exists. The batch name must be unique.' } $body = '{"batchId":"' + $($GroupName) + '","devices":' + $Devices + '}' - $GraphRequest = (New-GraphPostRequest -uri "https://api.partnercenter.microsoft.com/v1/customers/$TenantFilter/DeviceBatches" -body $body -scope 'https://api.partnercenter.microsoft.com/user_impersonation') - Write-Host ($GraphRequest | ConvertTo-Json) - Start-Sleep 5 - $NewStatus = New-GraphgetRequest -uri "https://api.partnercenter.microsoft.com/v1/customers/$tenantfilter/DeviceBatches" -scope 'https://api.partnercenter.microsoft.com/user_impersonation' - Write-Host $($Newstatus | ConvertTo-Json) - if ($Newstatus.totalcount -eq $CurrentStatus.totalcount) { throw 'We could not find the new autopilot device. Please check if your input is correct.' } - Write-Host $CurrentStatus.Items + $GraphRequest = (New-GraphPostRequest -returnHeaders $true -uri "https://api.partnercenter.microsoft.com/v1/customers/$TenantFilter/DeviceBatches" -body $body -scope 'https://api.partnercenter.microsoft.com/user_impersonation') + $Amount = 0 + do { + Write-Host "Checking status of import job for $GroupName" + $amount ++ + Start-Sleep 1 + $NewStatus = New-GraphgetRequest -uri "https://api.partnercenter.microsoft.com/v1/$($GraphRequest.Location)" -scope 'https://api.partnercenter.microsoft.com/user_impersonation' + } until ($Newstatus.status -eq 'finished' -or $amount -eq 4) + if ($NewStatus.status -ne 'finished') { throw 'Could not retrieve status of import - This job might still be running. Check the autopilot device list in 10 minutes for the latest status.' } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($Request.body.TenantFilter) -message "Created Autopilot devices group. Group ID is $GroupName" -Sev 'Info' - "Created Autopilot devices group for $($Request.body.TenantFilter). Group ID is $GroupName" - } - catch { - "$($Request.body.TenantFilter): Failed to create autopilot devices. $($_.Exception.Message)" + [PSCustomObject]@{ + Status = 'Import Job Completed' + Devices = @($NewStatus.devicesStatus) + } + } catch { + [PSCustomObject]@{ + Status = "$($Request.body.TenantFilter): Failed to create autopilot devices. $($_.Exception.Message)" + Devices = @() + } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($Request.body.TenantFilter) -message "Failed to create autopilot devices. $($_.Exception.Message)" -Sev 'Error' } diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 index dfbb5445c5e8..753a47922b66 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 @@ -1,5 +1,5 @@ -function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $NoAuthCheck, $skipTokenCache, $AddedHeaders, $contentType, $IgnoreErrors = $false) { +function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $NoAuthCheck, $skipTokenCache, $AddedHeaders, $contentType, $IgnoreErrors = $false, $returnHeaders = $false) { <# .FUNCTIONALITY Internal @@ -20,7 +20,7 @@ function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $N $contentType = 'application/json; charset=utf-8' } try { - $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType $contentType -SkipHttpErrorCheck:$IgnoreErrors) + $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType $contentType -SkipHttpErrorCheck:$IgnoreErrors -ResponseHeadersVariable responseHeaders) } catch { $Message = if ($_.ErrorDetails.Message) { Get-NormalizedError -Message $_.ErrorDetails.Message @@ -29,7 +29,11 @@ function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $N } throw $Message } - return $ReturnedData + if ($returnHeaders) { + return $responseHeaders + } else { + return $ReturnedData + } } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } From 0912865f630f5eee5e276a1345fab6e7deba62d0 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 28 May 2024 12:24:33 +0200 Subject: [PATCH 027/138] increased timeout for tenant cache rebuild --- .../Activity Triggers/Push-ExecOnboardTenantQueue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 index 78223a4bdf93..3e597fab6553 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 @@ -278,7 +278,7 @@ Function Push-ExecOnboardTenantQueue { $Tenant = Get-Tenants -TriggerRefresh -IncludeAll | Where-Object { $_.customerId -eq $Relationship.customer.tenantId } | Select-Object -First 1 $y++ Start-Sleep -Seconds 20 - } while (!$Tenant -and $y -le 4) + } while (!$Tenant -and $y -le 10) if ($Tenant) { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Tenant found in customer list' }) From 980ded9c74ddf2d68118bbc21f1973a24ed13fa4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 28 May 2024 17:55:13 +0200 Subject: [PATCH 028/138] fix casing issues --- .../Activity Triggers/Push-ExecScheduledCommand.ps1 | 8 +++++--- .../Administration/Users/Invoke-ExecOffboardUser.ps1 | 7 ++++--- Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 | 8 +++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index b75de4bd1d4d..f254651b2165 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -4,16 +4,17 @@ function Push-ExecScheduledCommand { Entrypoint #> param($Item) - Write-Host "We are going to be running a scheduled task: $($Item.TaskInfo | ConvertTo-Json)" + Write-Host "We are going to be running a scheduled task: $($Item.TaskInfo | ConvertTo-Json -Depth 10)" $Table = Get-CippTable -tablename 'ScheduledTasks' $task = $Item.TaskInfo - $commandParameters = $Item.Parameters | ConvertTo-Json | ConvertFrom-Json -AsHashtable + $commandParameters = $Item.Parameters | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashtable $tenant = $Item.Parameters['TenantFilter'] Write-Host "Started Task: $($Item.Command) for tenant: $tenant" try { try { + Write-Host "Starting task: $($Item.Command) with parameters: " $results = & $Item.Command @commandParameters } catch { $results = "Task Failed: $($_.Exception.Message)" @@ -79,7 +80,8 @@ function Push-ExecScheduledCommand { } Write-Host 'Sent the results to the target. Updating the task state.' - if ($task.Recurrence -eq '0' -or $task.Recurrence -eq $null) { + if ($task.Recurrence -eq '0' -or [string]::IsNullOrEmpty($task.Recurrence)) { + Write-Host 'Recurrence empty or 0. Task is not recurring. Setting task state to completed.' Update-AzDataTableEntity @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 index 7142cb3ca837..0bf9feaf3dff 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 @@ -24,9 +24,10 @@ Function Invoke-ExecOffboardUser { value = 'Invoke-CIPPOffboardingJob' } Parameters = @{ - Username = $Username - APIName = 'Scheduled Offboarding' - options = $request.body + Username = $Username + APIName = 'Scheduled Offboarding' + options = $request.body + RunScheduled = $true } ScheduledTime = $Request.body.scheduled.date PostExecution = @{ diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 index 0d45ac6311df..533d0954679a 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 @@ -13,6 +13,7 @@ function Invoke-CIPPOffboardingJob { $Options = $Options | ConvertFrom-Json } $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)" -tenantid $Tenantfilter).id + Write-Host "Running offboarding job for $username with options: $($Options | ConvertTo-Json -Depth 10)" $Return = switch ($Options) { { $_.'ConvertToShared' -eq 'true' } { Set-CIPPMailboxType -ExecutingUser $ExecutingUser -tenantFilter $tenantFilter -userid $username -username $username -MailboxType 'Shared' -APIName $APIName @@ -59,14 +60,15 @@ function Invoke-CIPPOffboardingJob { Remove-CIPPUser -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_.'RemoveRules' -eq 'true' } { + { $_.'removeRules' -eq 'true' } { + Write-Host "Removing rules for $username" Remove-CIPPRules -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_.'RemoveMobile' -eq 'true' } { + { $_.'removeMobile' -eq 'true' } { Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName } - { $_.'RemovePermissions' } { + { $_.'removePermissions' } { if ($RunScheduled) { Remove-CIPPMailboxPermissions -PermissionsLevel @('FullAccess', 'SendAs', 'SendOnBehalf') -userid 'AllUsers' -AccessUser $UserName -TenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $ExecutingUser From 992135e5a2d5ebca86e909daf95d1fb04ed0340b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Tue, 28 May 2024 20:52:33 +0200 Subject: [PATCH 029/138] we need to go deeper --- .../Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 1fe3b38b1825..d01025dc080a 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 @@ -46,18 +46,18 @@ Function Invoke-AddIntuneTemplate { $Type = 'deviceCompliancePolicies' $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)/$($ID)?`$expand=scheduledActionsForRule(`$expand=scheduledActionConfigurations)" -tenantid $tenantfilter $DisplayName = $Template.displayName - $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 10 -Compress + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress } 'managedAppPolicies' { $Type = 'AppProtection' $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$($urlname)('$($ID)')" -tenantid $tenantfilter $DisplayName = $Template.displayName - $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 10 -Compress + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress } 'configurationPolicies' { $Type = 'Catalog' $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)('$($ID)')?`$expand=settings" -tenantid $tenantfilter | Select-Object name, description, settings, platforms, technologies, templateReference - $TemplateJson = $Template | ConvertTo-Json -Depth 10 + $TemplateJson = $Template | ConvertTo-Json -Depth 100 $DisplayName = $Template.name @@ -67,7 +67,7 @@ Function Invoke-AddIntuneTemplate { $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)/$($ID)" -tenantid $tenantfilter | Select-Object * -ExcludeProperty id, lastModifiedDateTime, '@odata.context', 'ScopeTagIds', 'supportsScopeTags', 'createdDateTime' Write-Host ($Template | ConvertTo-Json) $DisplayName = $Template.displayName - $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 10 -Compress + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress } 'groupPolicyConfigurations' { $Type = 'Admin' @@ -102,7 +102,7 @@ Function Invoke-AddIntuneTemplate { } - $TemplateJson = (ConvertTo-Json -InputObject $inputvar -Depth 15 -Compress) + $TemplateJson = (ConvertTo-Json -InputObject $inputvar -Depth 100 -Compress) } } From 714e051110cb4c4ba1b8fbf55ee3dbc4ad78b211 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 May 2024 20:12:51 -0400 Subject: [PATCH 030/138] Custom Roles --- .../Get-CIPPHttpFunctions.ps1 | 2 +- .../Get-CIPPRolePermissions.ps1 | 29 ++++++++ .../Public/Authentication/Test-CIPPAccess.ps1 | 71 +++++++++++++++++++ .../Scheduler/Invoke-ListScheduledItems.ps1 | 4 ++ .../Settings/Invoke-ExecAPIPermissionList.ps1 | 17 +++++ .../CIPP/Settings/Invoke-ExecCustomRole.ps1 | 52 ++++++++++++++ .../Invoke-Z_CIPPHttpTrigger.ps1 | 28 -------- .../Alerts/Invoke-ListAlertsQueue.ps1 | 26 ++++++- .../Tenant/Invoke-ListTenants.ps1 | 11 ++- .../Tenant/Standards/Invoke-ListBPA.ps1 | 5 ++ .../Entrypoints/Invoke-ListContacts.ps1 | 2 +- .../Public/Entrypoints/Invoke-ListLogs.ps1 | 11 +++ Modules/CippEntrypoints/CippEntrypoints.psm1 | 37 ++++++++-- 13 files changed, 254 insertions(+), 41 deletions(-) rename Modules/CIPPCore/Public/{ => Authentication}/Get-CIPPHttpFunctions.ps1 (95%) create mode 100644 Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 create mode 100644 Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAPIPermissionList.ps1 create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 delete mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-Z_CIPPHttpTrigger.ps1 diff --git a/Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 similarity index 95% rename from Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 rename to Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 index bc66128c7b68..477f092a446c 100644 --- a/Modules/CIPPCore/Public/Get-CIPPHttpFunctions.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 @@ -16,7 +16,7 @@ function Get-CIPPHttpFunctions { } if ($ByRole.IsPresent -or $ByRoleGroup.IsPresent) { - $Results = $Results | Group-Object -Property Role | Select-Object -Property @{l = 'Permission'; e = { $_.Name -eq '' ? 'None' : $_.Name } }, Count, @{l = 'Functions'; e = { $_.Group.Function -replace 'Invoke-' } } + $Results = $Results | Group-Object -Property Role | Select-Object -Property @{l = 'Permission'; e = { $_.Name -eq '' ? 'None' : $_.Name } }, Count, @{l = 'Functions'; e = { $_.Group.Function -replace 'Invoke-' } } | Sort-Object -Property Permission if ($ByRoleGroup.IsPresent) { $RoleGroup = @{} diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 new file mode 100644 index 000000000000..03bff3901fb1 --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 @@ -0,0 +1,29 @@ +function Get-CIPPRolePermissions { + <# + .SYNOPSIS + Get the permissions associated with a role. + .PARAMETER RoleName + The role to get the permissions for. + .EXAMPLE + Get-CIPPRolePermissions -RoleName 'mycustomrole' + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$RoleName + ) + + $Table = Get-CippTable -tablename 'CustomRoles' + $Filter = "RowKey eq '$RoleName'" + $Role = Get-CIPPAzDataTableEntity @Table -Filter $Filter + if ($Role) { + $Permissions = $Role.Permissions | ConvertFrom-Json + [PSCustomObject]@{ + Role = $Role.RowKey + Permissions = $Permissions.PSObject.Properties.Value + AllowedTenants = $Role.AllowedTenants | ConvertFrom-Json + } + } else { + Write-Error "Role $RoleName not found." + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 new file mode 100644 index 000000000000..332f4c06cf9a --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -0,0 +1,71 @@ +function Test-CIPPAccess { + param( + $Request, + [switch]$TenantList + ) + $DefaultRoles = @('admin', 'editor', 'readonly', 'anonymous', 'authenticated') + $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json + if ($User.userRoles -contains 'admin' -or $User.userRoles -contains 'superadmin') { + if ($TenantList.IsPresent) { + return @('AllTenants') + } + return $true + } + $CustomRoles = $User.userRoles | ForEach-Object { + if ($DefaultRoles -notcontains $_) { + $_ + } + } + if (($CustomRoles | Measure-Object).Count -gt 0 ) { + $Tenants = Get-Tenants -IncludeErrors + $APIAllowed = $false + $TenantAllowed = $false + $PermissionSet = foreach ($CustomRole in $CustomRoles) { + Get-CIPPRolePermissions -Role $CustomRole + } + if ($TenantList.IsPresent) { + $AllowedTenants = foreach ($Permission in $PermissionSet) { + foreach ($Tenant in $Permission.AllowedTenants) { + $Tenant + } + } + return $AllowedTenants + } + $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint + $Help = Get-Help $FunctionName + $APIRole = $Help.Role + foreach ($Role in $PermissionSet) { + foreach ($Perm in $Role.Permissions) { + if ($Perm -match $APIRole) { + $APIAllowed = $true + break + } + } + if ($APIAllowed) { + if ($Role.AllowedTenants -contains 'AllTenants') { + $TenantAllowed = $true + } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { + $TenantAllowed = $false + } else { + $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId + + if ($Tenant) { + $TenantAllowed = $Role.AllowedTenants -contains $Tenant + } else { + $TenantAllowed = $true + } + } + if ($TenantAllowed) { + return $true + } else { + throw 'Access to this tenant is not allowed' + } + } + } + if (!$APIAllowed) { + throw "Access to this API is not allowed, required role: $APIRole" + } + } else { + return $true + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 index d0f3869560a2..98e51126ed22 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 @@ -19,6 +19,10 @@ Function Invoke-ListScheduledItems { $HiddenTasks = $true } $Tasks = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask'" | Where-Object { $_.Hidden -ne $HiddenTasks } + $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList + if ($AllowedTenants -notcontains 'AllTenants') { + $Tasks = $Tasks | Where-Object -Property TenantId -In $AllowedTenants + } $ScheduledTasks = foreach ($Task in $tasks) { $Task.Parameters = $Task.Parameters | ConvertFrom-Json $Task diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAPIPermissionList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAPIPermissionList.ps1 new file mode 100644 index 000000000000..a877e4b829d2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAPIPermissionList.ps1 @@ -0,0 +1,17 @@ +function Invoke-ExecAPIPermissionList { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.SuperAdmin.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Roles = Get-CIPPHttpFunctions -ByRoleGroup | ConvertTo-Json -Depth 10 + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Roles + }) +} 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 new file mode 100644 index 000000000000..c0f3a4576147 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 @@ -0,0 +1,52 @@ +function Invoke-ExecCustomRole { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Table = Get-CippTable -tablename 'CustomRoles' + switch ($Request.Query.Action) { + 'AddUpdate' { + $Role = @{ + 'PartitionKey' = 'CustomRoles' + 'RowKey' = "$($Request.Body.RoleName)" + 'Permissions' = "$($Request.Body.Permissions | ConvertTo-Json -Compress)" + 'AllowedTenants' = "$($Request.Body.AllowedTenants | ConvertTo-Json -Compress)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Role -Force | Out-Null + $Body = @{Results = 'Role added' } + } + 'Delete' { + $Role = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.RoleName)'" -Property RowKey, PartitionKey + Remove-AzDataTableEntity @Table -Entity $Role + $Body = @{Results = 'Role deleted' } + } + default { + $Body = Get-CIPPAzDataTableEntity @Table + + if (!$Body) { + $Body = @( + @{ + RowKey = 'No custom roles found' + } + ) + } else { + $Body = foreach ($Role in $Body) { + $Role.Permissions = $Role.Permissions | ConvertFrom-Json + $Role.AllowedTenants = @($Role.AllowedTenants | ConvertFrom-Json) + $Role + } + $Body = @($Body) + } + } + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-Z_CIPPHttpTrigger.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-Z_CIPPHttpTrigger.ps1 deleted file mode 100644 index 9f0083676d1e..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-Z_CIPPHttpTrigger.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -function Invoke-Z_CIPPHttpTrigger { - <# - .FUNCTIONALITY - Entrypoint - #> - Param( - $Request, - $TriggerMetadata - ) - - $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint - - Write-Host "Function: $($Request.Params.CIPPEndpoint)" - - $HttpTrigger = @{ - Request = $Request - TriggerMetadata = $TriggerMetadata - } - - if (Get-Command -Name $FunctionName -ErrorAction SilentlyContinue) { - & $FunctionName @HttpTrigger - } else { - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::NotFound - Body = 'Endpoint not found' - }) - } -} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 index 8c884978d21f..9b0e5aab48bb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 @@ -22,14 +22,17 @@ Function Invoke-ListAlertsQueue { $ScheduledTasks = Get-CIPPTable -TableName 'ScheduledTasks' $ScheduledTasks = Get-CIPPAzDataTableEntity @ScheduledTasks | Where-Object { $_.hidden -eq $true } + $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList + $TenantList = Get-Tenants -IncludeErrors $AllTasksArrayList = [system.collections.generic.list[object]]::new() foreach ($Task in $WebhookRules) { $Conditions = $Task.Conditions | ConvertFrom-Json -ErrorAction SilentlyContinue $TranslatedConditions = ($Conditions | ForEach-Object { "When $($_.Property.label) is $($_.Operator.label) $($_.input.value)" }) -join ' and ' $TranslatedActions = ($Task.Actions | ConvertFrom-Json -ErrorAction SilentlyContinue).label -join ',' + $Tenants = ($Task.Tenants | ConvertFrom-Json -ErrorAction SilentlyContinue).fullValue $TaskEntry = [PSCustomObject]@{ - Tenants = ($Task.Tenants | ConvertFrom-Json -ErrorAction SilentlyContinue).fullValue.defaultDomainName -join ',' + Tenants = $Tenants.defaultDomainName -join ',' Conditions = $TranslatedConditions Actions = $TranslatedActions LogType = $Task.type @@ -38,7 +41,17 @@ Function Invoke-ListAlertsQueue { PartitionKey = $Task.PartitionKey RepeatsEvery = 'When received' } - $AllTasksArrayList.Add($TaskEntry) + + if ($AllowedTenants -notcontains 'AllTenants') { + foreach ($Tenant in $Tenants) { + if ($AllowedTenants -contains $Tenant.customerId) { + $AllTasksArrayList.Add($TaskEntry) + break + } + } + } else { + $AllTasksArrayList.Add($TaskEntry) + } } foreach ($Task in $ScheduledTasks) { @@ -52,7 +65,14 @@ Function Invoke-ListAlertsQueue { EventType = 'Scheduled Task' RepeatsEvery = $Task.Recurrence } - $AllTasksArrayList.Add($TaskEntry) + if ($AllowedTenants -notcontains 'AllTenants') { + $Tenant = $TenantList | Where-Object -Property defaultDomainName -EQ $Task.Tenant + if ($AllowedTenants -contains $Tenant.customerId) { + $AllTasksArrayList.Add($TaskEntry) + } + } else { + $AllTasksArrayList.Add($TaskEntry) + } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 index 3ecb43be0920..67b0d6562ec7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 @@ -13,7 +13,13 @@ Function Invoke-ListTenants { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantAccess = Test-CIPPAccess -Request $Request -TenantList + if ($TenantAccess -notcontains 'AllTenants') { + $AllTenantSelector = $false + } else { + $AllTenantSelector = $Request.Query.AllTenantSelector + } # Clear Cache if ($request.Query.ClearCache -eq 'true') { @@ -32,10 +38,13 @@ Function Invoke-ListTenants { try { $tenantfilter = $Request.Query.TenantFilter $Tenants = Get-Tenants -IncludeErrors -SkipDomains + if ($TenantAccess -notcontains 'AllTenants') { + $Tenants = $Tenants | Where-Object -Property customerId -In $TenantAccess + } if ($null -eq $TenantFilter -or $TenantFilter -eq 'null') { $TenantList = [system.collections.generic.list[object]]::new() - if ($Request.Query.AllTenantSelector -eq $true) { + if ($AllTenantSelector -eq $true) { $TenantList.Add(@{ customerId = 'AllTenants' defaultDomainName = 'AllTenants' 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 abdce86f9df5..df3e849a19e8 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 @@ -48,7 +48,12 @@ Function Invoke-ListBPA { $Data = $mergedObject } else { + $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList $Tenants = Get-Tenants -IncludeErrors + if ($AllowedTenants -notcontains 'AllTenants') { + $Tenants = $Tenants | Where-Object -Property customerId -In $AllowedTenants + } + Write-Information ($tenants.defaultDomainName | ConvertTo-Json) $Data = (Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$NAME'") | ForEach-Object { $row = $_ $JSONFields | ForEach-Object { diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 index 98544c614be7..00a7b0410365 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 @@ -5,7 +5,7 @@ Function Invoke-ListContacts { .FUNCTIONALITY Entrypoint .ROLE - Exchange.Contacts.Read + Exchange.Contact.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index 688e3e81695c..0a3877cfc4c9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -10,9 +10,11 @@ Function Invoke-ListLogs { [CmdletBinding()] param($Request, $TriggerMetadata) + $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantList = Get-Tenants -IncludeErrors if ($request.Query.Filter -eq 'True') { $LogLevel = if ($Request.query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } $PartitionKey = $Request.query.DateFilter @@ -36,6 +38,15 @@ Function Invoke-ListLogs { $Filter = "PartitionKey eq '{0}'" -f $PartitionKey $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -In $LogLevel -and $_.user -like $username } foreach ($Row in $Rows) { + + if ($AllowedTenants -notcontains 'AllTenants') { + if ($Row.Tenant -ne 'None') { + $Tenant = $TenantList | Where-Object -Property defaultDomainName -EQ $Row.Tenant + if ($Tenant.customerId -notin $AllowedTenants) { + continue + } + } + } $LogData = if ($Row.LogData -and (Test-Json -Json $Row.LogData)) { $Row.LogData | ConvertFrom-Json } else { $Row.LogData } diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index 800fd3618526..6be99039dcc2 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -1,20 +1,43 @@ using namespace System.Net function Receive-CippHttpTrigger { - Param($Request, $TriggerMetadata) - #force path to CIPP-API - Set-Location (Get-Item $PSScriptRoot).Parent.Parent.FullName - Write-Information (Get-Item $PSScriptRoot).Parent.Parent.FullName - $APIName = $TriggerMetadata.FunctionName + <# + .FUNCTIONALITY + Entrypoint + #> + Param( + $Request, + $TriggerMetadata + ) - $FunctionName = 'Invoke-{0}' -f $APIName + $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint + + Write-Host "Function: $($Request.Params.CIPPEndpoint)" $HttpTrigger = @{ Request = $Request TriggerMetadata = $TriggerMetadata } - & $FunctionName @HttpTrigger + if (Get-Command -Name $FunctionName -ErrorAction SilentlyContinue) { + try { + $Access = Test-CIPPAccess -Request $Request + Write-Information "Access: $Access" + if ($Access) { + & $FunctionName @HttpTrigger + } + } catch { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::Forbidden + Body = $_.Exception.Message + }) + } + } else { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::NotFound + Body = 'Endpoint not found' + }) + } } function Receive-CippQueueTrigger { From 47cd6163606dc7e6c314ed1b93ab3edadb48e8cc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 May 2024 20:38:33 -0400 Subject: [PATCH 031/138] Update Invoke-ListMessageTrace.ps1 --- .../HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 index 434b5121d544..25a5e57b1e59 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 @@ -5,7 +5,7 @@ Function Invoke-ListMessageTrace { .FUNCTIONALITY Entrypoint .ROLE - Exchange.Transport.Read + Exchange.TransportRule.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) From 1378ca05354c4212edf76eb17d6e091b1556084e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 May 2024 20:49:41 -0400 Subject: [PATCH 032/138] Custom Role --- Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 332f4c06cf9a..40ab1555819d 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -63,7 +63,7 @@ function Test-CIPPAccess { } } if (!$APIAllowed) { - throw "Access to this API is not allowed, required role: $APIRole" + throw "Access to this API is not allowed, required permission: $APIRole" } } else { return $true 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 c0f3a4576147..45b0e6931d89 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 @@ -18,12 +18,12 @@ function Invoke-ExecCustomRole { 'AllowedTenants' = "$($Request.Body.AllowedTenants | ConvertTo-Json -Compress)" } Add-CIPPAzDataTableEntity @Table -Entity $Role -Force | Out-Null - $Body = @{Results = 'Role added' } + $Body = @{Results = 'Custom role saved' } } 'Delete' { $Role = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.RoleName)'" -Property RowKey, PartitionKey Remove-AzDataTableEntity @Table -Entity $Role - $Body = @{Results = 'Role deleted' } + $Body = @{Results = 'Custom role deleted' } } default { $Body = Get-CIPPAzDataTableEntity @Table From 3db9faa532fabd55e0e774895e3252d4dd778ce5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 28 May 2024 20:56:12 -0400 Subject: [PATCH 033/138] Update Test-CIPPAccess.ps1 --- 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 40ab1555819d..8f6a3d1748b9 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -63,7 +63,7 @@ function Test-CIPPAccess { } } if (!$APIAllowed) { - throw "Access to this API is not allowed, required permission: $APIRole" + throw "Access to this API is not allowed, required permission missing: $APIRole" } } else { return $true From 80eaf888eff2bdd7541a829bd62f10a9f416ce29 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 01:18:29 -0400 Subject: [PATCH 034/138] Update Get-CIPPHttpFunctions.ps1 --- .../CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 index 477f092a446c..968fa5f70b9a 100644 --- a/Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPHttpFunctions.ps1 @@ -25,7 +25,7 @@ function Get-CIPPHttpFunctions { if ($PermSplit.Count -ne 3) { continue } if ($RoleGroup[$PermSplit[0]] -eq $null) { $RoleGroup[$PermSplit[0]] = @{} } if ($RoleGroup[$PermSplit[0]][$PermSplit[1]] -eq $null) { $RoleGroup[$PermSplit[0]][$PermSplit[1]] = @{} } - $RoleGroup[$PermSplit[0]][$PermSplit[1]][$PermSplit[2]] = $Permission.Functions + $RoleGroup[$PermSplit[0]][$PermSplit[1]][$PermSplit[2]] = @($Permission.Functions) } $Results = $RoleGroup } From c5599aef8ae2e0755d1e284abf0cd999f906e0eb Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 09:17:49 -0400 Subject: [PATCH 035/138] CIPP-API role restriction --- .../Get-CIPPRolePermissions.ps1 | 2 +- .../Public/Authentication/Test-CIPPAccess.ps1 | 86 +++++++++++-------- Modules/CippEntrypoints/CippEntrypoints.psm1 | 1 + 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 index 03bff3901fb1..0f932ee7f842 100644 --- a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 @@ -24,6 +24,6 @@ function Get-CIPPRolePermissions { AllowedTenants = $Role.AllowedTenants | ConvertFrom-Json } } else { - Write-Error "Role $RoleName not found." + throw "Role $RoleName not found." } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 8f6a3d1748b9..6cfa7eef8943 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -3,17 +3,24 @@ function Test-CIPPAccess { $Request, [switch]$TenantList ) - $DefaultRoles = @('admin', 'editor', 'readonly', 'anonymous', 'authenticated') - $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json - if ($User.userRoles -contains 'admin' -or $User.userRoles -contains 'superadmin') { - if ($TenantList.IsPresent) { - return @('AllTenants') + + if (!$Request.Headers.'x-ms-client-principal') { + # Direct API Access + $CustomRoles = @('CIPP-API') + } else { + $DefaultRoles = @('admin', 'editor', 'readonly', 'anonymous', 'authenticated') + $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json + if ($User.userRoles -contains 'admin' -or $User.userRoles -contains 'superadmin') { + if ($TenantList.IsPresent) { + return @('AllTenants') + } + return $true } - return $true - } - $CustomRoles = $User.userRoles | ForEach-Object { - if ($DefaultRoles -notcontains $_) { - $_ + + $CustomRoles = $User.userRoles | ForEach-Object { + if ($DefaultRoles -notcontains $_) { + $_ + } } } if (($CustomRoles | Measure-Object).Count -gt 0 ) { @@ -21,7 +28,11 @@ function Test-CIPPAccess { $APIAllowed = $false $TenantAllowed = $false $PermissionSet = foreach ($CustomRole in $CustomRoles) { - Get-CIPPRolePermissions -Role $CustomRole + try { + Get-CIPPRolePermissions -Role $CustomRole + } catch { + Write-Information $_.Exception.Message + } } if ($TenantList.IsPresent) { $AllowedTenants = foreach ($Permission in $PermissionSet) { @@ -31,35 +42,40 @@ function Test-CIPPAccess { } return $AllowedTenants } - $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint - $Help = Get-Help $FunctionName - $APIRole = $Help.Role - foreach ($Role in $PermissionSet) { - foreach ($Perm in $Role.Permissions) { - if ($Perm -match $APIRole) { - $APIAllowed = $true - break + + if (($PermissionSet | Measure-Object).Count -eq 0) { + return $true + } else { + $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint + $Help = Get-Help $FunctionName + $APIRole = $Help.Role + foreach ($Role in $PermissionSet) { + foreach ($Perm in $Role.Permissions) { + if ($Perm -match $APIRole) { + $APIAllowed = $true + break + } } - } - if ($APIAllowed) { - if ($Role.AllowedTenants -contains 'AllTenants') { - $TenantAllowed = $true - } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { - $TenantAllowed = $false - } else { - $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId + if ($APIAllowed) { + if ($Role.AllowedTenants -contains 'AllTenants') { + $TenantAllowed = $true + } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { + $TenantAllowed = $false + } else { + $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId - if ($Tenant) { - $TenantAllowed = $Role.AllowedTenants -contains $Tenant + if ($Tenant) { + $TenantAllowed = $Role.AllowedTenants -contains $Tenant + } else { + $TenantAllowed = $true + } + } + if ($TenantAllowed) { + return $true } else { - $TenantAllowed = $true + throw 'Access to this tenant is not allowed' } } - if ($TenantAllowed) { - return $true - } else { - throw 'Access to this tenant is not allowed' - } } } if (!$APIAllowed) { diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index 6be99039dcc2..9943b1cea1cd 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -27,6 +27,7 @@ function Receive-CippHttpTrigger { & $FunctionName @HttpTrigger } } catch { + Write-Information $_.Exception.Message Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::Forbidden Body = $_.Exception.Message From 1472137d665d7faf6d1dcffc1d642fa38e962262 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 10:05:02 -0400 Subject: [PATCH 036/138] wording, multi role support --- .../Public/Authentication/Test-CIPPAccess.ps1 | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 6cfa7eef8943..53338c1b387d 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -25,8 +25,6 @@ function Test-CIPPAccess { } if (($CustomRoles | Measure-Object).Count -gt 0 ) { $Tenants = Get-Tenants -IncludeErrors - $APIAllowed = $false - $TenantAllowed = $false $PermissionSet = foreach ($CustomRole in $CustomRoles) { try { Get-CIPPRolePermissions -Role $CustomRole @@ -48,8 +46,12 @@ function Test-CIPPAccess { } else { $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint $Help = Get-Help $FunctionName + # Check API for required role $APIRole = $Help.Role foreach ($Role in $PermissionSet) { + # Loop through each custom role permission and check API / Tenant access + $TenantAllowed = $false + $APIAllowed = $false foreach ($Perm in $Role.Permissions) { if ($Perm -match $APIRole) { $APIAllowed = $true @@ -57,6 +59,7 @@ function Test-CIPPAccess { } } if ($APIAllowed) { + # Check tenant level access if ($Role.AllowedTenants -contains 'AllTenants') { $TenantAllowed = $true } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { @@ -66,20 +69,23 @@ function Test-CIPPAccess { if ($Tenant) { $TenantAllowed = $Role.AllowedTenants -contains $Tenant + if (!$TenantAllowed) { continue } + break } else { $TenantAllowed = $true + break } } - if ($TenantAllowed) { - return $true - } else { - throw 'Access to this tenant is not allowed' - } } } - } - if (!$APIAllowed) { - throw "Access to this API is not allowed, required permission missing: $APIRole" + if (!$APIAllowed) { + throw "Access to this API is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" + } + if (!$TenantAllowed) { + throw 'Access to this tenant is not allowed' + } else { + return $true + } } } else { return $true From 9b2b23184015a8da382330f67ce658c538e1d2fe Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 13:12:01 -0400 Subject: [PATCH 037/138] Update Test-CIPPAccess.ps1 --- 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 53338c1b387d..5fcd0395a783 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -79,7 +79,7 @@ function Test-CIPPAccess { } } if (!$APIAllowed) { - throw "Access to this API is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" + throw "Access to this CIPP API endpoint is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" } if (!$TenantAllowed) { throw 'Access to this tenant is not allowed' From 5e3f11820ce2a90cb459bb62a2e526ea3fdd5a0d Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 15:32:07 -0400 Subject: [PATCH 038/138] Create CIPP.AppSettings category --- .../HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 | 2 +- .../HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 | 2 +- .../Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 | 2 +- .../CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 | 2 +- .../CIPP/Settings/Invoke-ExecNotificationConfig.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 | 2 +- .../HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 | 2 +- .../HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 2 +- .../Public/Entrypoints/Invoke-ListNotificationConfig.ps1 | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 index 0e5581ffb476..c2c194438e96 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 @@ -3,7 +3,7 @@ function Invoke-ExecDurableFunctions { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding(SupportsShouldProcess = $true)] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 index 0989b2c5e843..5a235ee7cb7d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 @@ -3,7 +3,7 @@ function Invoke-ExecPartnerWebhook { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> Param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 index 1a2e0912cd87..0f7431ee9534 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 @@ -5,7 +5,7 @@ Function Invoke-GetVersion { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.Read + CIPP.AppSettings.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 index 4f51b3525989..019e3af0997e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecAccessChecks { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.Read + CIPP.AppSettings.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 index 066f1e665601..4613ea2c3c68 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAddTrustedIP.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecAddTrustedIP { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 index ea00cbb12691..4c0adc7368e8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecBackendURLs.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecBackendURLs { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.Read + CIPP.AppSettings.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 index 356b1643834f..db0bae59c71b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecCPVPermissions { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 index a4d54f0b9eb6..147855eab44c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecDnsConfig { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 index 7b40efffe84c..8b18bb186e4a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecExcludeLicenses { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 index 177aa425b86f..76c414414905 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecExcludeTenant { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 index aa1e92027101..fe01aed3123e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecMaintenanceScripts.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecMaintenanceScripts { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.Read + CIPP.AppSettings.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 index 23fbd238f807..411400303392 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecNotificationConfig.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecNotificationConfig { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 index 346920fb6a24..9f4815e3f25d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecPasswordConfig { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 index b3aafb0f21f3..b9820352bfdd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecRestoreBackup { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 index 08bb5ec54673..5dd1070a2c49 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecRunBackup { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) 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 2b1b9b9dc28c..e61a272a80ac 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 @@ -5,7 +5,7 @@ Function Invoke-ExecSAMSetup { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.ReadWrite + CIPP.AppSettings.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 index 1f3426888c33..a375c65deb04 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListNotificationConfig.ps1 @@ -5,7 +5,7 @@ Function Invoke-ListNotificationConfig { .FUNCTIONALITY Entrypoint .ROLE - CIPP.Core.Read + CIPP.AppSettings.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) From 213fedbaf57961c91b960839fc36f1f3203f4d03 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 29 May 2024 20:47:20 -0400 Subject: [PATCH 039/138] Update Get-CIPPStandards.ps1 --- Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 60751d34303d..6e941c7608cd 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -43,7 +43,7 @@ function Get-CIPPStandards { if ($StandardsTenant.Standards.OverrideAllTenants.remediate -ne $true) { #Write-Host 'AllTenant Standards apply to this tenant.' foreach ($StandardName in $StandardsAllTenants.Standards.PSObject.Properties.Name) { - $CurrentStandard = $StandardsAllTenants.Standards.$StandardName + $CurrentStandard = $StandardsAllTenants.Standards.$StandardName.PSObject.Copy() #Write-Host ($CurrentStandard | ConvertTo-Json -Depth 10) if ($CurrentStandard.remediate -eq $true -or $CurrentStandard.alert -eq $true -or $CurrentStandard.report -eq $true) { #Write-Host "AllTenant Standard $StandardName" @@ -54,16 +54,16 @@ function Get-CIPPStandards { foreach ($StandardName in $StandardsTenant.Standards.PSObject.Properties.Name) { if ($StandardName -eq 'OverrideAllTenants') { continue } - $CurrentStandard = $StandardsTenant.Standards.$StandardName + $CurrentStandard = $StandardsTenant.Standards.$StandardName.PSObject.Copy() if ($CurrentStandard.remediate -eq $true -or $CurrentStandard.alert -eq $true -or $CurrentStandard.report -eq $true) { - #Write-Host "`r`nTenant: $StandardName" + # Write-Host "`r`nTenant: $StandardName" if (!$ComputedStandards[$StandardName] ) { #Write-Host "Applying tenant level $StandardName" $ComputedStandards[$StandardName] = $CurrentStandard } else { foreach ($Setting in $CurrentStandard.PSObject.Properties.Name) { - #Write-Host "$Setting - Current: $($CurrentStandard.$Setting) | Computed: $($ComputedStandards[$StandardName].$($Setting))" + # 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)) { #Write-Host "Overriding $Setting for $StandardName at tenant level" if ($ComputedStandards[$StandardName].PSObject.Properties.Name -contains $Setting) { From 503c0c6211de6eb053e8efc3e48043ce302fa8a9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 00:12:46 -0400 Subject: [PATCH 040/138] Extension permissions --- .../Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 | 2 +- .../CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 | 2 +- Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 index 4bafafd3d374..5ea8abad3067 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecExtensionNinjaOneQueue.ps1 @@ -5,7 +5,7 @@ Function Invoke-ExecExtensionNinjaOneQueue { .FUNCTIONALITY Entrypoint .ROLE - Extension.NinjaOne.ReadWrite + CIPP.Extension.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 index ddff3b174b6a..e2feff0542d7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExtensionsConfig.ps1 @@ -5,7 +5,7 @@ Function Invoke-ListExtensionsConfig { .FUNCTIONALITY Entrypoint .ROLE - Extension.Config.Read + CIPP.Extension.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 index f129aebe7df3..e00ba611aa67 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListHaloClients.ps1 @@ -5,7 +5,7 @@ Function Invoke-ListHaloClients { .FUNCTIONALITY Entrypoint .ROLE - Extension.HaloPSA.Read + CIPP.Extension.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) From b3e35020cfaab5270a21cc146974a4258d63689e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 08:54:16 -0400 Subject: [PATCH 041/138] Trim version strings --- .../HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 index 0f7431ee9534..95e7353f6f61 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 @@ -13,11 +13,11 @@ Function Invoke-GetVersion { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $APIVersion = Get-Content 'version_latest.txt' | Out-String + $APIVersion = (Get-Content 'version_latest.txt' -Raw).trim() $CIPPVersion = $request.query.localversion - $RemoteAPIVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt' - $RemoteCIPPVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt' + $RemoteAPIVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt').trim() + $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt').trim() $version = [PSCustomObject]@{ LocalCIPPVersion = $CIPPVersion From 44de619ce60a45e93fe583894e7b64161ea5270a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 09:08:58 -0400 Subject: [PATCH 042/138] Move version check to function --- .../CIPPCore/Public/Assert-CippVersion.ps1 | 27 ++++++++++++++ .../CIPP/Core/Invoke-GetCippAlerts.ps1 | 36 ++++++------------- .../CIPP/Core/Invoke-GetVersion.ps1 | 13 +------ 3 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 Modules/CIPPCore/Public/Assert-CippVersion.ps1 diff --git a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 new file mode 100644 index 000000000000..83f77f43edd0 --- /dev/null +++ b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 @@ -0,0 +1,27 @@ +function Assert-CippVersion { + <# + .SYNOPSIS + Compare the local version of CIPP with the latest version. + + .DESCRIPTION + Retrieves the local version of CIPP and compares it with the latest version in GitHub. + + .PARAMETER CIPPVersion + Local version of CIPP frontend + + #> + Param($CIPPVersion) + $APIVersion = (Get-Content 'version_latest.txt' -Raw).trim() + + $RemoteAPIVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt').trim() + $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt').trim() + + [PSCustomObject]@{ + LocalCIPPVersion = $CIPPVersion + RemoteCIPPVersion = $RemoteCIPPVersion + LocalCIPPAPIVersion = $APIVersion + RemoteCIPPAPIVersion = $RemoteAPIVersion + OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) + OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) + } +} \ No newline at end of file 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 53a0321cfb8a..0e78c0e093f2 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 @@ -10,53 +10,39 @@ Function Invoke-GetCippAlerts { [CmdletBinding()] param($Request, $TriggerMetadata) - $Alerts = [System.Collections.ArrayList]@() + $Alerts = [System.Collections.Generic.List[object]]::new() $Table = Get-CippTable -tablename CippAlerts $PartitionKey = Get-Date -UFormat '%Y%m%d' $Filter = "PartitionKey eq '{0}'" -f $PartitionKey $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TableTimestamp -Descending | Select-Object -First 10 $role = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json).userRoles - $APIVersion = Get-Content 'version_latest.txt' | Out-String - $CIPPVersion = $request.query.localversion - - $RemoteAPIVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt' - $RemoteCIPPVersion = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt' - - $version = [PSCustomObject]@{ - LocalCIPPVersion = $CIPPVersion - RemoteCIPPVersion = $RemoteCIPPVersion - LocalCIPPAPIVersion = $APIVersion - RemoteCIPPAPIVersion = $RemoteAPIVersion - OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) - OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) - } - if ($version.outOfDateCIPP) { - $Alerts.add(@{Alert = 'Your CIPP Frontend is out of date. Please update to the latest version. Find more on the following '; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) + $CIPPVersion = $Request.Query.localversion + $Version = Assert-CippVersion -CIPPVersion $CIPPVersion + if ($Version.OutOfDateCIPP) { + $Alerts.Add(@{Alert = 'Your CIPP Frontend is out of date. Please update to the latest version. Find more on the following '; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) Write-LogMessage -message 'Your CIPP Frontend is out of date. Please update to the latest version' -API 'Updates' -tenant 'All Tenants' -sev Alert } - if ($version.outOfDateCIPPAPI) { - $Alerts.add(@{Alert = 'Your CIPP API is out of date. Please update to the latest version. Find more on the following'; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) + if ($Version.OutOfDateCIPPAPI) { + $Alerts.Add(@{Alert = 'Your CIPP API is out of date. Please update to the latest version. Find more on the following'; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) 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 setup your SAM Setup. Please go to the SAM Wizard in settings to finish setup'; link = '/cipp/setup'; type = 'warning' }) } - 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:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.Add(@{Alert = 'You have not yet setup your SAM Setup. Please go to the SAM Wizard in settings to finish setup'; link = '/cipp/setup'; type = 'warning' }) } + 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') { - $Alerts.add( + $Alerts.Add( @{Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this ' link = 'https://docs.cipp.app/setup/installation/runfrompackage' type = 'warning' }) } - if ($Rows) { $Rows | ForEach-Object { $alerts.add($_) } } + if ($Rows) { $Rows | ForEach-Object { $alerts.Add($_) } } $Alerts = @($Alerts) $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 index 95e7353f6f61..61df91438485 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 @@ -13,20 +13,9 @@ Function Invoke-GetVersion { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $APIVersion = (Get-Content 'version_latest.txt' -Raw).trim() $CIPPVersion = $request.query.localversion - $RemoteAPIVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt').trim() - $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt').trim() - - $version = [PSCustomObject]@{ - LocalCIPPVersion = $CIPPVersion - RemoteCIPPVersion = $RemoteCIPPVersion - LocalCIPPAPIVersion = $APIVersion - RemoteCIPPAPIVersion = $RemoteAPIVersion - OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) - OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) - } + $Version = Assert-CippVersion -CIPPVersion $CIPPVersion # Write to the Azure Functions log stream. # Associate values to output bindings by calling 'Push-OutputBinding'. From 08bd17719ac51fad18c18eb996262bc27fdd4d16 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 09:14:33 -0400 Subject: [PATCH 043/138] Update Invoke-GetCippAlerts.ps1 --- .../HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 0e78c0e093f2..1ec68eb1a7c7 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,16 +29,16 @@ 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 setup your SAM Setup. Please go to the SAM Wizard in settings to finish setup'; 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' }) } 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') { + if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1' -and $env:AzureWebJobsStorage -ne 'UseDevelopmentStorage=true') { $Alerts.Add( @{Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this ' link = 'https://docs.cipp.app/setup/installation/runfrompackage' type = 'warning' }) } - if ($Rows) { $Rows | ForEach-Object { $alerts.Add($_) } } + if ($Rows) { $Rows | ForEach-Object { $Alerts.Add($_) } } $Alerts = @($Alerts) $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' From f67648047220a5b7841de3fa7510a4dff352f41a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 11:09:09 -0400 Subject: [PATCH 044/138] Update Invoke-ExecGDAPInvite.ps1 --- .../HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 index 41e4fdd26e77..ac1f15cfafb9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 @@ -9,7 +9,7 @@ Function Invoke-ExecGDAPInvite { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName + $APIName = 'ExecGDAPInvite' Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $RoleMappings = $Request.body.gdapRoles @@ -49,7 +49,7 @@ Function Invoke-ExecGDAPInvite { if ($NewRelationshipRequest.action -eq 'lockForApproval') { $InviteUrl = "https://admin.microsoft.com/AdminPortal/Home#/partners/invitation/granularAdminRelationships/$($NewRelationship.id)" - $Uri = ([System.Uri]$TriggerMetadata.Headers.referer) + $Uri = ([System.Uri]$TriggerMetadata.Headers.Referer) $TableFilter = [System.Web.HttpUtility]::UrlEncode(('Complex: id eq {0}' -f $NewRelationship.id)) $OnboardingUrl = $Uri.AbsoluteUri.Replace($Uri.PathAndQuery, "/tenant/administration/tenant-onboarding-wizard?tableFilter=$TableFilter") @@ -72,7 +72,7 @@ Function Invoke-ExecGDAPInvite { } catch { $Message = 'Error creating GDAP relationship' Write-Host "GDAP ERROR: $($_.Exception.Message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $env:TenantID -message "$($Message): $($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $env:TenantID -message "$($Message): $($_.Exception.Message)" -Sev 'Error' -LogData (Get-CippException -Exception $_) } $body = @{ From 15ee3492e5f4ea9091de6c0cc21d2281436f5b92 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 11:22:17 -0400 Subject: [PATCH 045/138] Update Invoke-ExecGDAPInvite.ps1 --- .../HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 index ac1f15cfafb9..91cfa3388bb2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 @@ -71,7 +71,7 @@ Function Invoke-ExecGDAPInvite { } } catch { $Message = 'Error creating GDAP relationship' - Write-Host "GDAP ERROR: $($_.Exception.Message)" + Write-Host "GDAP ERROR: $($_.InvocationInfo.PositionMessage)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $env:TenantID -message "$($Message): $($_.Exception.Message)" -Sev 'Error' -LogData (Get-CippException -Exception $_) } From d1df0ed1cfc94e7fde083552005fd27312e127c1 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 11:54:43 -0400 Subject: [PATCH 046/138] Fix Get-Tenants --- Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 index 77a9e22e107b..fdcb3d3eb95b 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -103,7 +103,7 @@ function Get-Tenants { } } - $obj = [PSCustomObject]@{ + $Obj = [PSCustomObject]@{ PartitionKey = 'Tenants' RowKey = $_.Name customerId = $_.Name @@ -111,6 +111,7 @@ function Get-Tenants { relationshipEnd = $LatestRelationship.relationshipEnd relationshipCount = $_.Count defaultDomainName = $defaultDomainName + initialDomainName = $initialDomainName hasAutoExtend = $AutoExtend delegatedPrivilegeStatus = 'granularDelegatedAdminPrivileges' domains = '' @@ -125,7 +126,8 @@ function Get-Tenants { if ($Obj.defaultDomainName -eq 'Invalid' -or !$Obj.defaultDomainName) { continue } - Add-CIPPAzDataTableEntity @TenantsTable -Entity $obj -Force | Out-Null + Add-CIPPAzDataTableEntity @TenantsTable -Entity $Obj -Force | Out-Null + $Obj } } $IncludedTenantsCache = [system.collections.generic.list[object]]::new() @@ -136,7 +138,7 @@ function Get-Tenants { RowKey = $env:TenantID PartitionKey = 'Tenants' customerId = $env:TenantID - defaultDomainName = ($Domains | Where-Object { $_.isInitial -eq $true }).id + defaultDomainName = ($Domains | Where-Object { $_.isDefault -eq $true }).id initialDomainName = ($Domains | Where-Object { $_.isInitial -eq $true }).id displayName = '*Partner Tenant' domains = 'PartnerTenant' @@ -148,7 +150,7 @@ function Get-Tenants { RequiresRefresh = [bool]$RequiresRefresh LastRefresh = (Get-Date).ToUniversalTime() }) | Out-Null - + } foreach ($Tenant in $TenantList) { if ($Tenant.defaultDomainName -eq 'Invalid' -or !$Tenant.defaultDomainName) { From 1bfb35bcfc21c2d79c47cf2841c5da2ef0d5571e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 12:33:09 -0400 Subject: [PATCH 047/138] pathing --- Modules/CIPPCore/Public/Assert-CippVersion.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 index 83f77f43edd0..ac28abb49026 100644 --- a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 +++ b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 @@ -11,7 +11,8 @@ function Assert-CippVersion { #> Param($CIPPVersion) - $APIVersion = (Get-Content 'version_latest.txt' -Raw).trim() + $CippRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName + $APIVersion = (Get-Content "$CippRoot\version_latest.txt" -Raw).trim() $RemoteAPIVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt').trim() $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt').trim() From 9f3be9c8559765e3e413f0c6d809d4a55d2d77ee Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 30 May 2024 12:38:19 -0400 Subject: [PATCH 048/138] pathing --- Modules/CIPPCore/Public/Assert-CippVersion.ps1 | 3 +-- Modules/CippEntrypoints/CippEntrypoints.psm1 | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 index ac28abb49026..83f77f43edd0 100644 --- a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 +++ b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 @@ -11,8 +11,7 @@ function Assert-CippVersion { #> Param($CIPPVersion) - $CippRoot = (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName - $APIVersion = (Get-Content "$CippRoot\version_latest.txt" -Raw).trim() + $APIVersion = (Get-Content 'version_latest.txt' -Raw).trim() $RemoteAPIVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt').trim() $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt').trim() diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index 9943b1cea1cd..994dab0633bf 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -10,8 +10,8 @@ function Receive-CippHttpTrigger { $TriggerMetadata ) + Set-Location (Get-Item $PSScriptRoot).Parent.Parent.FullName $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint - Write-Host "Function: $($Request.Params.CIPPEndpoint)" $HttpTrigger = @{ From 3fe1772db59934fd57490a5b6e1ab07706f44f9b Mon Sep 17 00:00:00 2001 From: Esco Date: Thu, 30 May 2024 10:50:09 +0200 Subject: [PATCH 049/138] Fixed Defender Policys not working --- .../Invoke-CIPPStandardAntiPhishPolicy.ps1 | 35 ++++++++++++++++++- ...nvoke-CIPPStandardSafeAttachmentPolicy.ps1 | 34 ++++++++++++++++++ .../Invoke-CIPPStandardSafeLinksPolicy.ps1 | 34 ++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index b96e9f47ec89..d561c3cc51d3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -26,6 +26,17 @@ function Invoke-CIPPStandardAntiPhishPolicy { ($CurrentState.MailboxIntelligenceProtectionAction -eq $Settings.MailboxIntelligenceProtectionAction) -and ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $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 + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + if ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy already correctly configured' -sev Info @@ -61,8 +72,30 @@ function Invoke-CIPPStandardAntiPhishPolicy { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing Policy. Error: $ErrorMessage" -sev Error } } - } + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + AntiPhishPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + try { + if ($RuleState.Name -eq "CIPP $PolicyName") { + $cmdparams.Add('Identity', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated AntiPhish Rule' -sev Info + } else { + $cmdparams.Add('Name', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created AntiPhish Rule' -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create AntiPhish Rule. Error: $ErrorMessage" -sev Error + } + } + } if ($Settings.alert -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index 24d6c424d036..1973cb4efc10 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -17,6 +17,17 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { ($CurrentState.Redirect -eq $Settings.Redirect) -and (($null -eq $Settings.RedirectAddress) -or ($CurrentState.RedirectAddress -eq $Settings.RedirectAddress)) + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $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 + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + if ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { @@ -44,6 +55,29 @@ 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 + } + + try { + if ($RuleState.Name -eq "CIPP $PolicyName") { + $cmdparams.Add('Identity', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeAttachmentRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated SafeAttachment Rule' -sev Info + } else { + $cmdparams.Add('Name', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeAttachmentRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created SafeAttachment Rule' -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeAttachment Rule. Error: $ErrorMessage" -sev Error + } + } } if ($Settings.alert -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 index 65471148d7c8..bd353b32e485 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -23,6 +23,17 @@ function Invoke-CIPPStandardSafeLinksPolicy { ($CurrentState.DisableUrlRewrite -eq $Settings.DisableUrlRewrite) -and ($CurrentState.EnableOrganizationBranding -eq $Settings.EnableOrganizationBranding) + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $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 + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + if ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { @@ -56,6 +67,29 @@ function Invoke-CIPPStandardSafeLinksPolicy { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink Policy. Error: $ErrorMessage" -sev Error } } + + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + SafeLinksPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + try { + if ($RuleState.Name -eq "CIPP $PolicyName") { + $cmdparams.Add('Identity', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeLinksRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated SafeLink Rule' -sev Info + } else { + $cmdparams.Add('Name', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeLinksRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created SafeLink Rule' -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink Rule. Error: $ErrorMessage" -sev Error + } + } } if ($Settings.alert -eq $true) { From 12c3511d06901563acf1428993836108275d3289 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 May 2024 09:41:22 -0400 Subject: [PATCH 050/138] Adjust logging --- .../Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index 473a75ab15c7..e3c7d190e072 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -8,7 +8,7 @@ function Invoke-CIPPStandardNudgeMFA { $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 { $Body = $CurrentInfo @@ -17,12 +17,12 @@ function Invoke-CIPPStandardNudgeMFA { $body = ConvertTo-Json -Depth 10 -InputObject ($body | Select-Object registrationEnforcement) New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -Type patch -Body $body -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "$($Settings.state) Authenticator App Nudge with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "$StateName Authenticator App Nudge with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info $CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.state = $Settings.state $CurrentInfo.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays = $Settings.snoozeDurationInDays } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to $($Settings.state) Authenticator App Nudge: $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set Authenticator App Nudge to $($Settings.state): $ErrorMessage" -sev Error } } else { Write-LogMessage -API 'Standards' -tenant $tenant -message "Authenticator App Nudge is already set to $($Settings.state) with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info From d2e4083e876453d0ebaa24be89ee2ec00cf98656 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 May 2024 11:23:47 -0400 Subject: [PATCH 051/138] Change alert input parameter --- .../Public/Alerts/Get-CIPPAlertAdminPassword.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertApnCertExpiry.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertDefenderMalware.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertDefenderStatus.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1 | 5 +++-- .../Public/Alerts/Get-CIPPAlertExpiringLicenses.ps1 | 3 ++- .../CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 | 3 ++- .../CIPPCore/Public/Alerts/Get-CIPPAlertNewRole.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertNoCAConfig.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertOverusedLicenses.ps1 | 3 ++- .../CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 | 11 ++++++----- .../Public/Alerts/Get-CIPPAlertSecDefaultsUpsell.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 | 5 +++-- .../Public/Alerts/Get-CIPPAlertUnusedLicenses.ps1 | 3 ++- .../Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1 | 5 +++-- 18 files changed, 43 insertions(+), 25 deletions(-) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAdminPassword.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAdminPassword.ps1 index 2b92dc01a0ab..27e911fe98b0 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAdminPassword.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAdminPassword.ps1 @@ -7,7 +7,8 @@ function Get-CIPPAlertAdminPassword { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertApnCertExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertApnCertExpiry.ps1 index 25d63b23ebcd..bf6086581cf6 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertApnCertExpiry.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertApnCertExpiry.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertApnCertExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 index cc4884df294b..c749316e4189 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertAppSecretExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderMalware.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderMalware.ps1 index 6129c3b6ab3f..ea4812c62548 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderMalware.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderMalware.ps1 @@ -7,7 +7,8 @@ function Get-CIPPAlertDefenderMalware { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderStatus.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderStatus.ps1 index cccb46f13f5b..8dca902b18a5 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderStatus.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDefenderStatus.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertDefenderStatus { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1 index c67ff7bc39d0..1bf1e9c4463e 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDepTokenExpiry.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertDepTokenExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) @@ -22,7 +23,7 @@ function Get-CIPPAlertDepTokenExpiry { } catch {} - + } catch { Write-AlertMessage -tenant $($TenantFilter) -message "Failed to check Apple Device Enrollment Program token expiry for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)" } diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertExpiringLicenses.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertExpiringLicenses.ps1 index bf41dbc3e74c..1c8046934429 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertExpiringLicenses.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertExpiringLicenses.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertExpiringLicenses { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 index d1eb7df2c93a..411e3c96a806 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertMFAAdmins { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 index 386dbde00c5f..0b59055ed560 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertMFAAlertUsers { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 index 9fe0dc66271d..3708942b4759 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 @@ -7,7 +7,8 @@ function Get-CIPPAlertNewAppApproval { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewRole.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewRole.ps1 index 65fc84b35315..04beb6a6d523 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewRole.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewRole.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertNewRole { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) $Deltatable = Get-CIPPTable -Table DeltaCompare diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1 index 2875b082fa6a..2bbc9e5a55a5 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNoCAConfig.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertNoCAConfig { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertOverusedLicenses.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertOverusedLicenses.ps1 index dedead01d535..b02a8bb00676 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertOverusedLicenses.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertOverusedLicenses.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertOverusedLicenses { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 index 675dbeb8251e..f320f5b78a8d 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertQuotaUsed { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) @@ -14,12 +15,12 @@ function Get-CIPPAlertQuotaUsed { try { $AlertData = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application/json" -tenantid $TenantFilter | ForEach-Object { if ($_.StorageUsedInBytes -eq 0) { return } - $PercentLeft = [math]::round($_.StorageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes * 100) - if ($Input) { $Value = $input } else { $Value = 90 } + $PercentLeft = [math]::round(($_.storageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes) * 100) + if ($InputValue) { $Value = [int]$InputValue } else { $Value = 90 } if ($PercentLeft -gt $Value) { - "$($_.UserPrincipalName): Mailbox is more than $($value)% full. Mailbox is $PercentLeft% full" + "$($_.userPrincipalName): Mailbox is more than $($value)% full. Mailbox is $PercentLeft% full" } - + } Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData } catch { diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSecDefaultsUpsell.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSecDefaultsUpsell.ps1 index 8f3ff0fd48c2..c560d47329cb 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSecDefaultsUpsell.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSecDefaultsUpsell.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertSecDefaultsUpsell { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 index db33c5a1a4f1..e5f5c28d6fe9 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 @@ -7,7 +7,8 @@ function Get-CIPPAlertSharepointQuota { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) Try { @@ -16,7 +17,7 @@ function Get-CIPPAlertSharepointQuota { $sharepointToken.Add('accept', 'application/json') $sharepointQuota = (Invoke-RestMethod -Method 'GET' -Headers $sharepointToken -Uri "https://$($tenantName)-admin.sharepoint.com/_api/StorageQuotas()?api-version=1.3.2" -ErrorAction Stop).value if ($sharepointQuota) { - if ($input -Is [Boolean]) { $Value = 90 } else { $Value = $input } + if ($InputValue -Is [Boolean]) { $Value = 90 } else { $Value = $InputValue } $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) if ($UsedStoragePercentage -gt $Value) { $AlertData = "SharePoint Storage is at $($UsedStoragePercentage)%. Your alert threshold is $($Value)%" diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertUnusedLicenses.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertUnusedLicenses.ps1 index 5344c17d9ce3..d8fc1dd69e2c 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertUnusedLicenses.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertUnusedLicenses.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertUnusedLicenses { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1 index 6fb0c2695d57..224d23857005 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVppTokenExpiry.ps1 @@ -6,7 +6,8 @@ function Get-CIPPAlertVppTokenExpiry { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] - $input, + [Alias('input')] + $InputValue, $TenantFilter ) try { @@ -23,7 +24,7 @@ function Get-CIPPAlertVppTokenExpiry { Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData } catch {} - + } catch { # Error handling } From c0b6d0a6896cbccb99d71a6ad4dd7bc8fecc7f35 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 May 2024 12:13:50 -0400 Subject: [PATCH 052/138] Detailed exception for scheduler errors --- .../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 f254651b2165..20746f57fa52 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -54,7 +54,7 @@ function Push-ExecScheduledCommand { Results = "$errorMessage" TaskState = $State } - Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error -LogData (Get-CippExceptionData -Exception $_.Exception) } Write-Host 'Sending task results to target. Updating the task state.' From e0ff79190b1d93db74f0a924b05d7f25183b2404 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 May 2024 13:24:50 -0400 Subject: [PATCH 053/138] Alert tweaks --- .../Alerts/Get-CIPPAlertAppSecretExpiry.ps1 | 27 +++++++++---------- .../Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 | 24 +++++++++-------- .../Alerts/Get-CIPPAlertSharepointQuota.ps1 | 19 +++++++------ 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 index c749316e4189..cef5ba03ba14 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppSecretExpiry.ps1 @@ -14,23 +14,20 @@ function Get-CIPPAlertAppSecretExpiry { try { Write-Host "Checking app expire for $($TenantFilter)" $appList = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$select=appId,displayName,passwordCredentials" -tenantid $TenantFilter - $AlertData = foreach ($App in $applist) { - Write-Host "checking $($App.displayName)" - if ($App.passwordCredentials) { - foreach ($Credential in $App.passwordCredentials) { - if ($Credential.endDateTime -lt (Get-Date).AddDays(30) -and $Credential.endDateTime -gt (Get-Date).AddDays(-7)) { - Write-Host ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime) - @{ DisplayName = $App.displayName; Expires = $Credential.endDateTime } - } + } catch { + return + } + + $AlertData = foreach ($App in $applist) { + Write-Host "checking $($App.displayName)" + if ($App.passwordCredentials) { + foreach ($Credential in $App.passwordCredentials) { + if ($Credential.endDateTime -lt (Get-Date).AddDays(30) -and $Credential.endDateTime -gt (Get-Date).AddDays(-7)) { + Write-Host ("Application '{0}' has secrets expiring on {1}" -f $App.displayName, $Credential.endDateTime) + @{ DisplayName = $App.displayName; Expires = $Credential.endDateTime } } } - Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData - - } else { - Write-Host "Skipping app expire for $($TenantFilter)" } - } catch { - #Write-AlertMessage -tenant $($TenantFilter) -message "Failed to check App registration expiry for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)" } + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData } - diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 index f320f5b78a8d..32b63925c02a 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuotaUsed.ps1 @@ -11,18 +11,20 @@ function Get-CIPPAlertQuotaUsed { $TenantFilter ) - try { - $AlertData = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application/json" -tenantid $TenantFilter | ForEach-Object { - if ($_.StorageUsedInBytes -eq 0) { return } - $PercentLeft = [math]::round(($_.storageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes) * 100) - if ($InputValue) { $Value = [int]$InputValue } else { $Value = 90 } - if ($PercentLeft -gt $Value) { - "$($_.userPrincipalName): Mailbox is more than $($value)% full. Mailbox is $PercentLeft% full" - } - - } - Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + $AlertData = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application/json" -tenantid $TenantFilter } catch { + return } + $AlertData | ForEach-Object { + if ($_.StorageUsedInBytes -eq 0) { return } + $PercentLeft = [math]::round(($_.storageUsedInBytes / $_.prohibitSendReceiveQuotaInBytes) * 100) + if ($InputValue) { $Value = [int]$InputValue } else { $Value = 90 } + if ($PercentLeft -gt $Value) { + "$($_.userPrincipalName): Mailbox is more than $($value)% full. Mailbox is $PercentLeft% full" + } + + } + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + } diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 index e5f5c28d6fe9..4cb04042f495 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertSharepointQuota.ps1 @@ -16,16 +16,15 @@ function Get-CIPPAlertSharepointQuota { $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 - if ($sharepointQuota) { - if ($InputValue -Is [Boolean]) { $Value = 90 } else { $Value = $InputValue } - $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) - if ($UsedStoragePercentage -gt $Value) { - $AlertData = "SharePoint Storage is at $($UsedStoragePercentage)%. Your alert threshold is $($Value)%" - Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData - } - } } catch { + return + } + if ($sharepointQuota) { + if ($InputValue -Is [Boolean]) { $Value = 90 } else { $Value = $InputValue } + $UsedStoragePercentage = [int](($sharepointQuota.GeoUsedStorageMB / $sharepointQuota.TenantStorageMB) * 100) + if ($UsedStoragePercentage -gt $Value) { + $AlertData = "SharePoint Storage is at $($UsedStoragePercentage)%. Your alert threshold is $($Value)%" + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + } } - - } \ No newline at end of file From 666e1e336943d95efd3b60a275f9d5d0f464905d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 19:56:02 +0200 Subject: [PATCH 054/138] Add CloudMessageRecall standard --- .../Invoke-CIPPStandardCloudMessageRecall.ps1 | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 new file mode 100644 index 000000000000..4994b6cf91c1 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -0,0 +1,48 @@ +function Invoke-CIPPStandardCloudMessageRecall { + <# + .FUNCTIONALITY + 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 'MessageRecallEnabled: Invalid state parameter set' -sev Error + Exit + } + + $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) { + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ MessageRecallEnabled = $WantedState } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set the tenant Message Recall state to $($Settings.state)" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set the tenant Message Recall state to $($Settings.state). Error: $ErrorMessage" -sev Error + } + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Message Recall state is already set correctly to $($Settings.state)" -sev Info + } + + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Message Recall is set correctly to $($Settings.state)" -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Message Recall 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 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + } + +} \ No newline at end of file From d55c2b2ac072f062748978bcfb27c4ebb66971c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 21:13:49 +0200 Subject: [PATCH 055/138] Add TeamsMeetingsByDefault standard --- ...oke-CIPPStandardTeamsMeetingsByDefault.ps1 | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 new file mode 100644 index 000000000000..0c836bd682b5 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -0,0 +1,48 @@ +function Invoke-CIPPStandardTeamsMeetingsByDefault { + <# + .FUNCTIONALITY + 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 'TeamsMeetingsByDefault: Invalid state parameter set' -sev Error + Exit + } + + $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) { + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ OnlineMeetingsByDefaultEnabled = $WantedState } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set the tenant TeamsMeetingsByDefault state to $($Settings.state)" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set the tenant TeamsMeetingsByDefault state to $($Settings.state). Error: $ErrorMessage" -sev Error + } + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant TeamsMeetingsByDefault state is already set correctly to $($Settings.state)" -sev Info + } + + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant TeamsMeetingsByDefault is set correctly to $($Settings.state)" -sev Info + } else { + 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 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + } + +} \ No newline at end of file From 3894994de58182e26d969309d3a1a50e491b2873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 21:18:39 +0200 Subject: [PATCH 056/138] Forgot report fieldname --- .../Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 0c836bd682b5..86509c52564b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { 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 + Add-CIPPBPAField -FieldName 'TeamsMeetingsByDefault' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant } } \ No newline at end of file From b45f74cb608fbfa911888d44abc5273e2ed257f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Fri, 31 May 2024 21:32:04 +0200 Subject: [PATCH 057/138] Add bookings standard --- .../Standards/Invoke-CIPPStandardBookings.ps1 | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 new file mode 100644 index 000000000000..24d4a7c0ee3b --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -0,0 +1,48 @@ +function Invoke-CIPPStandardBookings { + <# + .FUNCTIONALITY + 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 'BookingsEnabled: Invalid state parameter set' -sev Error + Exit + } + + $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.remediate -eq $true) { + Write-Host 'Time to remediate' + if ($StateIsCorrect -eq $false) { + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ BookingsEnabled = $WantedState } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set the tenant Bookings state to $($Settings.state)" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set the tenant Bookings state to $($Settings.state). Error: $ErrorMessage" -sev Error + } + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Bookings state is already set correctly to $($Settings.state)" -sev Info + } + + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Bookings is set correctly to $($Settings.state)" -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Bookings 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 'BookingsState' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + } + +} \ No newline at end of file From 4764eb8a9154d79c7877e120e330360f0c208c7d Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 31 May 2024 15:46:52 -0400 Subject: [PATCH 058/138] 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 23900d674daa..dfa102a57492 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.3 \ No newline at end of file +5.7.4 From cb53d870c0d22d8c1279e161c7ef7e046b629052 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 2 Jun 2024 12:54:35 -0400 Subject: [PATCH 059/138] Change Role permission --- .../Users/Invoke-ExecJITAdmin.ps1 | 52 +++++++++++++++++++ .../Public/Entrypoints/Invoke-ListRoles.ps1 | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 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 new file mode 100644 index 000000000000..ab2cc1ecd5b2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -0,0 +1,52 @@ +using namespace System.Net + +Function Invoke-ExecJITAdmin { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.Role.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' + #If UserId is a guid, get the user's UPN + 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 + } + if ($Request.body.vacation -eq 'true') { + $StartDate = $Request.body.StartDate + $TaskBody = @{ + TenantFilter = $Request.body.TenantFilter + Name = "Add CA Exclusion Vacation Mode: $Username - $($Request.body.TenantFilter)" + Command = @{ + value = 'Set-CIPPCAExclusion' + label = 'Set-CIPPCAExclusion' + } + Parameters = @{ + ExclusionType = 'Add' + UserID = $Request.body.UserID + PolicyId = $Request.body.PolicyId + UserName = $Username + } + ScheduledTime = $StartDate + } + Add-CIPPScheduledTask -Task $TaskBody -hidden $false + #Removal of the exclusion + $TaskBody.Parameters.ExclusionType = 'Remove' + $TaskBody.Name = "Remove CA Exclusion Vacation Mode: $username - $($Request.body.TenantFilter)" + $TaskBody.ScheduledTime = $Request.body.EndDate + Add-CIPPScheduledTask -Task $TaskBody -hidden $false + $body = @{ Results = "Successfully added vacation mode schedule for $Username." } + } else { + Set-CIPPCAExclusion -TenantFilter $Request.body.TenantFilter -ExclusionType $Request.body.ExclusionType -UserID $Request.body.UserID -PolicyId $Request.body.PolicyId -executingUser $request.headers.'x-ms-client-principal' -UserName $Username + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 index 9f17fde986f1..b56c40828a63 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoles.ps1 @@ -5,7 +5,7 @@ Function Invoke-ListRoles { .FUNCTIONALITY Entrypoint .ROLE - Tenant.Directory.Read + Identity.Role.Read #> [CmdletBinding()] param($Request, $TriggerMetadata) From f4e4b10e5eb84c9c00b63356d5f937c5de5e5964 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Sun, 2 Jun 2024 12:58:31 -0400 Subject: [PATCH 060/138] Update Invoke-ExecJITAdmin.ps1 --- .../Administration/Users/Invoke-ExecJITAdmin.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 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 ab2cc1ecd5b2..15c879d16589 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 @@ -16,17 +16,17 @@ Function Invoke-ExecJITAdmin { 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 } - if ($Request.body.vacation -eq 'true') { + <#if ($Request.body.vacation -eq 'true') { $StartDate = $Request.body.StartDate $TaskBody = @{ TenantFilter = $Request.body.TenantFilter - Name = "Add CA Exclusion Vacation Mode: $Username - $($Request.body.TenantFilter)" + Name = "Set JIT Admin: $Username - $($Request.body.TenantFilter)" Command = @{ - value = 'Set-CIPPCAExclusion' - label = 'Set-CIPPCAExclusion' + value = 'Set-CIPPJITAdmin' + label = 'Set-CIPPJITAdmin' } Parameters = @{ - ExclusionType = 'Add' + UserType = 'Add' UserID = $Request.body.UserID PolicyId = $Request.body.PolicyId UserName = $Username @@ -42,7 +42,7 @@ Function Invoke-ExecJITAdmin { $body = @{ Results = "Successfully added vacation mode schedule for $Username." } } else { Set-CIPPCAExclusion -TenantFilter $Request.body.TenantFilter -ExclusionType $Request.body.ExclusionType -UserID $Request.body.UserID -PolicyId $Request.body.PolicyId -executingUser $request.headers.'x-ms-client-principal' -UserName $Username - } + }#> Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK From 8c4005a5bcebdb6dafe7bafb5c68c53396664d05 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 3 Jun 2024 14:38:30 +0200 Subject: [PATCH 061/138] Added Malware Filter Rule --- ...Invoke-CIPPStandardMalwareFilterPolicy.ps1 | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index 178c5b048861..b2856a8031f7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -21,6 +21,17 @@ function Invoke-CIPPStandardMalwareFilterPolicy { ($CurrentState.EnableExternalSenderAdminNotifications -eq $Settings.EnableExternalSenderAdminNotifications) -and (($null -eq $Settings.ExternalSenderAdminAddress) -or ($CurrentState.ExternalSenderAdminAddress -eq $Settings.ExternalSenderAdminAddress)) + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $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 + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + if ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { @@ -52,6 +63,29 @@ function Invoke-CIPPStandardMalwareFilterPolicy { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Malware Filter Policy. Error: $ErrorMessage" -sev Error } } + + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + MalwareFilterPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + try { + if ($RuleState.Name -eq "CIPP $PolicyName") { + $cmdparams.Add('Identity', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MalwareFilterRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Malware Filter Rule' -sev Info + } else { + $cmdparams.Add('Name', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'New-MalwareFilterRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created Malware Filter Rule' -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Malware Filter Rule. Error: $ErrorMessage" -sev Error + } + } } if ($Settings.alert -eq $true) { @@ -67,4 +101,4 @@ function Invoke-CIPPStandardMalwareFilterPolicy { Add-CIPPBPAField -FieldName 'MalwareFilterPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} From 8e6048ea3416bc7cd34f88ab428bfa317cf832c2 Mon Sep 17 00:00:00 2001 From: Esco Date: Mon, 3 Jun 2024 14:58:44 +0200 Subject: [PATCH 062/138] Added FilesTypes to Policy --- .../Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index b2856a8031f7..d9ae65ac222f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -9,11 +9,12 @@ function Invoke-CIPPStandardMalwareFilterPolicy { $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterPolicy' | Where-Object -Property Name -EQ $PolicyName | - Select-Object Name, EnableFileFilter, FileTypeAction, ZapEnabled, QuarantineTag, EnableInternalSenderAdminNotifications, InternalSenderAdminAddress, EnableExternalSenderAdminNotifications, ExternalSenderAdminAddress + Select-Object Name, EnableFileFilter, FileTypeAction, FileTypes, ZapEnabled, QuarantineTag, EnableInternalSenderAdminNotifications, InternalSenderAdminAddress, EnableExternalSenderAdminNotifications, ExternalSenderAdminAddress $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and ($CurrentState.EnableFileFilter -eq $true) -and ($CurrentState.FileTypeAction -eq $Settings.FileTypeAction) -and + ($null -ne $CurrentState.FileTypes) -and ($CurrentState.ZapEnabled -eq $true) -and ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and ($CurrentState.EnableInternalSenderAdminNotifications -eq $Settings.EnableInternalSenderAdminNotifications) -and @@ -48,6 +49,12 @@ function Invoke-CIPPStandardMalwareFilterPolicy { ExternalSenderAdminAddress = $Settings.ExternalSenderAdminAddress } + if ($null -eq $CurrentState.FileTypes) { + $cmdparams.Add('FileTypes', @('ace', 'ani', 'apk', 'app', 'appx', 'arj', 'bat', 'cab', 'cmd', 'com', 'deb', 'dex', 'dll', 'docm', 'elf', 'exe', 'hta', 'img', 'iso', 'jar', 'jnlp', 'kext', 'lha', 'lib', 'library', 'lnk', 'lzh', 'macho', 'msc', 'msi', 'msix', 'msp', 'mst', 'pif', 'ppa', 'ppam', 'reg', 'rev', 'scf', 'scr', 'sct', 'sys', 'uif', 'vb', 'vbe', 'vbs', 'vxd', 'wsc', 'wsf', 'wsh', 'xll', 'xz', 'z')) + } else { + $cmdparams.Add('FileTypes', $CurrentState.FileTypes) + } + try { if ($CurrentState.Name -eq $PolicyName) { $cmdparams.Add('Identity', $PolicyName) From ce4b4320bdc3decfc1ec68a5350738bfc011fe21 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 10:12:14 -0400 Subject: [PATCH 063/138] Fix cache clear errors --- .../Activity Triggers/Push-UpdateTenants.ps1 | 15 +++++++++-- .../Tenant/Invoke-ListTenants.ps1 | 26 ++++++++++++++----- .../Public/GraphHelper/Remove-CIPPCache.ps1 | 19 +++++++++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 index f60a27a57b26..811d54b229be 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 @@ -10,13 +10,24 @@ function Push-UpdateTenants { Write-Host 'Update Tenants already running' return } - $Queue = New-CippQueueEntry -Name 'Update Tenants' -Reference $QueueReference + $Queue = New-CippQueueEntry -Name 'Update Tenants' -Reference $QueueReference -TotalTasks 1 try { + $QueueTask = @{ + QueueId = $Queue.RowKey + Name = 'Get tenant list' + Status = 'Running' + } + $TaskStatus = Set-CippQueueTask @QueueTask + $QueueTask.TaskId = $TaskStatus.RowKey Update-CippQueueEntry -RowKey $Queue.RowKey -Status 'Running' - Get-Tenants | Out-Null + Get-Tenants -IncludeAll -TriggerRefresh | Out-Null Update-CippQueueEntry -RowKey $Queue.RowKey -Status 'Completed' + $QueueTask.Status = 'Completed' + Set-CippQueueTask @QueueTask } catch { Write-Host "Queue Error: $($_.Exception.Message)" Update-CippQueueEntry -RowKey $Queue.RowKey -Status 'Failed' + $QueueTask.Status = 'Failed' + Set-CippQueueTask @QueueTask } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 index 67b0d6562ec7..7e3d3da4e22c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 @@ -12,7 +12,7 @@ Function Invoke-ListTenants { $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantAccess = Test-CIPPAccess -Request $Request -TenantList if ($TenantAccess -notcontains 'AllTenants') { @@ -22,17 +22,29 @@ Function Invoke-ListTenants { } # Clear Cache - if ($request.Query.ClearCache -eq 'true') { - Remove-CIPPCache -tenantsOnly $request.query.TenantsOnly - $GraphRequest = [pscustomobject]@{'Results' = 'Successfully completed request.' } + if ($Request.Query.ClearCache -eq $true) { + Remove-CIPPCache -tenantsOnly $Request.Query.TenantsOnly + + $InputObject = [PSCustomObject]@{ + Batch = @( + @{ + FunctionName = 'UpdateTenants' + } + ) + OrchestratorName = 'UpdateTenants' + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) + + $GraphRequest = [pscustomobject]@{'Results' = 'Cache has been cleared and a tenant refresh is queued.' } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $GraphRequest }) - Get-Tenants -IncludeAll -TriggerRefresh - + #Get-Tenants -IncludeAll -TriggerRefresh + return } - if ($Request.query.TriggerRefresh) { + if ($Request.Query.TriggerRefresh) { Get-Tenants -IncludeAll -TriggerRefresh } try { diff --git a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 index 1bbab4a3f025..99057374f0de 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 @@ -9,9 +9,12 @@ function Remove-CIPPCache { # Remove all tenants except excluded $TenantsTable = Get-CippTable -tablename 'Tenants' $Filter = "PartitionKey eq 'Tenants' and Excluded eq false" - $ClearIncludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - Remove-AzDataTableEntity @TenantsTable -Entity $ClearIncludedTenants - if ($tenantsonly -eq 'false') { + $ClearIncludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter -Property PartitionKey, RowKey + if ($ClearIncludedTenants) { + Remove-AzDataTableEntity @TenantsTable -Entity $ClearIncludedTenants + } + + if ($TenantsOnly -eq 'false') { Write-Host 'Clearing all' # Remove Domain Analyser cached results $DomainsTable = Get-CippTable -tablename 'Domains' @@ -20,11 +23,15 @@ function Remove-CIPPCache { $_.DomainAnalyser = '' $_ } - Update-AzDataTableEntity @DomainsTable -Entity $ClearDomainAnalyserRows + if ($ClearDomainAnalyserRows) { + Update-AzDataTableEntity @DomainsTable -Entity $ClearDomainAnalyserRows + } #Clear BPA - $BPATable = Get-CippTable -tablename 'cachebpa' + $BPATable = Get-CippTable -tablename 'cachebpav2' $ClearBPARows = Get-CIPPAzDataTableEntity @BPATable - Remove-AzDataTableEntity @BPATable -Entity $ClearBPARows + if ($ClearBPARows) { + Remove-AzDataTableEntity @BPATable -Entity $ClearBPARows + } $ENV:SetFromProfile = $null $Script:SkipListCache = $Null $Script:SkipListCacheEmpty = $Null From fcd5f6e4637f77625dfa0cb477602f8825f5614c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 11:12:50 -0400 Subject: [PATCH 064/138] Durable clear on version change --- .../CIPPCore/Public/Clear-CippDurables.ps1 | 62 +++++++++++++++++++ .../CIPP/Core/Invoke-ExecDurableFunctions.ps1 | 8 ++- profile.ps1 | 17 +++++ 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 Modules/CIPPCore/Public/Clear-CippDurables.ps1 diff --git a/Modules/CIPPCore/Public/Clear-CippDurables.ps1 b/Modules/CIPPCore/Public/Clear-CippDurables.ps1 new file mode 100644 index 000000000000..eb1949a39078 --- /dev/null +++ b/Modules/CIPPCore/Public/Clear-CippDurables.ps1 @@ -0,0 +1,62 @@ +function Clear-CippDurables { + [CmdletBinding(SupportsShouldProcess = $true)] + Param() + # Collect info + $StorageContext = New-AzStorageContext -ConnectionString $env:AzureWebJobsStorage + $FunctionName = $env:WEBSITE_SITE_NAME + + # Get orchestrators + $InstancesTable = Get-CippTable -TableName ('{0}Instances' -f $FunctionName) + $HistoryTable = Get-CippTable -TableName ('{0}History' -f $FunctionName) + $Yesterday = (Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $Filter = "CreatedTime ge datetime'$Yesterday' or RuntimeStatus eq 'Pending' or RuntimeStatus eq 'Running'" + $Instances = Get-CippAzDataTableEntity @InstancesTable -Filter $Filter + + $Queues = Get-AzStorageQueue -Context $StorageContext -Name ('{0}*' -f $FunctionName) | Select-Object -Property Name, ApproximateMessageCount, QueueClient + + $RunningQueues = $Queues | Where-Object { $_.ApproximateMessageCount -gt 0 } + foreach ($Queue in $RunningQueues) { + Write-Information "- Removing queue: $($Queue.Name), message count: $($Queue.ApproximateMessageCount)" + if ($PSCmdlet.ShouldProcess($Queue.Name, 'Clear Queue')) { + $Queue.QueueClient.ClearMessagesAsync() + } + } + + $QueueTable = Get-CippTable -TableName 'CippQueue' + $CippQueue = Invoke-ListCippQueue + $QueueEntities = foreach ($Queue in $CippQueue) { + if ($Queue.Status -eq 'Running') { + $Queue.TotalTasks = $Queue.CompletedTasks + $Queue | Select-Object -Property PartitionKey, RowKey, TotalTasks + } + } + if (($QueueEntities | Measure-Object).Count -gt 0) { + if ($PSCmdlet.ShouldProcess('Queues', 'Mark Failed')) { + Update-AzDataTableEntity @QueueTable -Entity $QueueEntities + } + } + + $CippQueueTasks = Get-CippTable -TableName 'CippQueueTasks' + $RunningTasks = Get-CIPPAzDataTableEntity @CippQueueTasks -Filter "Status eq 'Running'" -Property RowKey, PartitionKey, Status + if (($RunningTasks | Measure-Object).Count -gt 0) { + if ($PSCmdlet.ShouldProcess('Tasks', 'Mark Failed')) { + $UpdatedTasks = foreach ($Task in $RunningTasks) { + $Task.Status = 'Failed' + $Task + } + Update-AzDataTableEntity @CippQueueTasks -Entity $UpdatedTasks + } + } + + Remove-AzDataTable @InstancesTable + Remove-AzDataTable @HistoryTable + $BlobContainer = '{0}-largemessages' -f $Function.Name + if (Get-AzStorageContainer -Name $BlobContainer -Context $StorageContext -ErrorAction SilentlyContinue) { + Write-Information "- Removing blob container: $BlobContainer" + if ($PSCmdlet.ShouldProcess($BlobContainer, 'Remove Blob Container')) { + Remove-AzStorageContainer -Name $BlobContainer -Context $StorageContext -Confirm:$false -Force + } + } + $null = Get-CippTable -TableName ('{0}History' -f $FunctionName) + Write-Information 'Durable Orchestrators and Queues have been cleared' +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 index c2c194438e96..09da6bd2c990 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 @@ -141,9 +141,13 @@ function Invoke-ExecDurableFunctions { $HistoryTable = Get-CippTable -TableName ('{0}History' -f $FunctionName) if ($Request.Query.PartitionKey) { $HistoryEntities = Get-CIPPAzDataTableEntity @HistoryTable -Filter "PartitionKey eq '$($Request.Query.PartitionKey)'" -Property RowKey, PartitionKey - Remove-AzDataTableEntity @HistoryTable -Entity $HistoryEntities + if ($HistoryEntities) { + Remove-AzDataTableEntity @HistoryTable -Entity $HistoryEntities + } $Instance = Get-CIPPAzDataTableEntity @InstancesTable -Filter "PartitionKey eq '$($Request.Query.PartitionKey)'" -Property RowKey, PartitionKey - Remove-AzDataTableEntity @InstancesTable -Entity $Instance + if ($Instance) { + Remove-AzDataTableEntity @InstancesTable -Entity $Instance + } $Body = [PSCustomObject]@{ Results = 'Orchestrator {0} purged successfully' -f $Request.Query.PartitionKey } diff --git a/profile.ps1 b/profile.ps1 index 1aa6a00d98c6..134944f4d7e7 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -46,6 +46,23 @@ try { Write-LogMessage -message 'Could not retrieve keys from Keyvault' -LogData (Get-CippException -Exception $_) -Sev 'debug' } +$CurrentVersion = (Get-Content .\version_latest.txt).trim() +$Table = Get-CippTable -tablename 'Version' +$LastStartup = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Version' and RowKey eq 'Version'" +if ($CurrentVersion -ne $LastStartup.Version) { + Write-Host "Version has changed from $($LastStartup.Version) to $CurrentVersion" + Clear-CippDurables + if ($LastStartup) { + $LastStartup.Version = $CurrentVersion + } else { + $LastStartup = [PSCustomObject]@{ + PartitionKey = 'Version' + RowKey = 'Version' + Version = $CurrentVersion + } + } + Update-AzDataTableEntity @Table -Entity $LastStartup +} # Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell. # Enable-AzureRmAlias From b71dfb3dffec98072adc14feed2b1ec1410f4c76 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 11:22:29 -0400 Subject: [PATCH 065/138] Fix tenant access check --- .../CIPP/Settings/Invoke-ExecAccessChecks.ps1 | 10 +++++----- Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 | 7 ++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 index 019e3af0997e..f655b21c2a91 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 @@ -16,14 +16,14 @@ Function Invoke-ExecAccessChecks { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - if ($Request.query.Permissions -eq 'true') { - $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:tenantid -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + if ($Request.Query.Permissions -eq 'true') { + $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:tenantid -APIName $APINAME -ExecutingUser $Request.Headers.'x-ms-client-principal' } - if ($Request.query.Tenants -eq 'true') { - $Results = Test-CIPPAccessTenant -Tenantcsv $Request.body.TenantId + if ($Request.Query.Tenants -eq 'true') { + $Results = Test-CIPPAccessTenant -TenantCSV $Request.Body.tenantid } - if ($Request.query.GDAP -eq 'true') { + if ($Request.Query.GDAP -eq 'true') { $Results = Test-CIPPGDAPRelationships } diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 index 014218b3cc16..842b4f4b66aa 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 @@ -22,9 +22,6 @@ function Test-CIPPAccessTenant { $Tenants = ($TenantCSV).split(',') if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } $TenantList = Get-Tenants - $TenantIds = foreach ($Tenant in $Tenants) { - ($TenantList | Where-Object { $_.defaultDomainName -eq $Tenant }).customerId - } $results = foreach ($tenant in $Tenants) { $AddedText = '' @@ -32,9 +29,9 @@ function Test-CIPPAccessTenant { $TenantId = ($TenantList | Where-Object { $_.defaultDomainName -eq $tenant }).customerId $BulkRequests = $ExpectedRoles | ForEach-Object { @( @{ - id = "roleManagement_$($_.id)" + id = "roleManagement_$($_.Id)" method = 'GET' - url = "roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '$($_.id)'&`$expand=principal" + url = "roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '$($_.Id)'&`$expand=principal" } ) } From 16bd1f120d47df6050d4125e5079c00b498b4742 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 13:06:30 -0400 Subject: [PATCH 066/138] JIT Admin --- .../Users/Invoke-ExecJITAdmin.ps1 | 45 ++++++++++- .../Public/Get-CIPPSchemaExtensions.ps1 | 79 +++++++++++++++++++ .../Public/Set-CIPPSchemaExtension.ps1 | 52 ------------ .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 24 ++++-- 4 files changed, 137 insertions(+), 63 deletions(-) create mode 100644 Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 delete mode 100644 Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 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 15c879d16589..5ca4705ad81f 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 @@ -11,11 +11,48 @@ Function Invoke-ExecJITAdmin { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - #If UserId is a guid, get the user's UPN - 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 'Accessed this API' -Sev 'Debug' + Write-Information ($Request.Body | ConvertTo-Json -Depth 10) + if ($Request.Query.Action -eq 'List') { + $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } + Write-Information "Schema: $($Schema)" + $Query = @{ + TenantFilter = $Request.Query.TenantFilter + Endpoint = 'users' + Parameters = @{ + '$count' = 'true' + '$select' = "id,displayName,userPrincipalName,$($Schema.id)" + '$filter' = "$($Schema.id)/jitAdminEnabled eq true or $($Schema.id)/jitAdminEnabled eq false" + } + } + $Users = Get-GraphRequestList @Query | Where-Object { $_.id } + $Results = $Users | ForEach-Object { + $MemberOf = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName" -tenantid $Request.Query.TenantFilter -ComplexFilter + [PSCustomObject]@{ + id = $_.id + displayName = $_.displayName + userPrincipalName = $_.userPrincipalName + jitAdminEnabled = $_.($Schema.id).jitAdminEnabled + jitAdminExpiration = $_.($Schema.id).jitAdminExpiration + memberOf = $MemberOf + } + } + + + Write-Information ($Results | ConvertTo-Json -Depth 10) + $Body = @{ + Results = @($Results) + Metadata = @{ + Parameters = $Query.Parameters + } + } + } else { + #If UserId is a guid, get the user's UPN + 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 + } } + <#if ($Request.body.vacation -eq 'true') { $StartDate = $Request.body.StartDate $TaskBody = @{ diff --git a/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 b/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 new file mode 100644 index 000000000000..26794daffea7 --- /dev/null +++ b/Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1 @@ -0,0 +1,79 @@ +function Get-CIPPSchemaExtensions { + [CmdletBinding()] + Param() + + $Schemas = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/schemaExtensions?`$filter=owner eq '$($env:applicationid)' and status eq 'Available'" -NoAuthCheck $true -AsApp $true + + $SchemaDefinitions = [PSCustomObject]@( + @{ + id = 'cippUser' + description = 'CIPP User Schema' + targetTypes = @('User') + properties = @( + @{ + name = 'jitAdminEnabled' + type = 'Boolean' + } + @{ + name = 'jitAdminExpiration' + type = 'DateTime' + } + @{ + name = 'mailboxType' + type = 'String' + } + @{ + name = 'archiveEnabled' + type = 'Boolean' + } + @{ + name = 'autoExpandingArchiveEnabled' + type = 'Boolean' + } + ) + } + ) + foreach ($SchemaDefinition in $SchemaDefinitions) { + $SchemaFound = $false + foreach ($Schema in $Schemas) { + if ($Schema.id -match $SchemaDefinition.id) { + $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 ($Schema.status -ne 'Available') { + $Patch.status = 'Available' + } + if ($Schema.targetTypes -ne $SchemaDefinition.targetTypes) { + $Patch.targetTypes = $SchemaDefinition.targetTypes + } + if ($Patch.Keys.Count -gt 0) { + Write-Information "Updating $($Schema.id)" + $Json = ConvertTo-Json -Depth 5 -InputObject $Patch + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true + } else { + $Schema + } + } + } + if (!$SchemaFound) { + Write-Information "Creating Schema Extension for $($SchemaDefinition.id)" + $Body = [PSCustomObject]@{ + id = 'cippUser' + description = 'CIPP User' + targetTypes = $SchemaDefinition.TargetTypes + properties = $SchemaDefinition.Properties + } + + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + $Schema = New-GraphPOSTRequest -type POST -Uri 'https://graph.microsoft.com/v1.0/schemaExtensions' -Body $Json -AsApp $true -NoAuthCheck $true + $Patch = [PSCustomObject]@{ + status = 'Available' + } + $PatchJson = ConvertTo-Json -Depth 5 -InputObject $Patch + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $PatchJson -AsApp $true -NoAuthCheck $true + } + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 b/Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 deleted file mode 100644 index 111e02daa7d1..000000000000 --- a/Modules/CIPPCore/Public/Set-CIPPSchemaExtension.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -function Set-CIPPSchemaExtension { - [CmdletBinding()] - Param() - - $Schema = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/schemaExtensions?`$filter=owner eq '$($env:applicationid)'" -NoAuthCheck $true -AsApp $true - - $Properties = [PSCustomObject]@( - @{ - name = 'jitAdminEnabled' - type = 'Boolean' - } - @{ - name = 'jitAdminExpiration' - type = 'DateTime' - } - ) - $TargetTypes = @('User') - - if (!$Schema.id) { - $Body = [PSCustomObject]@{ - id = 'cippSchema' - description = 'CIPP Schema Extension' - targetTypes = $TargetTypes - properties = $Properties - } - - $Json = ConvertTo-Json -Depth 5 -InputObject $Body - Write-Host $Json - $Schema = New-GraphPOSTRequest -type POST -Uri 'https://graph.microsoft.com/v1.0/schemaExtensions' -Body $Json -AsApp $true -NoAuthCheck $true - $Schema.status = 'Available' - New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true - } else { - $Schema = $Schema | Where-Object { $_.id -match 'cippSchema' } - $Patch = @{} - if (Compare-Object -ReferenceObject ($Properties | Select-Object name, type) -DifferenceObject $Schema.properties) { - $Patch.properties = $Properties - } - if ($Schema.status -ne 'Available') { - $Patch.status = 'Available' - } - if ($Schema.targetTypes -ne $TargetTypes) { - $Patch.targetTypes = $TargetTypes - } - - if ($Patch.Keys.Count -gt 0) { - $Json = ConvertTo-Json -Depth 5 -InputObject $Patch - New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true - } else { - $Schema - } - } -} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 143d12ae02b5..1eeef4afbecd 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -4,17 +4,27 @@ function Set-CIPPUserJITAdmin { [string]$TenantFilter, [string]$UserId, [switch]$Enabled, - $Expiration + $Expiration, + [switch]$Clear ) - $Schema = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/schemaExtensions?`$filter=owner eq '$($env:applicationid)'" -NoAuthCheck $true -AsApp $true | Where-Object { $_.owner -eq $env:applicationid } - $Body = [PSCustomObject]@{ - "$($Schema.id)" = @{ - jitAdminEnabled = $Enabled.IsPresent - jitAdminExpiration = $Expiration + $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } + if ($Clear.IsPresent) { + $Body = [PSCustomObject]@{ + "$($Schema.id)" = @{ + jitAdminEnabled = $null + jitAdminExpiration = $null + } + } + } else { + $Body = [PSCustomObject]@{ + "$($Schema.id)" = @{ + jitAdminEnabled = $Enabled.IsPresent + jitAdminExpiration = $Expiration.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + } } } + $Json = ConvertTo-Json -Depth 5 -InputObject $Body - Write-Host $Json New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter } \ No newline at end of file From 2481a8315dcc978b2704f8e9b508f12b44ef9032 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 13:25:02 -0400 Subject: [PATCH 067/138] Add Application.ReadWrite.All - Application --- Modules/CIPPCore/Public/SAMManifest.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index 4fce3279465c..3ee73e6b09d1 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -155,9 +155,10 @@ { "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": "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" } ] }, { From 82da597161decb45c790e6b55a4071dffe4cab50 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 14:19:40 -0400 Subject: [PATCH 068/138] Fix license report --- .../Public/Entrypoints/Invoke-ListLicenses.ps1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 index 1fc0f4ca57e9..82bb1e4aab1f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 @@ -49,9 +49,13 @@ Function Invoke-ListLicenses { Write-Host "Started permissions orchestration with ID = '$InstanceId'" } } else { - $GraphRequest = $Rows | ForEach-Object { - $TermInfo = $_.TermInfo | ConvertFrom-Json -ErrorAction SilentlyContinue - $_.TermInfo = $TermInfo + $GraphRequest = $Rows | Where-Object { $_.License } | ForEach-Object { + if ($_.TermInfo) { + $TermInfo = $_.TermInfo | ConvertFrom-Json -ErrorAction SilentlyContinue + $_.TermInfo = $TermInfo + } else { + $_ | Add-Member -NotePropertyName TermInfo -NotePropertyValue $null + } $_ } } From b4a58fd86dbd9146fb30b4b2a42fae9658cb7cad Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 15:17:17 -0400 Subject: [PATCH 069/138] JIT Admin functions --- .../Users/Invoke-ExecJITAdmin.ps1 | 94 ++++++++++++++----- .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 87 +++++++++++++---- .../Public/Set-CIPPUserJITAdminProperties.ps1 | 30 ++++++ 3 files changed, 165 insertions(+), 46 deletions(-) create mode 100644 Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 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 5ca4705ad81f..9d89e0a494d1 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 @@ -12,7 +12,7 @@ Function Invoke-ExecJITAdmin { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - Write-Information ($Request.Body | ConvertTo-Json -Depth 10) + if ($Request.Query.Action -eq 'List') { $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } Write-Information "Schema: $($Schema)" @@ -47,43 +47,85 @@ Function Invoke-ExecJITAdmin { } } } else { - #If UserId is a guid, get the user's UPN + Write-Information ($Request.Body | ConvertTo-Json -Depth 10) 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 } - } - <#if ($Request.body.vacation -eq 'true') { - $StartDate = $Request.body.StartDate - $TaskBody = @{ - TenantFilter = $Request.body.TenantFilter - Name = "Set JIT Admin: $Username - $($Request.body.TenantFilter)" + $Start = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.StartDate)).DateTime.ToLocalTime() + $Expiration = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.EndDate)).DateTime.ToLocalTime() + $Results = [System.Collections.Generic.List[string]]::new() + + if ($Request.Body.useraction -eq 'create') { + Write-Information "Creating JIT Admin user $($Request.Body.UserPrincipalName)" + $JITAdmin = @{ + User = @{ + 'FirstName' = $Request.Body.FirstName + 'LastName' = $Request.Body.LastName + 'UserPrincipalName' = $Request.Body.UserPrincipalName + } + Expiration = $Expiration + Action = 'Create' + } + $CreateResult = Set-CIPPUserJITAdmin @JITAdmin + $Results.Add("Created User: $($CreateResult.userPrincipalName)") + $Results.Add("Password: $($CreateResult.password)") + } + $Parameters = @{ + TenantFilter = $Request.Body.TenantFilter + User = @{ + 'UserPrincipalName' = $Username + } + Roles = $Request.Body.AdminRoles + Action = 'AddRoles' + Expiration = $Expiration + } + if ($Start -gt (Get-Date)) { + $Results.Add("Scheduling JIT Admin enable task for $Username") + $TaskBody = @{ + TenantFilter = $Request.Body.TenantFilter + Name = "JIT Admin (enable): $Username" + Command = @{ + value = 'Set-CIPPUserJITAdmin' + label = 'Set-CIPPUserJITAdmin' + } + Parameters = $Parameters + ScheduledTime = $Request.Body.StartDate + } + Add-CIPPScheduledTask -Task $TaskBody -hidden $false + Set-CIPPUserJITAdminProperties -TenantFilter $Request.Body.TenantFilter -UserId $UserObj.id -Expiration $Expiration + $Results.Add("Scheduled JIT Admin enable task for $Username") + } else { + $Results.Add("Executing JIT Admin enable task for $Username") + Set-CIPPUserJITAdmin @Parameters + } + + $DisableTaskBody = @{ + TenantFilter = $Request.Body.TenantFilter + Name = "JIT Admin (disable): $($Request.Body.UserPrincipalName)" Command = @{ - value = 'Set-CIPPJITAdmin' - label = 'Set-CIPPJITAdmin' + value = 'Set-CIPPUserJITAdmin' + label = 'Set-CIPPUserJITAdmin' } Parameters = @{ - UserType = 'Add' - UserID = $Request.body.UserID - PolicyId = $Request.body.PolicyId - UserName = $Username + TenantFilter = $Request.Body.TenantFilter + User = @{ + 'UserPrincipalName' = $Request.Body.UserPrincipalName + } + Roles = $Request.Body.AdminRoles + Action = $Request.Body.ExpireAction } - ScheduledTime = $StartDate + ScheduledTime = $Request.Body.EndDate } - Add-CIPPScheduledTask -Task $TaskBody -hidden $false - #Removal of the exclusion - $TaskBody.Parameters.ExclusionType = 'Remove' - $TaskBody.Name = "Remove CA Exclusion Vacation Mode: $username - $($Request.body.TenantFilter)" - $TaskBody.ScheduledTime = $Request.body.EndDate - Add-CIPPScheduledTask -Task $TaskBody -hidden $false - $body = @{ Results = "Successfully added vacation mode schedule for $Username." } - } else { - Set-CIPPCAExclusion -TenantFilter $Request.body.TenantFilter -ExclusionType $Request.body.ExclusionType -UserID $Request.body.UserID -PolicyId $Request.body.PolicyId -executingUser $request.headers.'x-ms-client-principal' -UserName $Username - }#> + Add-CIPPScheduledTask -Task $DisableTaskBody -hidden $false + $Results.Add("Scheduled JIT Admin disable task for $Username") + $Body = @{ + Results = @($Results) + } + } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Body }) - } diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 1eeef4afbecd..0848966155b9 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -1,30 +1,77 @@ function Set-CIPPUserJITAdmin { - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess = $true)] Param( [string]$TenantFilter, - [string]$UserId, - [switch]$Enabled, - $Expiration, - [switch]$Clear + $User, + [string[]]$Roles, + [string]$Action, + $Expiration ) - $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } - if ($Clear.IsPresent) { - $Body = [PSCustomObject]@{ - "$($Schema.id)" = @{ - jitAdminEnabled = $null - jitAdminExpiration = $null - } + if ($PSCmdlet.ShouldProcess("User: $($User.UserPrincipalName)", "Action: $Action")) { + if ($Action -ne 'Create') { + $UserObj = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/users/$($User.UserPrincipalName)" -tenantid $TenantFilter } - } else { - $Body = [PSCustomObject]@{ - "$($Schema.id)" = @{ - jitAdminEnabled = $Enabled.IsPresent - jitAdminExpiration = $Expiration.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + + switch ($Action) { + 'Create' { + $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } + $Body = @{ + accountEnabled = $true + displayName = $User.FirstName + ' ' + $User.LastName + userPrincipalName = $User.UserPrincipalName + passwordProfile = @{ + forceChangePasswordNextSignIn = $true + password = New-passwordString + } + "$($Schema.id)" = @{ + jitAdminEnabled = $false + jitAdminExpiration = $Expiration.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + } + } + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + $NewUser = New-GraphPOSTRequest -Uri 'https://graph.microsoft.com/beta/users' -Body $Json -tenantid $TenantFilter + [PSCustomObject]@{ + id = $NewUser.id + userPrincipalName = $NewUser.userPrincipalName + password = $Body.passwordProfile.password + } + } + 'AddRoles' { + $Roles = $Roles | ForEach-Object { + try { + $Body = @{ + '@odata.id' = "https://graph.microsoft.com/v1.0/directoryObjects/$($UserObj.id)" + } + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/`$ref" -tenantid $TenantFilter -body $Json + } finally {} + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration + return "Added admin roles to user $($UserObj.displayName) ($($UserObj.userPrincipalName))" + } + } + 'RemoveRoles' { + $Roles = $Roles | ForEach-Object { + try { + $null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/$($UserObj.id)/`$ref" -tenantid $TenantFilter + } finally {} + } + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Clear + return "Removed admin roles from user $($UserObj.displayName)" + } + 'DeleteUser' { + $null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $TenantFilter + return "Deleted user $($UserObj.displayName) ($($UserObj.userPrincipalName)) with id $($UserObj.id)" + } + 'DisableUser' { + $Body = @{ + accountEnabled = $false + } + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + 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 + return "Disabled user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } } } - - $Json = ConvertTo-Json -Depth 5 -InputObject $Body - New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 new file mode 100644 index 000000000000..21e2a7d19bfb --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 @@ -0,0 +1,30 @@ +function Set-CIPPUserJITAdminProperties { + [CmdletBinding()] + Param( + [string]$TenantFilter, + [string]$UserId, + [switch]$Enabled, + $Expiration, + [switch]$Clear + ) + + $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } + if ($Clear.IsPresent) { + $Body = [PSCustomObject]@{ + "$($Schema.id)" = @{ + jitAdminEnabled = $null + jitAdminExpiration = $null + } + } + } else { + $Body = [PSCustomObject]@{ + "$($Schema.id)" = @{ + jitAdminEnabled = $Enabled.IsPresent + jitAdminExpiration = $Expiration.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + } + } + } + + $Json = ConvertTo-Json -Depth 5 -InputObject $Body + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter +} \ No newline at end of file From 08bf03446324f0414172c8689bfe71d26ad94b9f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 16:09:51 -0400 Subject: [PATCH 070/138] Fix JIT bug --- .../Administration/Users/Invoke-ExecJITAdmin.ps1 | 16 ++++++++-------- Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 4 ++-- .../Public/Set-CIPPUserJITAdminProperties.ps1 | 1 + 3 files changed, 11 insertions(+), 10 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 9d89e0a494d1..ec5dbb935a9a 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 @@ -48,8 +48,8 @@ Function Invoke-ExecJITAdmin { } } else { Write-Information ($Request.Body | ConvertTo-Json -Depth 10) - 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 + 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 } $Start = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.StartDate)).DateTime.ToLocalTime() @@ -68,6 +68,7 @@ Function Invoke-ExecJITAdmin { Action = 'Create' } $CreateResult = Set-CIPPUserJITAdmin @JITAdmin + $Username = $CreateResult.userPrincipalName $Results.Add("Created User: $($CreateResult.userPrincipalName)") $Results.Add("Password: $($CreateResult.password)") } @@ -81,7 +82,6 @@ Function Invoke-ExecJITAdmin { Expiration = $Expiration } if ($Start -gt (Get-Date)) { - $Results.Add("Scheduling JIT Admin enable task for $Username") $TaskBody = @{ TenantFilter = $Request.Body.TenantFilter Name = "JIT Admin (enable): $Username" @@ -93,8 +93,8 @@ Function Invoke-ExecJITAdmin { ScheduledTime = $Request.Body.StartDate } Add-CIPPScheduledTask -Task $TaskBody -hidden $false - Set-CIPPUserJITAdminProperties -TenantFilter $Request.Body.TenantFilter -UserId $UserObj.id -Expiration $Expiration - $Results.Add("Scheduled JIT Admin enable task for $Username") + Set-CIPPUserJITAdminProperties -TenantFilter $Request.Body.TenantFilter -UserId $Request.Body.UserId -Expiration $Expiration + $Results.Add("Scheduling JIT Admin enable task for $Username") } else { $Results.Add("Executing JIT Admin enable task for $Username") Set-CIPPUserJITAdmin @Parameters @@ -102,7 +102,7 @@ Function Invoke-ExecJITAdmin { $DisableTaskBody = @{ TenantFilter = $Request.Body.TenantFilter - Name = "JIT Admin (disable): $($Request.Body.UserPrincipalName)" + Name = "JIT Admin (disable): $Username" Command = @{ value = 'Set-CIPPUserJITAdmin' label = 'Set-CIPPUserJITAdmin' @@ -110,7 +110,7 @@ Function Invoke-ExecJITAdmin { Parameters = @{ TenantFilter = $Request.Body.TenantFilter User = @{ - 'UserPrincipalName' = $Request.Body.UserPrincipalName + 'UserPrincipalName' = $Username } Roles = $Request.Body.AdminRoles Action = $Request.Body.ExpireAction @@ -118,7 +118,7 @@ Function Invoke-ExecJITAdmin { ScheduledTime = $Request.Body.EndDate } Add-CIPPScheduledTask -Task $DisableTaskBody -hidden $false - $Results.Add("Scheduled JIT Admin disable task for $Username") + $Results.Add("Scheduling JIT Admin disable task for $Username") $Body = @{ Results = @($Results) } diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 0848966155b9..1b7a32c8cfe7 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -46,9 +46,9 @@ function Set-CIPPUserJITAdmin { $Json = ConvertTo-Json -Depth 5 -InputObject $Body $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/`$ref" -tenantid $TenantFilter -body $Json } finally {} - Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration - return "Added admin roles to user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration + return "Added admin roles to user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } 'RemoveRoles' { $Roles = $Roles | ForEach-Object { diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 index 21e2a7d19bfb..cc9e19f082ba 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 @@ -26,5 +26,6 @@ function Set-CIPPUserJITAdminProperties { } $Json = ConvertTo-Json -Depth 5 -InputObject $Body + Write-Information $Json New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter } \ No newline at end of file From 4da414cc8dfb99710ca49540432581a49d04abde Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 3 Jun 2024 20:39:57 -0400 Subject: [PATCH 071/138] JIT/Scheduler --- .../Scheduler/Invoke-ListScheduledItems.ps1 | 8 ++- .../Users/Invoke-ExecJITAdmin.ps1 | 32 ++++++++--- .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 53 ++++++++++++------- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 index 98e51126ed22..81231ca9df96 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 @@ -13,7 +13,7 @@ Function Invoke-ListScheduledItems { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' $Table = Get-CIPPTable -TableName 'ScheduledTasks' - if ($Request.query.Showhidden -eq 'true') { + if ($Request.Query.Showhidden -eq $true) { $HiddenTasks = $false } else { $HiddenTasks = $true @@ -24,7 +24,11 @@ Function Invoke-ListScheduledItems { $Tasks = $Tasks | Where-Object -Property TenantId -In $AllowedTenants } $ScheduledTasks = foreach ($Task in $tasks) { - $Task.Parameters = $Task.Parameters | ConvertFrom-Json + if ($Task.Parameters) { + $Task.Parameters = $Task.Parameters | ConvertFrom-Json -ErrorAction SilentlyContinue + } else { + $Task | Add-Member -NotePropertyName Parameters -NotePropertyValue @{} + } $Task } 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 ec5dbb935a9a..010d7d85fd10 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 @@ -15,7 +15,7 @@ Function Invoke-ExecJITAdmin { if ($Request.Query.Action -eq 'List') { $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } - Write-Information "Schema: $($Schema)" + #Write-Information "Schema: $($Schema)" $Query = @{ TenantFilter = $Request.Query.TenantFilter Endpoint = 'users' @@ -26,8 +26,18 @@ Function Invoke-ExecJITAdmin { } } $Users = Get-GraphRequestList @Query | Where-Object { $_.id } + $BulkRequests = $Users | ForEach-Object { @( + @{ + id = $_.id + method = 'GET' + url = "users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName" + } + ) + } + $RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests $BulkRequests + #Write-Information ($RoleResults | ConvertTo-Json -Depth 10 ) $Results = $Users | ForEach-Object { - $MemberOf = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_.id)/memberOf/microsoft.graph.directoryRole/?`$select=id,displayName" -tenantid $Request.Query.TenantFilter -ComplexFilter + $MemberOf = ($RoleResults | Where-Object -Property id -EQ $_.id).body.value | Select-Object displayName, id [PSCustomObject]@{ id = $_.id displayName = $_.displayName @@ -38,8 +48,7 @@ Function Invoke-ExecJITAdmin { } } - - Write-Information ($Results | ConvertTo-Json -Depth 10) + #Write-Information ($Results | ConvertTo-Json -Depth 10) $Body = @{ Results = @($Results) Metadata = @{ @@ -47,7 +56,7 @@ Function Invoke-ExecJITAdmin { } } } else { - Write-Information ($Request.Body | ConvertTo-Json -Depth 10) + #Write-Information ($Request.Body | ConvertTo-Json -Depth 10) 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 } @@ -59,18 +68,20 @@ Function Invoke-ExecJITAdmin { if ($Request.Body.useraction -eq 'create') { Write-Information "Creating JIT Admin user $($Request.Body.UserPrincipalName)" $JITAdmin = @{ - User = @{ + User = [PSCustomObject]@{ 'FirstName' = $Request.Body.FirstName 'LastName' = $Request.Body.LastName 'UserPrincipalName' = $Request.Body.UserPrincipalName } - Expiration = $Expiration - Action = 'Create' + Expiration = $Expiration + Action = 'Create' + TenantFilter = $Request.Body.TenantFilter } $CreateResult = Set-CIPPUserJITAdmin @JITAdmin $Username = $CreateResult.userPrincipalName $Results.Add("Created User: $($CreateResult.userPrincipalName)") $Results.Add("Password: $($CreateResult.password)") + Start-Sleep -Seconds 1 } $Parameters = @{ TenantFilter = $Request.Body.TenantFilter @@ -115,6 +126,11 @@ Function Invoke-ExecJITAdmin { Roles = $Request.Body.AdminRoles Action = $Request.Body.ExpireAction } + PostExecution = @{ + Webhook = [bool]$Request.Body.PostExecution.Webhook + Email = [bool]$Request.Body.PostExecution.Email + PSA = [bool]$Request.Body.PostExecution.PSA + } ScheduledTime = $Request.Body.EndDate } Add-CIPPScheduledTask -Task $DisableTaskBody -hidden $false diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 1b7a32c8cfe7..62923cc006e6 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -17,24 +17,31 @@ function Set-CIPPUserJITAdmin { 'Create' { $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } $Body = @{ + givenName = $User.FirstName + surname = $User.LastName accountEnabled = $true displayName = $User.FirstName + ' ' + $User.LastName userPrincipalName = $User.UserPrincipalName + mailNickname = $User.UserPrincipalName.Split('@')[0] passwordProfile = @{ - forceChangePasswordNextSignIn = $true - password = New-passwordString - } - "$($Schema.id)" = @{ - jitAdminEnabled = $false - jitAdminExpiration = $Expiration.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + forceChangePasswordNextSignIn = $true + forceChangePasswordNextSignInWithMfa = $false + password = New-passwordString } } $Json = ConvertTo-Json -Depth 5 -InputObject $Body - $NewUser = New-GraphPOSTRequest -Uri 'https://graph.microsoft.com/beta/users' -Body $Json -tenantid $TenantFilter - [PSCustomObject]@{ - id = $NewUser.id - userPrincipalName = $NewUser.userPrincipalName - password = $Body.passwordProfile.password + #Write-Information $Json + #Write-Information $TenantFilter + try { + $NewUser = New-GraphPOSTRequest -type POST -Uri 'https://graph.microsoft.com/beta/users' -Body $Json -tenantid $TenantFilter + [PSCustomObject]@{ + id = $NewUser.id + userPrincipalName = $NewUser.userPrincipalName + password = $Body.passwordProfile.password + } + } catch { + Write-Information "Error creating user: $($_.Exception.Message)" + throw $_.Exception.Message } } 'AddRoles' { @@ -44,8 +51,8 @@ function Set-CIPPUserJITAdmin { '@odata.id' = "https://graph.microsoft.com/v1.0/directoryObjects/$($UserObj.id)" } $Json = ConvertTo-Json -Depth 5 -InputObject $Body - $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/`$ref" -tenantid $TenantFilter -body $Json - } finally {} + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/`$ref" -tenantid $TenantFilter -body $Json -ErrorAction SilentlyContinue + } catch {} } Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration return "Added admin roles to user $($UserObj.displayName) ($($UserObj.userPrincipalName))" @@ -54,23 +61,31 @@ function Set-CIPPUserJITAdmin { $Roles = $Roles | ForEach-Object { try { $null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/$($UserObj.id)/`$ref" -tenantid $TenantFilter - } finally {} + } catch {} } Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Clear return "Removed admin roles from user $($UserObj.displayName)" } 'DeleteUser' { - $null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $TenantFilter - return "Deleted user $($UserObj.displayName) ($($UserObj.userPrincipalName)) with id $($UserObj.id)" + try { + $null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $TenantFilter + return "Deleted user $($UserObj.displayName) ($($UserObj.userPrincipalName)) with id $($UserObj.id)" + } catch { + return "Error deleting user $($UserObj.displayName) ($($UserObj.userPrincipalName)): $($_.Exception.Message)" + } } 'DisableUser' { $Body = @{ accountEnabled = $false } $Json = ConvertTo-Json -Depth 5 -InputObject $Body - 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 - return "Disabled user $($UserObj.displayName) ($($UserObj.userPrincipalName))" + 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 + return "Disabled user $($UserObj.displayName) ($($UserObj.userPrincipalName))" + } catch { + return "Error disabling user $($UserObj.displayName) ($($UserObj.userPrincipalName)): $($_.Exception.Message)" + } } } } From bbc85048c14a4229c53126fe2875085d9a22e475 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 4 Jun 2024 09:27:23 -0400 Subject: [PATCH 072/138] Fix bulk request --- .../Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 | 2 +- 1 file changed, 1 insertion(+), 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 010d7d85fd10..b83438b46bcd 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 @@ -34,7 +34,7 @@ Function Invoke-ExecJITAdmin { } ) } - $RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests $BulkRequests + $RoleResults = New-GraphBulkRequest -tenantid $Request.Query.TenantFilter -Requests @($BulkRequests) #Write-Information ($RoleResults | ConvertTo-Json -Depth 10 ) $Results = $Users | ForEach-Object { $MemberOf = ($RoleResults | Where-Object -Property id -EQ $_.id).body.value | Select-Object displayName, id From b5faa2e4d457b92bb8687c98ae003465199e3b31 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 4 Jun 2024 13:16:15 -0400 Subject: [PATCH 073/138] Webhook alert bugfix --- .../Activity Triggers/Push-Schedulerwebhookcreation.ps1 | 7 ++++--- Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 | 4 ++-- Scheduler_GetQueue/run.ps1 | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 index d3ca1dc6b455..8c56ccb98971 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-Schedulerwebhookcreation.ps1 @@ -7,8 +7,9 @@ function Push-Schedulerwebhookcreation { $item ) $Table = Get-CIPPTable -TableName 'SchedulerConfig' - $WebhookTable = Get-CIPPTable -TableName 'WebhookTable' + $WebhookTable = Get-CIPPTable -TableName 'webhookTable' + #Write-Information ($item | ConvertTo-Json -Depth 10) $Row = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($item.SchedulerRow)'" if (!$Row) { Write-Host "No row found for $($item.SchedulerRow). Full received item was $($item | ConvertTo-Json)" @@ -34,7 +35,7 @@ function Push-Schedulerwebhookcreation { $NewSub = New-CIPPGraphSubscription -TenantFilter $Tenant -EventType $Row.webhookType -BaseURL $Row.CIPPURL -auditLogAPI $true if ($NewSub.Success -and $Row.tenantid -ne 'AllTenants') { Remove-AzDataTableEntity @Table -Entity $Row - } else { + } 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 } @@ -47,5 +48,5 @@ function Push-Schedulerwebhookcreation { } } } - + } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 index f7d0eb366389..535156115d0b 100644 --- a/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPGraphSubscription.ps1 @@ -55,12 +55,12 @@ function New-CIPPGraphSubscription { 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 = $CIPPID } | Out-Null + 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 return @{ success = $false; message = "Failed to create Webhook Subscription for $($TenantFilter): $($_.Exception.Message)" } } } - + } elseif ($PartnerCenter.IsPresent) { $WebhookFilter = "PartitionKey eq '$($env:TenantId)'" $ExistingWebhooks = Get-CIPPAzDataTableEntity @WebhookTable -Filter $WebhookFilter diff --git a/Scheduler_GetQueue/run.ps1 b/Scheduler_GetQueue/run.ps1 index f58f9d667ea6..87d355d1476c 100644 --- a/Scheduler_GetQueue/run.ps1 +++ b/Scheduler_GetQueue/run.ps1 @@ -21,7 +21,7 @@ $Tasks = foreach ($Tenant in $Tenants) { Tag = 'AllTenants' TenantID = $t.customerId Type = $Tenant.type - RowKey = $t.RowKey + RowKey = $Tenant.RowKey } } } From 23fd7e0865027c7eb9903b20f61ca767a425f69e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 4 Jun 2024 14:05:30 -0400 Subject: [PATCH 074/138] Break graph request loop on invalid url --- Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index bc0ef417a3c3..28e88e204d79 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -61,7 +61,7 @@ function New-GraphGetRequest { } throw $Message } - } until ($null -eq $NextURL) + } until ($null -eq $NextURL -or ' ' -eq $NextURL) $Tenant.LastGraphError = '' Update-AzDataTableEntity @TenantsTable -Entity $Tenant return $ReturnedData From bd54d80b4c5b61778512bdda5d69d6921c3c07f8 Mon Sep 17 00:00:00 2001 From: Esco Date: Wed, 5 Jun 2024 11:40:12 +0200 Subject: [PATCH 075/138] Added more Anti-Phishing actions --- .../Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index d561c3cc51d3..5fd7e8eeb346 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -24,7 +24,10 @@ function Invoke-CIPPStandardAntiPhishPolicy { ($CurrentState.EnableUnauthenticatedSender -eq $true) -and ($CurrentState.EnableViaTag -eq $true) -and ($CurrentState.MailboxIntelligenceProtectionAction -eq $Settings.MailboxIntelligenceProtectionAction) -and - ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) + ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) -and + ($CurrentState.TargetedUserProtectionAction -eq $Settings.TargetedUserProtectionAction) -and + ($CurrentState.TargetedDomainProtectionAction -eq $Settings.TargetedDomainProtectionAction) -and + ($CurrentState.EnableOrganizationDomainsProtection -eq $true) $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' @@ -55,6 +58,9 @@ function Invoke-CIPPStandardAntiPhishPolicy { EnableViaTag = $true MailboxIntelligenceProtectionAction = $Settings.MailboxIntelligenceProtectionAction MailboxIntelligenceQuarantineTag = $Settings.MailboxIntelligenceQuarantineTag + TargetedUserProtectionAction = $Settings.TargetedUserProtectionAction + TargetedDomainProtectionAction = $Settings.TargetedDomainProtectionAction + EnableOrganizationDomainsProtection = $true } try { @@ -110,4 +116,4 @@ function Invoke-CIPPStandardAntiPhishPolicy { Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } -} \ No newline at end of file +} From c965ba3630f1c7fe8f5b9cd5a22a88d0516f88c3 Mon Sep 17 00:00:00 2001 From: Esco Date: Wed, 5 Jun 2024 11:41:24 +0200 Subject: [PATCH 076/138] Convert to CRLF --- .../Invoke-CIPPStandardAntiPhishPolicy.ps1 | 238 +++++++++--------- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index 5fd7e8eeb346..1eeb304a0768 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -1,119 +1,119 @@ -function Invoke-CIPPStandardAntiPhishPolicy { - <# - .FUNCTIONALITY - Internal - #> - - param($Tenant, $Settings) - $PolicyName = 'Default Anti-Phishing Policy' - - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishPolicy' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object Name, Enabled, PhishThresholdLevel, EnableMailboxIntelligence, EnableMailboxIntelligenceProtection, EnableSpoofIntelligence, EnableFirstContactSafetyTips, EnableSimilarUsersSafetyTips, EnableSimilarDomainsSafetyTips, EnableUnusualCharactersSafetyTips, EnableUnauthenticatedSender, EnableViaTag, MailboxIntelligenceProtectionAction, MailboxIntelligenceQuarantineTag - - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.Enabled -eq $true) -and - ($CurrentState.PhishThresholdLevel -eq $Settings.PhishThresholdLevel) -and - ($CurrentState.EnableMailboxIntelligence -eq $true) -and - ($CurrentState.EnableMailboxIntelligenceProtection -eq $true) -and - ($CurrentState.EnableSpoofIntelligence -eq $true) -and - ($CurrentState.EnableFirstContactSafetyTips -eq $Settings.EnableFirstContactSafetyTips) -and - ($CurrentState.EnableSimilarUsersSafetyTips -eq $Settings.EnableSimilarUsersSafetyTips) -and - ($CurrentState.EnableSimilarDomainsSafetyTips -eq $Settings.EnableSimilarDomainsSafetyTips) -and - ($CurrentState.EnableUnusualCharactersSafetyTips -eq $Settings.EnableUnusualCharactersSafetyTips) -and - ($CurrentState.EnableUnauthenticatedSender -eq $true) -and - ($CurrentState.EnableViaTag -eq $true) -and - ($CurrentState.MailboxIntelligenceProtectionAction -eq $Settings.MailboxIntelligenceProtectionAction) -and - ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) -and - ($CurrentState.TargetedUserProtectionAction -eq $Settings.TargetedUserProtectionAction) -and - ($CurrentState.TargetedDomainProtectionAction -eq $Settings.TargetedDomainProtectionAction) -and - ($CurrentState.EnableOrganizationDomainsProtection -eq $true) - - $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' - - $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 - (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy already correctly configured' -sev Info - } else { - $cmdparams = @{ - Enabled = $true - PhishThresholdLevel = $Settings.PhishThresholdLevel - EnableMailboxIntelligence = $true - EnableMailboxIntelligenceProtection = $true - EnableSpoofIntelligence = $true - EnableFirstContactSafetyTips = $Settings.EnableFirstContactSafetyTips - EnableSimilarUsersSafetyTips = $Settings.EnableSimilarUsersSafetyTips - EnableSimilarDomainsSafetyTips = $Settings.EnableSimilarDomainsSafetyTips - EnableUnusualCharactersSafetyTips = $Settings.EnableUnusualCharactersSafetyTips - EnableUnauthenticatedSender = $true - EnableViaTag = $true - MailboxIntelligenceProtectionAction = $Settings.MailboxIntelligenceProtectionAction - MailboxIntelligenceQuarantineTag = $Settings.MailboxIntelligenceQuarantineTag - TargetedUserProtectionAction = $Settings.TargetedUserProtectionAction - TargetedDomainProtectionAction = $Settings.TargetedDomainProtectionAction - EnableOrganizationDomainsProtection = $true - } - - try { - if ($CurrentState.Name -eq $PolicyName) { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishPolicy' -cmdparams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Anti-phishing Policy' -sev Info - } else { - $cmdparams.Add('Name', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishPolicy' -cmdparams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created Anti-phishing Policy' -sev Info - } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing Policy. Error: $ErrorMessage" -sev Error - } - } - - if ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - AntiPhishPolicy = $PolicyName - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name - } - - try { - if ($RuleState.Name -eq "CIPP $PolicyName") { - $cmdparams.Add('Identity', "CIPP $PolicyName") - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishRule' -cmdparams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated AntiPhish Rule' -sev Info - } else { - $cmdparams.Add('Name', "CIPP $PolicyName") - New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishRule' -cmdparams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created AntiPhish Rule' -sev Info - } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create AntiPhish Rule. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy is not enabled' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } - -} +function Invoke-CIPPStandardAntiPhishPolicy { + <# + .FUNCTIONALITY + Internal + #> + + param($Tenant, $Settings) + $PolicyName = 'Default Anti-Phishing Policy' + + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishPolicy' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object Name, Enabled, PhishThresholdLevel, EnableMailboxIntelligence, EnableMailboxIntelligenceProtection, EnableSpoofIntelligence, EnableFirstContactSafetyTips, EnableSimilarUsersSafetyTips, EnableSimilarDomainsSafetyTips, EnableUnusualCharactersSafetyTips, EnableUnauthenticatedSender, EnableViaTag, MailboxIntelligenceProtectionAction, MailboxIntelligenceQuarantineTag + + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.Enabled -eq $true) -and + ($CurrentState.PhishThresholdLevel -eq $Settings.PhishThresholdLevel) -and + ($CurrentState.EnableMailboxIntelligence -eq $true) -and + ($CurrentState.EnableMailboxIntelligenceProtection -eq $true) -and + ($CurrentState.EnableSpoofIntelligence -eq $true) -and + ($CurrentState.EnableFirstContactSafetyTips -eq $Settings.EnableFirstContactSafetyTips) -and + ($CurrentState.EnableSimilarUsersSafetyTips -eq $Settings.EnableSimilarUsersSafetyTips) -and + ($CurrentState.EnableSimilarDomainsSafetyTips -eq $Settings.EnableSimilarDomainsSafetyTips) -and + ($CurrentState.EnableUnusualCharactersSafetyTips -eq $Settings.EnableUnusualCharactersSafetyTips) -and + ($CurrentState.EnableUnauthenticatedSender -eq $true) -and + ($CurrentState.EnableViaTag -eq $true) -and + ($CurrentState.MailboxIntelligenceProtectionAction -eq $Settings.MailboxIntelligenceProtectionAction) -and + ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) -and + ($CurrentState.TargetedUserProtectionAction -eq $Settings.TargetedUserProtectionAction) -and + ($CurrentState.TargetedDomainProtectionAction -eq $Settings.TargetedDomainProtectionAction) -and + ($CurrentState.EnableOrganizationDomainsProtection -eq $true) + + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $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 + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy already correctly configured' -sev Info + } else { + $cmdparams = @{ + Enabled = $true + PhishThresholdLevel = $Settings.PhishThresholdLevel + EnableMailboxIntelligence = $true + EnableMailboxIntelligenceProtection = $true + EnableSpoofIntelligence = $true + EnableFirstContactSafetyTips = $Settings.EnableFirstContactSafetyTips + EnableSimilarUsersSafetyTips = $Settings.EnableSimilarUsersSafetyTips + EnableSimilarDomainsSafetyTips = $Settings.EnableSimilarDomainsSafetyTips + EnableUnusualCharactersSafetyTips = $Settings.EnableUnusualCharactersSafetyTips + EnableUnauthenticatedSender = $true + EnableViaTag = $true + MailboxIntelligenceProtectionAction = $Settings.MailboxIntelligenceProtectionAction + MailboxIntelligenceQuarantineTag = $Settings.MailboxIntelligenceQuarantineTag + TargetedUserProtectionAction = $Settings.TargetedUserProtectionAction + TargetedDomainProtectionAction = $Settings.TargetedDomainProtectionAction + EnableOrganizationDomainsProtection = $true + } + + try { + if ($CurrentState.Name -eq $PolicyName) { + $cmdparams.Add('Identity', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishPolicy' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Anti-phishing Policy' -sev Info + } else { + $cmdparams.Add('Name', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishPolicy' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created Anti-phishing Policy' -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing Policy. Error: $ErrorMessage" -sev Error + } + } + + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + AntiPhishPolicy = $PolicyName + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + try { + if ($RuleState.Name -eq "CIPP $PolicyName") { + $cmdparams.Add('Identity', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated AntiPhish Rule' -sev Info + } else { + $cmdparams.Add('Name', "CIPP $PolicyName") + New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishRule' -cmdparams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Created AntiPhish Rule' -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create AntiPhish Rule. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing Policy is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + +} From 8dbf34b0ad62bd8364926b1691d4cddebbc6ecb9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 5 Jun 2024 13:46:27 +0200 Subject: [PATCH 077/138] fix naming issue. --- ...oke-UpdateSecureScore.ps1 => Invoke-ExecUpdateSecureScore.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/{Invoke-UpdateSecureScore.ps1 => Invoke-ExecUpdateSecureScore.ps1} (100%) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-UpdateSecureScore.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecUpdateSecureScore.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-UpdateSecureScore.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecUpdateSecureScore.ps1 From 7cdb878b10d19f7caccf4ee210e594c888b4f749 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 09:00:08 -0400 Subject: [PATCH 078/138] Custom Role block list --- .../Get-CIPPRolePermissions.ps1 | 3 +- .../Public/Authentication/Test-CIPPAccess.ps1 | 112 +++++++++++------- .../CIPP/Settings/Invoke-ExecCustomRole.ps1 | 12 +- profile.ps1 | 1 + 4 files changed, 81 insertions(+), 47 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 index 0f932ee7f842..f3e1f525ac57 100644 --- a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 @@ -21,7 +21,8 @@ function Get-CIPPRolePermissions { [PSCustomObject]@{ Role = $Role.RowKey Permissions = $Permissions.PSObject.Properties.Value - AllowedTenants = $Role.AllowedTenants | ConvertFrom-Json + AllowedTenants = if ($Role.AllowedTenants) { $Role.AllowedTenants | ConvertFrom-Json } else { @() } + BlockedTenants = if ($Role.BlockedTenants) { $Role.BlockedTenants | ConvertFrom-Json } else { @() } } } else { throw "Role $RoleName not found." diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 5fcd0395a783..1336247272bb 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -23,69 +23,91 @@ function Test-CIPPAccess { } } } - if (($CustomRoles | Measure-Object).Count -gt 0 ) { + if (($CustomRoles | Measure-Object).Count -gt 0) { $Tenants = Get-Tenants -IncludeErrors + $PermissionsFound = $false $PermissionSet = foreach ($CustomRole in $CustomRoles) { try { Get-CIPPRolePermissions -Role $CustomRole + $PermissionsFound = $true } catch { Write-Information $_.Exception.Message + continue } } - if ($TenantList.IsPresent) { - $AllowedTenants = foreach ($Permission in $PermissionSet) { - foreach ($Tenant in $Permission.AllowedTenants) { - $Tenant - } - } - return $AllowedTenants - } - - if (($PermissionSet | Measure-Object).Count -eq 0) { - return $true - } else { - $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint - $Help = Get-Help $FunctionName - # Check API for required role - $APIRole = $Help.Role - foreach ($Role in $PermissionSet) { - # Loop through each custom role permission and check API / Tenant access - $TenantAllowed = $false - $APIAllowed = $false - foreach ($Perm in $Role.Permissions) { - if ($Perm -match $APIRole) { - $APIAllowed = $true - break + if ($PermissionsFound) { + if ($TenantList.IsPresent) { + $LimitedTenantList = foreach ($Permission in $PermissionSet) { + if (($Permission.AllowedTenants | Measure-Object).Count -eq 0 -and ($Permission.BlockedTenants | Measure-Object).Count -eq 0) { + return @('AllTenants') + } else { + if ($Permission.AllowedTenants -contains 'AllTenants') { + $Permission.AllowedTenants = $Tenants.customerId + } + $Permission.AllowedTenants | Where-Object { $Permission.BlockedTenants -notcontains $_ } } } - if ($APIAllowed) { - # Check tenant level access - if ($Role.AllowedTenants -contains 'AllTenants') { - $TenantAllowed = $true - } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { - $TenantAllowed = $false - } else { - $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId + Write-Information ($LimitedTenantList | ConvertTo-Json) + return $LimitedTenantList + } - if ($Tenant) { - $TenantAllowed = $Role.AllowedTenants -contains $Tenant - if (!$TenantAllowed) { continue } + if (($PermissionSet | Measure-Object).Count -eq 0) { + return $true + } else { + $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint + $Help = Get-Help $FunctionName + # Check API for required role + $APIRole = $Help.Role + foreach ($Role in $PermissionSet) { + # Loop through each custom role permission and check API / Tenant access + $TenantAllowed = $false + $APIAllowed = $false + foreach ($Perm in $Role.Permissions) { + if ($Perm -match $APIRole) { + $APIAllowed = $true break - } else { + } + } + if ($APIAllowed) { + # Check tenant level access + if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') { $TenantAllowed = $true - break + } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { + $TenantAllowed = $false + } else { + $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId + if ($Role.AllowedTenants -contains 'AllTenants') { + $AllowedTenants = $Tenants + } else { + $AllowedTenants = $Role.AllowedTenants + } + + if ($Tenant) { + $TenantAllowed = $AllowedTenants -contains $Tenant -and $Role.BlockedTenants -notcontains $Tenant + if (!$TenantAllowed) { continue } + break + } else { + $TenantAllowed = $true + break + } } } } + if (!$APIAllowed) { + throw "Access to this CIPP API endpoint is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" + } + if (!$TenantAllowed) { + throw 'Access to this tenant is not allowed' + } else { + return $true + } } - if (!$APIAllowed) { - throw "Access to this CIPP API endpoint is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" - } - if (!$TenantAllowed) { - throw 'Access to this tenant is not allowed' - } else { - return $true + } else { + # No permissions found for any roles + if ($TenantList.IsPresent) { + return @('AllTenants') } + return $true } } else { return $true 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 45b0e6931d89..0b6f0055c15a 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 @@ -16,6 +16,7 @@ function Invoke-ExecCustomRole { 'RowKey' = "$($Request.Body.RoleName)" 'Permissions' = "$($Request.Body.Permissions | ConvertTo-Json -Compress)" 'AllowedTenants' = "$($Request.Body.AllowedTenants | ConvertTo-Json -Compress)" + 'BlockedTenants' = "$($Request.Body.BlockedTenants | ConvertTo-Json -Compress)" } Add-CIPPAzDataTableEntity @Table -Entity $Role -Force | Out-Null $Body = @{Results = 'Custom role saved' } @@ -37,7 +38,16 @@ function Invoke-ExecCustomRole { } else { $Body = foreach ($Role in $Body) { $Role.Permissions = $Role.Permissions | ConvertFrom-Json - $Role.AllowedTenants = @($Role.AllowedTenants | ConvertFrom-Json) + if ($Role.AllowedTenants) { + $Role.AllowedTenants = @($Role.AllowedTenants | ConvertFrom-Json) + } else { + $Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @() + } + if ($Role.BlockedTenants) { + $Role.BlockedTenants = @($Role.BlockedTenants | ConvertFrom-Json) + } else { + $Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() + } $Role } $Body = @($Body) diff --git a/profile.ps1 b/profile.ps1 index 134944f4d7e7..f72dcd0c4c7d 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -46,6 +46,7 @@ try { Write-LogMessage -message 'Could not retrieve keys from Keyvault' -LogData (Get-CippException -Exception $_) -Sev 'debug' } +Set-Location -Path $PSScriptRoot $CurrentVersion = (Get-Content .\version_latest.txt).trim() $Table = Get-CippTable -tablename 'Version' $LastStartup = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Version' and RowKey eq 'Version'" From b890d0f49cc7767a823719b9b1d58f3f4fedc81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Wed, 5 Jun 2024 15:23:56 +0200 Subject: [PATCH 079/138] Add Graph role and Pronouns standard --- Modules/CIPPCore/Public/SAMManifest.json | 3 +- .../Invoke-CIPPStandardEnablePronouns.ps1 | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index 3ee73e6b09d1..b6b291da57b4 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -158,7 +158,8 @@ { "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": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" }, + { "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" } ] }, { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 new file mode 100644 index 000000000000..56d5c8a1815e --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 @@ -0,0 +1,52 @@ +function Invoke-CIPPStandardEnablePronouns { + <# + .FUNCTIONALITY + Internal + #> + param ($Tenant, $Settings) + + $Uri = 'https://graph.microsoft.com/v1.0/admin/people/pronouns' + try { + $CurrentState = New-GraphGetRequest -Uri $Uri -tenantid $Tenant + } 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 + } + Write-Host $CurrentState + + if ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' + + if ($CurrentState.isEnabledInOrganization -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Pronouns are already enabled.' -sev Info + } else { + $CurrentState.isEnabledInOrganization = $true + try { + $Body = ConvertTo-Json -InputObject $CurrentState -Depth 10 -Compress + New-GraphPostRequest -Uri $Uri -tenantid $Tenant -Body $Body -type PATCH + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Enabled pronouns.' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable pronouns. Error: $ErrorMessage" -sev Error + } + } + } + + 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 From 97bcfead71d75bbabaa959ff97d81c65bfd08b1c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 09:55:52 -0400 Subject: [PATCH 080/138] Suppress output --- Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 6 +++--- Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 62923cc006e6..6825deb4e62e 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -15,7 +15,7 @@ function Set-CIPPUserJITAdmin { switch ($Action) { 'Create' { - $Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } + #$Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } $Body = @{ givenName = $User.FirstName surname = $User.LastName @@ -54,7 +54,7 @@ function Set-CIPPUserJITAdmin { $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/`$ref" -tenantid $TenantFilter -body $Json -ErrorAction SilentlyContinue } catch {} } - Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled -Expiration $Expiration | Out-Null return "Added admin roles to user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } 'RemoveRoles' { @@ -63,7 +63,7 @@ function Set-CIPPUserJITAdmin { $null = New-GraphPOSTRequest -type DELETE -uri "https://graph.microsoft.com/beta/directoryRoles(roleTemplateId='$($_)')/members/$($UserObj.id)/`$ref" -tenantid $TenantFilter } catch {} } - Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Clear + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Clear | Out-Null return "Removed admin roles from user $($UserObj.displayName)" } 'DeleteUser' { diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 index cc9e19f082ba..c6203128f2f9 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdminProperties.ps1 @@ -27,5 +27,5 @@ function Set-CIPPUserJITAdminProperties { $Json = ConvertTo-Json -Depth 5 -InputObject $Body Write-Information $Json - New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter + New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/beta/users/$UserId" -Body $Json -tenantid $TenantFilter | Out-Null } \ No newline at end of file From 2bfcbbfe8b7790ae472ec9225ebc2900c7150474 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 10:43:01 -0400 Subject: [PATCH 081/138] Add JIT comments --- .../Users/Invoke-ExecJITAdmin.ps1 | 2 +- .../Invoke-ListFunctionParameters.ps1 | 2 +- .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 43 ++++++++++++++++--- 3 files changed, 39 insertions(+), 8 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 b83438b46bcd..6b0ceb571cf1 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 @@ -68,7 +68,7 @@ Function Invoke-ExecJITAdmin { if ($Request.Body.useraction -eq 'create') { Write-Information "Creating JIT Admin user $($Request.Body.UserPrincipalName)" $JITAdmin = @{ - User = [PSCustomObject]@{ + User = @{ 'FirstName' = $Request.Body.FirstName 'LastName' = $Request.Body.LastName 'UserPrincipalName' = $Request.Body.UserPrincipalName diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 index 64c465e799e9..e3060be55daa 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 @@ -27,7 +27,7 @@ function Invoke-ListFunctionParameters { $CommandQuery.Name = $Function } $IgnoreList = 'entryPoint', 'internal' - $CommonParameters = @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction', 'ErrorVariable', 'WarningVariable', 'InformationVariable', 'OutVariable', 'OutBuffer', 'PipelineVariable', 'TenantFilter', 'APIName', 'ExecutingUser', 'ProgressAction') + $CommonParameters = @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction', 'ErrorVariable', 'WarningVariable', 'InformationVariable', 'OutVariable', 'OutBuffer', 'PipelineVariable', 'TenantFilter', 'APIName', 'ExecutingUser', 'ProgressAction', 'WhatIf', 'Confirm') $TemporaryBlacklist = 'Get-CIPPAuthentication', 'Invoke-CippWebhookProcessing', 'Invoke-ListFunctionParameters', 'New-CIPPAPIConfig', 'New-CIPPGraphSubscription' try { $Functions = Get-Command @CommandQuery | Where-Object { $_.Visibility -eq 'Public' } diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index 6825deb4e62e..c41b893c5a05 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -1,11 +1,45 @@ function Set-CIPPUserJITAdmin { + <# + .SYNOPSIS + Just-in-time admin management + + .DESCRIPTION + Just-in-time admin management for CIPP. This function can create users, add roles, remove roles, delete, or disable a user. + + .PARAMETER TenantFilter + Tenant to manage for JIT admin + + .PARAMETER User + User object to manage JIT admin roles, required property UserPrincipalName - If user is being created we also require FirstName and LastName + + .PARAMETER Roles + List of Role GUIDs to add or remove + + .PARAMETER Action + Action to perform: Create, AddRoles, RemoveRoles, DeleteUser, DisableUser + + .PARAMETER Expiration + DateTime for expiration + + .EXAMPLE + Set-CIPPUserJITAdmin -TenantFilter 'contoso.onmicrosoft.com' -User @{UserPrincipalName = 'jit@contoso.onmicrosoft.com'} -Roles @('62e90394-69f5-4237-9190-012177145e10') -Action 'AddRoles' -Expiration (Get-Date).AddDays(1) + + #> [CmdletBinding(SupportsShouldProcess = $true)] Param( + [Parameter(Mandatory = $true)] [string]$TenantFilter, - $User, + + [Parameter(Mandatory = $true)] + [hashtable]$User, + [string[]]$Roles, + + [Parameter(Mandatory = $true)] + [ValidateSet('Create', 'AddRoles', 'RemoveRoles', 'DeleteUser', 'DisableUser')] [string]$Action, - $Expiration + + [datetime]$Expiration ) if ($PSCmdlet.ShouldProcess("User: $($User.UserPrincipalName)", "Action: $Action")) { @@ -15,7 +49,6 @@ function Set-CIPPUserJITAdmin { switch ($Action) { 'Create' { - #$Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' } $Body = @{ givenName = $User.FirstName surname = $User.LastName @@ -30,8 +63,6 @@ function Set-CIPPUserJITAdmin { } } $Json = ConvertTo-Json -Depth 5 -InputObject $Body - #Write-Information $Json - #Write-Information $TenantFilter try { $NewUser = New-GraphPOSTRequest -type POST -Uri 'https://graph.microsoft.com/beta/users' -Body $Json -tenantid $TenantFilter [PSCustomObject]@{ @@ -81,7 +112,7 @@ function Set-CIPPUserJITAdmin { $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 - Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled:$false + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $UserObj.id -Enabled:$false | Out-Null return "Disabled user $($UserObj.displayName) ($($UserObj.userPrincipalName))" } catch { return "Error disabling user $($UserObj.displayName) ($($UserObj.userPrincipalName)): $($_.Exception.Message)" From 7f53eeb519143ed198ee1bea3275f34bbb3fb859 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 12:39:37 -0400 Subject: [PATCH 082/138] Add logging --- .../HTTP Functions/CIPP/Settings/Invoke-ExecCustomRole.ps1 | 2 ++ .../Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) 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 0b6f0055c15a..dafe35d226f8 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 @@ -11,6 +11,7 @@ function Invoke-ExecCustomRole { $Table = Get-CippTable -tablename 'CustomRoles' switch ($Request.Query.Action) { 'AddUpdate' { + 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)" @@ -22,6 +23,7 @@ function Invoke-ExecCustomRole { $Body = @{Results = 'Custom role saved' } } 'Delete' { + Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API 'ExecCustomRole' -message "Deleted custom role $($Request.Body.RoleName)" -Sev 'Info' $Role = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.RoleName)'" -Property RowKey, PartitionKey Remove-AzDataTableEntity @Table -Entity $Role $Body = @{Results = 'Custom role deleted' } 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 6b0ceb571cf1..ad887810061a 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 @@ -10,7 +10,7 @@ Function Invoke-ExecJITAdmin { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName + $APIName = 'ExecJITAdmin' Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' if ($Request.Query.Action -eq 'List') { @@ -56,7 +56,7 @@ Function Invoke-ExecJITAdmin { } } } else { - #Write-Information ($Request.Body | ConvertTo-Json -Depth 10) + 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 } @@ -66,6 +66,7 @@ Function Invoke-ExecJITAdmin { $Results = [System.Collections.Generic.List[string]]::new() if ($Request.Body.useraction -eq 'create') { + Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message "Creating JIT Admin user $($Request.Body.UserPrincipalName)" -Sev 'Info' Write-Information "Creating JIT Admin user $($Request.Body.UserPrincipalName)" $JITAdmin = @{ User = @{ From 68e0d95c7ce21299d1b96415e8567e2a8a73e50f Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 17:28:12 -0400 Subject: [PATCH 083/138] PasswordPusher integration --- .../Settings/Invoke-ExecExtensionTest.ps1 | 9 + .../Administration/Users/Invoke-AddUser.ps1 | 6 + .../Users/Invoke-AddUserBulk.ps1 | 28 +- .../CIPPCore/Public/Set-CIPPResetPassword.ps1 | 25 +- .../CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 | 10 +- .../Private/Set-PwPushConfig.ps1 | 18 + .../CippExtensions/Public/New-PwPushLink.ps1 | 24 + .../PassPushPosh/0.2.3/PSGetModuleInfo.xml | 142 +++ Modules/PassPushPosh/0.2.3/PassPushPosh.psd1 | 140 +++ Modules/PassPushPosh/0.2.3/PassPushPosh.psm1 | 1012 +++++++++++++++++ 10 files changed, 1390 insertions(+), 24 deletions(-) create mode 100644 Modules/CippExtensions/Private/Set-PwPushConfig.ps1 create mode 100644 Modules/CippExtensions/Public/New-PwPushLink.ps1 create mode 100644 Modules/PassPushPosh/0.2.3/PSGetModuleInfo.xml create mode 100644 Modules/PassPushPosh/0.2.3/PassPushPosh.psd1 create mode 100644 Modules/PassPushPosh/0.2.3/PassPushPosh.psm1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 index 7c2f271c13a5..78e82e78121a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExtensionTest.ps1 @@ -37,6 +37,15 @@ Function Invoke-ExecExtensionTest { $token = Get-NinjaOneToken -configuration $Configuration.NinjaOne $Results = [pscustomobject]@{'Results' = 'Succesfully Connected to NinjaOne' } } + 'PWPush' { + $Payload = 'This is a test from CIPP' + $PasswordLink = New-PwPushLink -Payload $Payload + if ($PasswordLink) { + $Results = [pscustomobject]@{'Results' = 'Succesfully generated PWPush'; 'Link' = $PasswordLink } + } else { + $Results = [pscustomobject]@{'Results' = 'PWPush is not enabled' } + } + } } } catch { $Results = [pscustomobject]@{'Results' = "Failed to connect: $($_.Exception.Message) $($_.InvocationInfo.ScriptLineNumber)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 index 5a4b4f95e08c..d554111c480c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 @@ -55,6 +55,12 @@ Function Invoke-AddUser { $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/users' -tenantid $UserObj.tenantID -type POST -body $BodyToship -verbose Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantID) -message "Created user $($UserObj.displayname) with id $($GraphRequest.id) " -Sev 'Info' + + #PWPush + $PasswordLink = New-PwPushLink -Payload $password + if ($PasswordLink) { + $password = $PasswordLink + } $results.add('Created user.') $results.add("Username: $($UserprincipalName)") $results.add("Password: $password") diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 index 8169512aaeee..2d33113d1ffb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 @@ -13,8 +13,7 @@ Function Invoke-AddUserBulk { $APIName = 'AddUserBulk' Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.body.TenantFilter - $Results = [System.Collections.ArrayList]@() - foreach ($userobj in $request.body.BulkUser) { + $Body = foreach ($userobj in $request.body.BulkUser) { Write-Host 'PowerShell HTTP trigger function processed a request.' try { $password = if ($userobj.password) { $userobj.password } else { New-passwordString } @@ -32,24 +31,29 @@ Function Invoke-AddUserBulk { $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/users' -tenantid $TenantFilter -type POST -body $BodyToship Write-Host "Graph request is $GraphRequest" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message "Created user $($userobj.displayname) with id $($GraphRequest.id) " -Sev 'Info' - $results.add("Created user $($UserprincipalName). Password is $password") | Out-Null + + #PWPush + $PasswordLink = New-PwPushLink -Payload $password + if ($PasswordLink) { + $password = $PasswordLink + } + $results = "Created user $($UserprincipalName). Password is $password" + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message "Failed to create user. Error:$($_.Exception.Message)" -Sev 'Error' - $body = $results.add("Failed to create user. $($_.Exception.Message)" ) + $results = "Failed to create user. $($_.Exception.Message)" + } + [PSCustomObject]@{ + 'Results' = $results + 'Username' = $UserprincipalName + 'Password' = $password } } - $body = [pscustomobject] @{ - 'Results' = @($results) - 'Username' = $UserprincipalName - 'Password' = $password - 'CopyFrom' = $copyFromResults - } - # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $Body + Body = @($Body) }) } diff --git a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 index 6128fd2af888..aff8463210be 100644 --- a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 @@ -3,26 +3,31 @@ function Set-CIPPResetPassword { param( $userid, $tenantFilter, - $APIName = "Reset Password", + $APIName = 'Reset Password', $ExecutingUser, [bool]$forceChangePasswordNextSignIn = $true ) - try { + try { $password = New-passwordString $passwordProfile = @{ - "passwordProfile" = @{ - "forceChangePasswordNextSignIn" = $forceChangePasswordNextSignIn - "password" = $password + 'passwordProfile' = @{ + 'forceChangePasswordNextSignIn' = $forceChangePasswordNextSignIn + 'password' = $password } } | ConvertTo-Json -Compress - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose - Write-LogMessage -user $ExecutingUser -API $APIName -message "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn" -Sev "Info" -tenant $TenantFilter + $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose + + #PWPush + $PasswordLink = New-PwPushLink -Payload $password + if ($PasswordLink) { + $password = $PasswordLink + } + Write-LogMessage -user $ExecutingUser -API $APIName -message "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter return "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password" - } - catch { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not reset password for $($userid)" -Sev "Error" -tenant $TenantFilter + } catch { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not reset password for $($userid)" -Sev 'Error' -tenant $TenantFilter return "Could not reset password for $($userid). Error: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 index c41b893c5a05..692b6c4828ef 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserJITAdmin.ps1 @@ -49,6 +49,7 @@ function Set-CIPPUserJITAdmin { switch ($Action) { 'Create' { + $Password = New-passwordString $Body = @{ givenName = $User.FirstName surname = $User.LastName @@ -59,16 +60,21 @@ function Set-CIPPUserJITAdmin { passwordProfile = @{ forceChangePasswordNextSignIn = $true forceChangePasswordNextSignInWithMfa = $false - password = New-passwordString + password = $Password } } $Json = ConvertTo-Json -Depth 5 -InputObject $Body try { $NewUser = New-GraphPOSTRequest -type POST -Uri 'https://graph.microsoft.com/beta/users' -Body $Json -tenantid $TenantFilter + #PWPush + $PasswordLink = New-PwPushLink -Payload $Password + if ($PasswordLink) { + $Password = $PasswordLink + } [PSCustomObject]@{ id = $NewUser.id userPrincipalName = $NewUser.userPrincipalName - password = $Body.passwordProfile.password + password = $Password } } catch { Write-Information "Error creating user: $($_.Exception.Message)" diff --git a/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 b/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 new file mode 100644 index 000000000000..72f1a0e5c9f8 --- /dev/null +++ b/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 @@ -0,0 +1,18 @@ +function Set-PwPushConfig { + param( + $Configuration + ) + $InitParams = @{} + if ($Configuration.BaseUrl) { + $InitParams.BaseUrl = $Configuration.BaseUrl + } + if ($Configuration.EmailAddress) { + $null = Connect-AzAccount -Identity + $ApiKey = (Get-AzKeyVaultSecret -VaultName $ENV:WEBSITE_DEPLOYMENT_ID -Name 'PWPush' -AsPlainText) + if ($ApiKey) { + $InitParams.ApiKey = $ApiKey + $InitParams.EmailAddress = $Configuration.EmailAddress + } + } + Initialize-PassPushPosh @InitParams +} \ No newline at end of file diff --git a/Modules/CippExtensions/Public/New-PwPushLink.ps1 b/Modules/CippExtensions/Public/New-PwPushLink.ps1 new file mode 100644 index 000000000000..a8739f39c9b6 --- /dev/null +++ b/Modules/CippExtensions/Public/New-PwPushLink.ps1 @@ -0,0 +1,24 @@ +function New-PwPushLink { + [CmdletBinding()] + Param( + $Payload + ) + $Table = Get-CIPPTable -TableName Extensionsconfig + $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).PWPush + if ($Configuration.Enabled) { + Set-PwPushConfig -Configuration $Configuration + $PushParams = @{ + Payload = $Payload + } + if ($Configuration.ExpireAfterDays) { $PushParams.ExpireAfterDays = $Configuration.ExpireAfterDays } + if ($Configuration.ExpireAfterViews) { $PushParams.ExpireAfterViews = $Configuration.ExpireAfterViews } + if ($Configuration.DeletableByViewer) { $PushParams.DeletableByViewer = $Configuration.DeletableByViewer } + $Link = New-Push @PushParams | Select-Object Link, LinkRetrievalStep + if ($Configuration.RetrievalStep) { + $Link.Link = $Link.LinkRetrievalStep + } + $Link | Select-Object -ExpandProperty Link + } else { + return $false + } +} \ No newline at end of file diff --git a/Modules/PassPushPosh/0.2.3/PSGetModuleInfo.xml b/Modules/PassPushPosh/0.2.3/PSGetModuleInfo.xml new file mode 100644 index 000000000000..00cc59d45a7d --- /dev/null +++ b/Modules/PassPushPosh/0.2.3/PSGetModuleInfo.xml @@ -0,0 +1,142 @@ + + + + Microsoft.PowerShell.Commands.PSRepositoryItemInfo + System.Management.Automation.PSCustomObject + System.Object + + + PassPushPosh + 0.2.3 + Module + *PassPushPosh* is a PowerShell Module for interfacing with the Password Pusher secure password / string sharing application, primarily through pwpush.com. It supports creating, retrieving, and deleting anonymous and authenticated pushes, links in any supported language, and getting Push and Dashboard data for authenticated users._x000D__x000A__x000D__x000A_Cmdlets provide clear responses to errors, support additional messaging via -Debug and -Verbose, transaction testing via -Whatif and -Confirm, and in general try to be as "Powershell-y" as possible. + Adam Burley + AdamBurley + Adam Burley, 2022 +
2023-03-05T00:10:36-05:00
+ + + https://www.gnu.org/licenses/gpl-3.0.en.html + https://github.com/adamburley/PassPushPosh + + + + System.Object[] + System.Array + System.Object + + + PSEdition_Desktop + PSEdition_Core + Windows + Linux + MacOS + Password + PSModule + + + + + System.Collections.Hashtable + System.Object + + + + DscResource + + + + + + + Cmdlet + + + + Function + + + + ConvertTo-PasswordPush + Get-Dashboard + Get-Push + Get-PushAuditLog + Get-SecretLink + Initialize-PassPushPosh + New-PasswordPush + New-Push + Remove-Push + + + + + Workflow + + + + RoleCapability + + + + Command + + + + ConvertTo-PasswordPush + Get-Dashboard + Get-Push + Get-PushAuditLog + Get-SecretLink + Initialize-PassPushPosh + New-PasswordPush + New-Push + Remove-Push + + + + + + + 0.2.3 - Bug fixing in New-Push. See PR #1_x000D__x000A_ 0.2.2 - Fixed issue with Get-Dashboard returning error referencing -JsonIsArray parameter_x000D__x000A_ General - Module is generally functional but has not been extensively bug-tested. Reccomend not implementing into a production environment at this time. + + + + + https://www.powershellgallery.com/api/v2 + PSGallery + NuGet + + + System.Management.Automation.PSCustomObject + System.Object + + + Adam Burley, 2022 + *PassPushPosh* is a PowerShell Module for interfacing with the Password Pusher secure password / string sharing application, primarily through pwpush.com. It supports creating, retrieving, and deleting anonymous and authenticated pushes, links in any supported language, and getting Push and Dashboard data for authenticated users._x000D__x000A__x000D__x000A_Cmdlets provide clear responses to errors, support additional messaging via -Debug and -Verbose, transaction testing via -Whatif and -Confirm, and in general try to be as "Powershell-y" as possible. + False + 0.2.3 - Bug fixing in New-Push. See PR #1_x000D__x000A_ 0.2.2 - Fixed issue with Get-Dashboard returning error referencing -JsonIsArray parameter_x000D__x000A_ General - Module is generally functional but has not been extensively bug-tested. Reccomend not implementing into a production environment at this time. + True + True + 44 + 76 + 15168 + 3/5/2023 12:10:36 AM -05:00 + 3/5/2023 12:10:36 AM -05:00 + 5/23/2024 10:57:25 AM -04:00 + PSEdition_Desktop PSEdition_Core Windows Linux MacOS Password PSModule PSFunction_ConvertTo-PasswordPush PSCommand_ConvertTo-PasswordPush PSFunction_Get-Dashboard PSCommand_Get-Dashboard PSFunction_Get-Push PSCommand_Get-Push PSFunction_Get-PushAuditLog PSCommand_Get-PushAuditLog PSFunction_Get-SecretLink PSCommand_Get-SecretLink PSFunction_Initialize-PassPushPosh PSCommand_Initialize-PassPushPosh PSFunction_New-PasswordPush PSCommand_New-PasswordPush PSFunction_New-Push PSCommand_New-Push PSFunction_Remove-Push PSCommand_Remove-Push PSIncludes_Function + False + 2024-05-23T10:57:25Z + 0.2.3 + Adam Burley + false + Module + PassPushPosh.nuspec|PassPushPosh.psd1|PassPushPosh.psm1 + 5d8a1afd-a912-440f-a9b9-e79f42a05f21 + 5.1 + Burley.dev + + + C:\GitHub\CIPP Workspace\CIPP-API\Modules\PassPushPosh\0.2.3 +
+
+
diff --git a/Modules/PassPushPosh/0.2.3/PassPushPosh.psd1 b/Modules/PassPushPosh/0.2.3/PassPushPosh.psd1 new file mode 100644 index 000000000000..1c911df9d9de --- /dev/null +++ b/Modules/PassPushPosh/0.2.3/PassPushPosh.psd1 @@ -0,0 +1,140 @@ +# +# Module manifest for module 'PassPushPosh' +# +# Generated by: Adam Burley +# +# Generated on: 3/4/2023 +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'PassPushPosh.psm1' + +# Version number of this module. +ModuleVersion = '0.2.3' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '5d8a1afd-a912-440f-a9b9-e79f42a05f21' + +# Author of this module +Author = 'Adam Burley' + +# Company or vendor of this module +CompanyName = 'Burley.dev' + +# Copyright statement for this module +Copyright = 'Adam Burley, 2022' + +# Description of the functionality provided by this module +Description = '*PassPushPosh* is a PowerShell Module for interfacing with the Password Pusher secure password / string sharing application, primarily through pwpush.com. It supports creating, retrieving, and deleting anonymous and authenticated pushes, links in any supported language, and getting Push and Dashboard data for authenticated users. + +Cmdlets provide clear responses to errors, support additional messaging via -Debug and -Verbose, transaction testing via -Whatif and -Confirm, and in general try to be as "Powershell-y" as possible.' + +# Minimum version of the PowerShell engine required by this module +PowerShellVersion = '5.1' + +# Name of the PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = 'ConvertTo-PasswordPush', 'Get-Dashboard', 'Get-Push', + 'Get-PushAuditLog', 'Get-SecretLink', 'Initialize-PassPushPosh', + 'New-PasswordPush', 'New-Push', 'Remove-Push' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = @() + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = 'Get-PushPreview' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = 'PSEdition_Desktop','PSEdition_Core','Windows','Linux','MacOS','Password' + + # A URL to the license for this module. + LicenseUri = 'https://www.gnu.org/licenses/gpl-3.0.en.html' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/adamburley/PassPushPosh' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + ReleaseNotes = @" + 0.2.3 - Bug fixing in New-Push. See PR #1 + 0.2.2 - Fixed issue with Get-Dashboard returning error referencing -JsonIsArray parameter + General - Module is generally functional but has not been extensively bug-tested. Reccomend not implementing into a production environment at this time. +"@ + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + +# HelpInfo URI of this module +HelpInfoURI = 'https://github.com/adamburley/PassPushPosh/blob/main/Docs' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + diff --git a/Modules/PassPushPosh/0.2.3/PassPushPosh.psm1 b/Modules/PassPushPosh/0.2.3/PassPushPosh.psm1 new file mode 100644 index 000000000000..e159d6a80d3d --- /dev/null +++ b/Modules/PassPushPosh/0.2.3/PassPushPosh.psm1 @@ -0,0 +1,1012 @@ +class PasswordPush { + [string]$Payload + [string] hidden $__UrlToken + [string] hidden $__LinkBase + [string]$Language + [bool]$RetrievalStep + [bool]$IsExpired + [bool]$IsDeleted + [bool]$IsDeletableByViewer + [int]$ExpireAfterDays + [int]$DaysRemaining + [int]$ExpireAfterViews + [int]$ViewsRemaining + [DateTime]$DateCreated + [DateTime]$DateUpdated + [DateTime]$DateExpired + # Added by constructors: + #[string]$URLToken + #[string]$Link + #[string]$LinkDirect + #[string]$LinkRetrievalStep + + PasswordPush() { + # Blank constructor + } + + # Constructor to allow casting or explicit import from a PSObject Representing the result of an API call + PasswordPush([PSCustomObject]$APIresponseObject) { + throw NotImplementedException + } + + # Allow casting or explicit import from the raw Content of an API call + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Scope = 'Function', Justification = 'Global variables are used for module session helpers.')] + PasswordPush([string]$JsonResponse) { + Write-Debug 'New PasswordPush object instantiated from JsonResponse string' + Initialize-PassPushPosh # Initialize the module if not yet done. + + $_j = $JsonResponse | ConvertFrom-Json + $this.Payload = $_j.payload + $this.IsExpired = $_j.expired + $this.IsDeleted = $_j.deleted + $this.IsDeletableByViewer = $_j.deletable_by_viewer + $this.ExpireAfterDays = $_j.expire_after_days + $this.DaysRemaining = $_j.days_remaining + $this.ExpireAfterViews = $_j.expire_after_views + $this.ViewsRemaining = $_j.views_remaining + $this.DateCreated = $_j.created_at + $this.DateUpdated = $_j.updated_at + $this.DateExpired = if ($_j.expired_on) { $_j.expired_on } else { [DateTime]0 } + + $this.Language = $Global:PPPLanguage + + $this | Add-Member -Name 'UrlToken' -MemberType ScriptProperty -Value { + return $this.__UrlToken + } -SecondValue { + $this.__UrlToken = $_ + $this.__LinkBase = "$Global:PPPBaseUrl/$($this.Language)/p/$($this.__UrlToken)" + } + $this.__UrlToken = $_j.url_token + $this.__LinkBase = "$Global:PPPBaseUrl/$($this.Language)/p/$($this.__UrlToken)" + $this | Add-Member -Name 'LinkDirect' -MemberType ScriptProperty -Value { return $this.__LinkBase } -SecondValue { + Write-Warning 'LinkDirect is a read-only calculated member.' + Write-Debug 'Link* members are calculated based on the Global BaseUrl and Language and Push Retrieval Step values' + } + $this | Add-Member -Name 'LinkRetrievalStep' -MemberType ScriptProperty -Value { return "$($this.__LinkBase)/r" } -SecondValue { + Write-Warning 'LinkRetrievalStep is a read-only calculated member.' + Write-Debug 'Link* members are calculated based on the Global BaseUrl and Language and Push Retrieval Step values' + } + $this | Add-Member -Name 'Link' -MemberType ScriptProperty -Value { + $_Link = if ($this.RetrievalStep) { $this.LinkRetrievalStep } else { $this.LinkDirect } + Write-Debug "Presented Link: $_link" + return $_Link + } -SecondValue { + Write-Warning 'Link is a read-only calculated member.' + Write-Debug 'Link* members are calculated based on the Global BaseUrl and Language and Push Retrieval Step values' + } + } +} + +function ConvertTo-PasswordPush { + <# + .SYNOPSIS + Convert API call response to a PasswordPush object + + .DESCRIPTION + Accepts a JSON string returned from the Password Pusher API and converts it to a [PasswordPush] object. + This allows calculated push retrieval URLs, language enumeration, and a more "PowerShell" experience. + Generally you won't need to use this directly, it's automatically invoked within Register-Push and Request-Push. + + .INPUTS + [string] + + .OUTPUTS + [PasswordPush] for single object + [PasswordPush[]] for Json array data + + .EXAMPLE + # Common usage - from within the Register-Push cmdlet + PS> $myPush = Register-Push -Payload "This is my secret!" + PS> $myPush.Link # The link parameter always presents the URL as it would appear with the same settings selected on pwpush.com + + https://pwpush.com/en/p/rz6nryvl-d4 + + .EXAMPLE + # Manually invoking the API + PS> $rawJson = Invoke-WebRequest ` + -Uri https://pwpush.com/en/p.json ` + -Method Post ` + -Body '{"password": { "payload": "This is my secret!"}}' ` + -ContentType 'application/json' | + Select-Object -ExpandProperty Content + PS> $rawJson + {"expire_after_days":7,"expire_after_views":5,"expired":false,"url_token":"rz6nryvl-d4","created_at":"2022-11-18T14:16:29.821Z","updated_at":"2022-11-18T14:16:29.821Z","deleted":false,"deletable_by_viewer":true,"retrieval_step":false,"expired_on":null,"days_remaining":7,"views_remaining":5} + PS> $rawJson | ConvertTo-PasswordPush + UrlToken : rz6nryvl-d4 + LinkDirect : https://pwpush.com/en/p/rz6nryvl-d4 + LinkRetrievalStep : https://pwpush.com/en/p/rz6nryvl-d4/r + Link : https://pwpush.com/en/p/rz6nryvl-d4 + Payload : + Language : en + RetrievalStep : False + IsExpired : False + IsDeleted : False + IsDeletableByViewer : True + ExpireAfterDays : 7 + DaysRemaining : 7 + ExpireAfterViews : 5 + ViewsRemaining : 5 + DateCreated : 11/18/2022 2:16:29 PM + DateUpdated : 11/18/2022 2:16:29 PM + DateExpired : 1/1/0001 12:00:00 AM + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/ConvertTo-PasswordPush.md + + .NOTES + Needs a rewrite / cleanup + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Creates a new object, no risk of overwriting data.')] + [CmdletBinding()] + [OutputType([PasswordPush])] + param( + # The string result of an API call from the Password Pusher application + [parameter(Mandatory, ValueFromPipeline)] + [ValidateNotNullOrEmpty()] + [string]$JsonResponse + ) + process { + try { + $jsonObject = $JsonResponse | ConvertFrom-Json + foreach ($o in $jsonObject) { + [PasswordPush]($o | ConvertTo-Json) # TODO fix this mess + } + } + catch { + Write-Debug 'Error in ConvertTo-PasswordPush coercing JSON object to PasswordPush object' + Write-Debug "JsonResponse parameter value: [[$JsonResponse]]" + Write-Error $_ + } + } +} +function Get-Dashboard { + <# + .SYNOPSIS + Get a list of active or expired Pushes for an authenticated user + + .DESCRIPTION + Retrieves a list of Pushes - active or expired - for an authenticated user. + Active and Expired are different endpoints, so to get both you'll need to make + two calls. + + .INPUTS + [string] 'Active' or 'Expired' + + .OUTPUTS + [PasswordPush[]] Array of pushes with data + [string] raw response body from API call + + .EXAMPLE + Get-Dashboard + + .EXAMPLE + Get-Dashboard Active + + .EXAMPLE + Get-Dashboard -Dashboard Expired + + .EXAMPLE + Get-Dashboard -Raw + [{"expire_after_days":1,"expire_after_views":5,"expired":false,"url_token":"xm3q7czvtdpmyg","created_at":"2022-11-19T18:10:42.055Z","updated_at":"2022-11-19T18:10:42.055Z","deleted":false,"deletable_by_viewer":true,"retrieval_step":false,"expired_on":null,"note":null,"days_remaining":1,"views_remaining":3}] + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/Get-Dashboard.md + + .LINK + https://pwpush.com/api/1.0/dashboard.en.html + + .LINK + Get-PushAuditLog + + .NOTES + TODO update Invoke-Webrequest flow and error-handling to match other functions + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Scope = 'Function', Justification = 'Global variables are used for module session helpers.')] + [CmdletBinding()] + [OutputType([PasswordPush[]],[string])] + param( + # URL Token from a secret + [parameter(Position=0)] + [ValidateSet('Active','Expired')] + [ValidateNotNullOrEmpty()] + [string] + $Dashboard = 'Active', + + # Return content of API call directly + [Parameter()] + [switch] + $Raw + ) + if (-not $Global:PPPHeaders) { Write-Error 'Dashboard access requires authentication. Run Initialize-PassPushPosh and pass your email address and API key before retrying.' -ErrorAction Stop -Category AuthenticationError } + try { + $uri = "$Global:PPPBaseUrl/d/" + if ($Dashboard -eq 'Active') { $uri += 'active.json' } + elseif ($Dashboard -eq 'Expired') { $uri += 'expired.json' } + Write-Debug "Requesting $uri" + $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $Global:PPPHeaders -ErrorAction Stop + if ($Raw) { return $response.Content } + else { + return $response.Content | ConvertTo-PasswordPush + } + } catch { + Write-Verbose "An exception was caught: $($_.Exception.Message)" + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name 'PPPLastError' -Value $_ + Write-Debug -Message 'Response object set to global variable $PPPLastError' + } + throw # Re-throw the error + } +} +function Get-Push { + <# + .SYNOPSIS + Retrieve the secret contents of a Push + + .DESCRIPTION + Accepts a URL Token string, returns the contents of a Push along with + metadata regarding that Push. Note, Get-Push will return data on an expired + Push (datestamps, etc) even if it does not return the Push contents. + + .INPUTS + [string] + + .OUTPUTS + [PasswordPush] or [string] + + .EXAMPLE + Get-Push -URLToken gzv65wiiuciy + + .EXAMPLE + Get-Push -URLToken gzv65wiiuciy -Raw + {"payload":"I am your payload!","expired":false,"deleted":false,"expired_on":"","expire_after_days":1,"expire_after_views":4,"url_token":"bwzehzem_xu-","created_at":"2022-11-21T13:20:08.635Z","updated_at":"2022-11-21T13:23:45.342Z","deletable_by_viewer":true,"retrieval_step":false,"days_remaining":1,"views_remaining":4} + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/Get-Push.md + + .LINK + https://pwpush.com/api/1.0/passwords/show.en.html + + .LINK + New-Push + + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','',Scope='Function',Justification='Global variables are used for module session helpers.')] + [CmdletBinding()] + [OutputType([PasswordPush])] + param( + # URL Token for the secret + [parameter(Mandatory,ValueFromPipeline,Position=0)] + [ValidateNotNullOrEmpty()] + [Alias('Token')] + $URLToken, + + # Return the raw response body from the API call + [Parameter()] + [switch] + $Raw + ) + begin { Initialize-PassPushPosh -Verbose:$VerbosePreference -Debug:$DebugPreference } + + process { + try { + $iwrSplat = @{ + 'Method' = 'Get' + 'ContentType' = 'application/json' + 'Uri' = "$Global:PPPBaseUrl/p/$URLToken.json" + 'UserAgent' = $Global:PPPUserAgent + } + if ($Global:PPPHeaders) { $iwrSplat['Headers'] = $Global:PPPHeaders } + Write-Verbose "Sending HTTP request: $($iwrSplat | Out-String)" + $response = Invoke-WebRequest @iwrSplat -ErrorAction Stop + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name PPPLastCall -Value $response + Write-Debug 'Response to Invoke-WebRequest set to PPPLastCall Global variable' + } + if ($Raw) { + Write-Debug "Returning raw object:`n$($response.Content)" + return $response.Content + } + return $response.Content | ConvertTo-PasswordPush + } catch { + Write-Verbose "An exception was caught: $($_.Exception.Message)" + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name PPPLastError -Value $_ + Write-Debug -Message 'Response object set to global variable $PPPLastError' + } + } + } +} +function Get-PushAuditLog { + <# + .SYNOPSIS + Get the view log of an authenticated Push + + .DESCRIPTION + Retrieves the view log of a Push created under an authenticated session. + Returns an array of custom objects with view data. If the query is + successful but there are no results, it returns an empty array. + If there's an error, a single object is returned with information. + See "handling errors" under NOTES + + .INPUTS + [string] + + .OUTPUTS + [PsCustomObject[]] Array of entries. + [PsCustomObject] If there's an error in the call, it will be returned an object with a property + named 'error'. The value of that member will contain more information + + .EXAMPLE + Get-PushAuditLog -URLToken 'mytokenfromapush' + ip : 75.202.43.56,102.70.135.200 + user_agent : Mozilla/5.0 (Macintosh; Darwin 21.6.0 Darwin Kernel Version 21.6.0: Mon Aug 22 20:20:05 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T8101; + en-US) PowerShell/7.2.7 + referrer : + successful : True + created_at : 11/19/2022 6:32:42 PM + updated_at : 11/19/2022 6:32:42 PM + kind : 0 + + .EXAMPLE + # If there are no views, an empty array is returned + Get-PushAuditLog -URLToken 'mytokenthatsneverbeenseen' + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/Get-PushAuditLog.md + + .LINK + https://pwpush.com/api/1.0/passwords/audit.en.html + + .LINK + Get-Dashboard + + .NOTES + Handling Errors: + The API returns different HTTP status codes and results depending where the + call fails. + + | HTTP RESPONSE | Error Reason | Response Body | Sample Object Returned | Note | + |------------------|---------------------------------|----------------------------------------------|--------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| + | 401 UNAUTHORIZED | Invalid API key or email | None | @{ 'Error'= 'Authentication error. Verify email address and API key.'; 'ErrorCode'= 401 } | | + | 200 OK | Push created by another account | {"error":"That push doesn't belong to you."} | @{ 'Error'= "That Push doesn't belong to you"; 'ErrorCode'= 403 } | Function transforms error code to 403 to allow easier response management | + | 404 NOT FOUND | Invalid URL token | None | @{ 'Error'= 'Invalid token. Verify your Push URL token is correct.'; 'ErrorCode'= 404 } | This is different than the response to a delete Push query - in this case it will only return 404 if the token is invalid. | + + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Scope = 'Function', Justification = 'Global variables are used for module session helpers.')] + [CmdletBinding()] + [OutputType([PSCustomObject[]],[string])] + param( + # URL Token from a secret + [parameter(ValueFromPipeline)] + [ValidateNotNullOrEmpty()] + [string] + $URLToken, + + # Return content of API call directly + [Parameter()] + [switch] + $Raw + ) + begin { + if (-not $Global:PPPHeaders) { Write-Error 'Retrieving audit logs requires authentication. Run Initialize-PassPushPosh and pass your email address and API key before retrying.' -ErrorAction Stop -Category AuthenticationError } + } + process { + try { + $uri = "$Global:PPPBaseUrl/p/$URLToken/audit.json" + Write-Debug 'Requesting $uri' + $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $Global:PPPHeaders -ErrorAction Stop + if ([int]$response.StatusCode -eq 200 -and $response.Content -ieq "{`"error`":`"That push doesn't belong to you.`"}") { + $result = [PSCustomObject]@{ 'Error' = "That Push doesn't belong to you"; 'ErrorCode' = 403 } + Write-Warning $result.Error + return $result + } + if ($Raw) { return $response.Content } else { return $response.Content | ConvertFrom-Json } + } + catch { + Write-Verbose "An exception was caught: $($_.Exception.Message)" + if ([int]$_.Exception.Response.StatusCode -eq 401) { # Could be optimized + $result = [PSCustomObject]@{ 'Error' = 'Authentication error. Verify email address and API key.'; 'ErrorCode' = 401 } + Write-Warning $result.Error + return $result + } elseif ([int]$_.Exception.Response.StatusCode -eq 404) { + $result = [PSCustomObject]@{ 'Error' = 'Invalid token. Verify your Push URL token is correct.'; 'ErrorCode' = 404 } + Write-Warning $result.Error + return $result + } + elseif ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name 'PPPLastError' -Value $_ + Write-Debug -Message 'Response object set to global variable $PPPLastError' + return [PSCustomObject]@{ + 'Error' = $_.Exception.Message + 'ErrorCode' = [int]$_.Exception.Response.StatusCode + 'ErrorMessage' = $_.Exception.Response.ReasonPhrase + } + } + } + } +} + +# Invalid API key / email - 401 +# Invalid URL Token - 404 +# Valid token but not mine - 200, content = {"error":"That push doesn't belong to you."} +# Success but no views - 200, content = : {"views":[]} +# Success with view history {"views":[{"ip":"75.118.137.58,172.70.135.200","user_agent":"Mozilla/5.0 (Macintosh; Darwin 21.6.0 Darwin Kernel Version 21.6.0: Mon Aug 22 20:20:05 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T8101; en-US) PowerShell/7.2.7","referrer":"","successful":true,"created_at":"2022-11-19T18:32:42.277Z","updated_at":"2022-11-19T18:32:42.277Z","kind":0}]} +# Content.Views +<# +ip : 75.118.137.58,172.70.135.200 +user_agent : Mozilla/5.0 (Macintosh; Darwin 21.6.0 Darwin Kernel Version 21.6.0: Mon Aug 22 20:20:05 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T8101; +en-US) PowerShell/7.2.7 +referrer : +successful : True +created_at : 11/19/2022 6:32:42 PM +updated_at : 11/19/2022 6:32:42 PM +kind : 0 +#> +function Get-SecretLink { + <# + .SYNOPSIS + Returns a fully qualified secret link to a push of given URL Token + + .DESCRIPTION + Accepts a string value for a URL Token and retrieves a full URL link to the secret. + Returned value is a 1-step retrieval link depending on option selected during Push creation. + Returns false if URL Token is invalid, however it will return a URL if the token is valid + but the Push is expired or deleted. + + .INPUTS + [string] URL Token value + + .OUTPUTS + [string] Fully qualified URL + [bool] $False if Push URL Token is invalid. Note: Expired or deleted Pushes will still return a link. + + .EXAMPLE + Get-SecretLink -URLToken gzv65wiiuciy + https://pwpush.com/en/p/gzv65wiiuciy/r + + .EXAMPLE + # En France + PS > Get-SecretLink -URLToken gzv65wiiuciy -Language fr + https://pwpush.com/fr/p/gzv65wiiuciy/r + + .EXAMPLE + Get-SecretLink -URLToken gzv65wiiuciy -Raw + { "url": "https://pwpush.com/es/p/0fkapnbo_pwp4gi8uy0/r" } + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/Get-SecretLink.md + + .LINK + https://pwpush.com/api/1.0/passwords/preview.en.html + + .NOTES + Including this endpoint for completeness - however it is generally unnecessary. + The only thing this endpoint does is return a different value depending if "Use 1-click retrieval step" + was selected when the Push was created. Since both the 1-click and the direct links are available + regardless if that option is selected, the links are calculable and both are included by default in a + [PasswordPush] object. + + As it returns false if a Push URL token is not valid you can use it to test if a Push exists without + burning a view. + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','',Scope='Function',Justification='Global variables are used for module session helpers.')] + [CmdletBinding()] + [Alias('Get-PushPreview')] + [OutputType('[string]')] + param( + # URL Token for the secret + [parameter(Mandatory, ValueFromPipeline)] + [ValidateLength(5, 256)] + [string]$URLToken, + + # Language for returned links. Defaults to system language, can be overridden here. + [Parameter()] + [string] + $Language = $Global:PPPLanguage, + + # Return the raw response body from the API call + [Parameter()] + [switch] + $Raw + ) + begin { Initialize-PassPushPosh -Verbose:$VerbosePreference -Debug:$DebugPreference } + process { + try { + if ($Language -ine 'en') { $uri += "?push_locale=$Language" } + $iwrSplat = @{ + 'Method' = 'Get' + 'ContentType' = 'application/json' + 'Uri' = "$Global:PPPBaseUrl/p/$URLToken/preview.json" + 'UserAgent' = $Global:PPPUserAgent + } + if ($Global:PPPHeaders) { $iwrSplat['Headers'] = $Global:PPPHeaders } + Write-Verbose "Sending HTTP request: $($iwrSplat | Out-String)" + $responseContent = Invoke-WebRequest @iwrSplat | Select-Object -ExpandProperty Content + if ($Raw) { return $responseContent } + else { return $responseContent | ConvertFrom-Json | Select-Object -ExpandProperty url } + } + catch { + Write-Verbose "An exception was caught: $($_.Exception.Message)" + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name 'PPPLastError' -Value $_ + Write-Debug -Message 'Response object set to global variable $PPPLastError' + } + } + } +} +function Initialize-PassPushPosh { + <# + .SYNOPSIS + Initialize the PassPushPosh module + + .DESCRIPTION + Sets global variables to handle the server URL, headers (authentication), and language. + Called automatically by module Functions if it is not called explicitly prior, so you don't actually need + to call it unless you're going to use the authenticated API or alternate server, etc + Default parameters use the pwpush.com domain, anonymous authentication, and whatever language your computer + is set to. + + .EXAMPLE + # Initialize with default settings + PS > Initialize-PassPushPosh + + .EXAMPLE + # Initialize with authentication + PS > Initialize-PassPushPosh -EmailAddress 'youremail@example.com' -ApiKey '239jf0jsdflskdjf' -Verbose + + VERBOSE: Initializing PassPushPosh. ApiKey: [x-kdjf], BaseUrl: https://pwpush.com + + .EXAMPLE + # Initialize with another server with authentication + PS > Initialize-PassPushPosh -BaseUrl https://myprivatepwpushinstance.com -EmailAddress 'youremail@example.com' -ApiKey '239jf0jsdflskdjf' -Verbose + + VERBOSE: Initializing PassPushPosh. ApiKey: [x-kdjf], BaseUrl: https://myprivatepwpushinstance.com + + .EXAMPLE + # Set a custom User Agent + PS > InitializePassPushPosh -UserAgent "I'm a cool dude with a cool script." + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/Initialize-PassPushPosh.md + + .NOTES + All variables set by this function start with PPP. + - PPPHeaders + - PPPLanguage + - PPPUserAgent + - PPPBaseUrl + + -WhatIf setting for Set-Variable -Global is disabled, otherwise -WhatIf + calls for other functions would return incorrect data in the case this + function has not yet run. + + TODO: Review API key pattern for parameter validation + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','',Scope='Function',Justification='Global variables are used for module session helpers.')] + [CmdletBinding(DefaultParameterSetName='Anonymous')] + param ( + # Email address to use for authenticated calls. + [Parameter(Mandatory,Position=0,ParameterSetName='Authenticated')] + [ValidatePattern('.+\@.+\..+')] + [string]$EmailAddress, + + # API Key for authenticated calls. + [Parameter(Mandatory,Position=1,ParameterSetName='Authenticated')] + [ValidateLength(5,256)] + [string]$ApiKey, + + # Base URL for API calls. Allows use of module with private instances of Password Pusher + # Default: https://pwpush.com + [Parameter(Position=0,ParameterSetName='Anonymous')] + [Parameter(Position=2,ParameterSetName='Authenticated')] + [ValidatePattern('^https?:\/\/[a-zA-Z0-9-_]+.[a-zA-Z0-9]+')] + [string]$BaseUrl, + + # Language to render resulting links in. Defaults to host OS language, or English if + # host OS language is not available + [Parameter()] + [string] + $Language, + + # Set a specific user agent. Default user agent is a combination of the + # module info, what your OS reports itself as, and a hash based on + # your username + workstation or domain name. This way the UA can be + # semi-consistent across sessions but not identifying. + [Parameter()] + [ValidateNotNullOrEmpty()] + [string] + $UserAgent, + + # Force setting new information. If module is already initialized you can use this to + # Re-initialize with default settings. Implied if either ApiKey or BaseUrl is provided. + [Parameter()][switch]$Force + ) + if ($Global:PPPBaseURL -and $true -inotin $Force, [bool]$ApiKey, [bool]$BaseUrl, [bool]$UserAgent) { Write-Debug -Message 'PassPushPosh is already initialized.' } + else { + $defaultBaseUrl = 'https://pwpush.com' + $apiKeyOutput = if ($ApiKey) { 'x-' + $ApiKey.Substring($ApiKey.Length-4) } else { 'None' } + + if (-not $Global:PPPBaseURL) { # Not initialized + if (-not $BaseUrl) { $BaseUrl = $defaultBaseUrl } + Write-Verbose "Initializing PassPushPosh. ApiKey: [$apiKeyOutput], BaseUrl: $BaseUrl" + } elseif ($Force -or $ApiKey -or $BaseURL) { + if (-not $BaseUrl) { $BaseUrl = $defaultBaseUrl } + $oldApiKeyOutput = if ($Global:PPPApiKey) { 'x-' + $Global:PPPApiKey.Substring($Global:PPPApiKey.Length-4) } else { 'None' } + Write-Verbose "Re-initializing PassPushPosh. Old ApiKey: [$oldApiKeyOutput] New ApiKey: [$apiKeyOutput], Old BaseUrl: $Global:PPPBaseUrl New BaseUrl: $BaseUrl" + } + if ($PSCmdlet.ParameterSetName -eq 'Authenticated') { + Set-Variable -Scope Global -Name PPPHeaders -WhatIf:$false -Value @{ + 'X-User-Email' = $EmailAddress + 'X-User-Token' = $ApiKey + } + } elseif ($Global:PPPHeaders) { # Remove if present - covers case where module is reinitialized from an authenticated to an anonymous session + Remove-Variable -Scope Global -Name PPPHeaders -WhatIf:$false + } + $availableLanguages = ('en','ca','cs','da','de','es','fi','fr','hu','it','nl','no','pl','pt-BR','sr','sv') + if (-not $Language) { + $Culture = Get-Culture + Write-Debug "Detected Culture: $($Culture.DisplayName)" + $matchedLanguage = $Culture.TwoLetterISOLanguageName, $Culture.IetfLanguageTag | + Foreach-Object { if ($_ -iin $availableLanguages) { $_ } } | + Select-Object -First 1 + if ($matchedLanguage) { + Write-Debug "Language is supported in Password Pusher." + $Language = $matchedLanguage + } else { Write-Warning "Detected language $($Culture.DisplayName) is not supported in PasswordPusher. Defaulting to English." } + } else { + if ($Language -iin $availableLanguages) { + Write-Debug "Language [$Language] is available in PasswordPusher." + } else + { + Write-Warning "Language [$Language] is not available in PasswordPusher. Defaulting to english." + $Language = 'en' + } + } + + if (-not $UserAgent) { + $osVersion = [System.Environment]::OSVersion + $userAtDomain = "{0}@{1}" -f [System.Environment]::UserName, [System.Environment]::UserDomainName + $uAD64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($userAtDomain)) + Write-Debug "$userAtDomain transformed to $uAD64. First 20 characters $($uAD64.Substring(0,20))" + $UserAgent = "PassPushPosh/$((Get-Module -Name PassPushPosh).Version.ToString()) $Language $osVersion/$($uAD64.Substring(0,20))" + Write-Verbose "Generated user agent: $UserAgent" + } else { + Write-Verbose "Using specified user agent: $UserAgent" + } + + Set-Variable -WhatIf:$false -Scope Global -Name PPPBaseURL -Value $BaseUrl.TrimEnd('/') + Set-Variable -WhatIf:$false -Scope Global -Name PPPLanguage -Value $Language + Set-Variable -WhatIf:$false -Scope Global -Name PPPUserAgent -Value $UserAgent + } +} +function New-PasswordPush { + <# + .SYNOPSIS + Create a new blank Password Push object. + + .DESCRIPTION + Creates a blank [PasswordPush]. + Generally not needed, use ConvertTo-PasswordPush + See New-Push if you're trying to create a new secret to send + + .INPUTS + None + + .OUTPUTS + [PasswordPush] + + .EXAMPLE + New-PasswordPush + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/New-PasswordPush.md + + .NOTES + TODO Rewrite - make this work including read-only properties + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Creates a new object, no risk of overwriting data.')] + [CmdletBinding()] + param () + return [PasswordPush]::new() +} +function New-Push { + <# + .SYNOPSIS + Create a new Password Push + + .DESCRIPTION + Create a new Push on the specified Password Pusher instance. The + programmatic equivalent of going to pwpush.com and entering info. + Returns [PasswordPush] object. Link member is a link created based on + 1-step setting and language specified, however both 1-step and direct links + are always provided at LinkRetrievalStep and LinkDirect. + + .EXAMPLE + $myPush = New-Push "Here's my secret!" + PS > $myPush | Select-Object Link, LinkRetrievalStep, LinkDirect + + Link : https://pwpush.com/en/p/gzv65wiiuciy # Requested style + LinkRetrievalStep : https://pwpush.com/en/p/gzv65wiiuciy/r # 1-step + LinkDirect : https://pwpush.com/en/p/gzv65wiiuciy # Direct + + .EXAMPLE + "Super secret secret" | New-Push -RetrievalStep | Select-Object -ExpandProperty Link + + https://pwpush.com/en/p/gzv65wiiuciy/r + + + .EXAMPLE + # "Burn after reading" style Push + PS > New-Push -Payload "Still secret text!" -ExpireAfterViews 1 -RetrievalStep + + .INPUTS + [string] + + .OUTPUTS + [PasswordPush] Push object + [string] Raw result of API call + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/New-Push.md + + .LINK + https://pwpush.com/api/1.0/passwords/create.en.html + + .LINK + Get-Push + + .NOTES + Maximum for -ExpireAfterDays and -ExpireAfterViews is based on the default + values for Password Pusher and what's used on the public instance + (pwpush.com). If you're using this with a private instance and want to + override that value you'll need to fork this module. + + TODO: Support [PasswordPush] input objects, testing + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','',Scope='Function',Justification='Global variables are used for module session helpers.')] + [CmdletBinding(SupportsShouldProcess,ConfirmImpact='Low',DefaultParameterSetName='Anonymous')] + [OutputType([PasswordPush],[string],[bool])] # Returntype should be [PasswordPush] but I've yet to find a way to add class access to a function on a module... + param( + # The password or secret text to share. + [Parameter(Mandatory=$true,ValueFromPipeline,Position=0)] + [Alias('Password')] + [ValidateNotNullOrEmpty()] + [string]$Payload, + + # Label for this Push (requires Authenticated session) + [Parameter(ParameterSetName='RequiresAuthentication')] + [ValidateNotNullOrEmpty()] + [string]$Note, + + # Expire secret link and delete after this many days. + [Parameter()] + [ValidateRange(1,90)] + [int] + $ExpireAfterDays, + + # Expire secret link after this many views. + [Parameter()] + [ValidateRange(1,100)] + [int] + $ExpireAfterViews, + + # Allow the recipient of a Push to delete it. + [Parameter()] + [switch] + $DeletableByViewer, + + # Require recipient click an extra link to view Push payload. + # Helps to avoid chat systems and URL scanners from eating up views. + # Note that the retrieval step URL is always available for a push. This + # parameter changes if the 1-click link is used in the Link parameter + # and returned from the secret link helper (Get-SecretLink) + [Parameter()] + [switch] + $RetrievalStep, + + # Override Language. Useful if sending to someone who speaks a + # different language. You can change this after the fact by changing + # the URL by hand or by requesting a link for the given token from the + # preview helper endpoint ( See Request-SecretLink ) + [Parameter()] + [string] + $Language, + + # Return the raw response body from the API call + [Parameter()] + [switch] + $Raw + ) + + begin { + Initialize-PassPushPosh -Verbose:$VerbosePreference -Debug:$DebugPreference + } + + process { + if ($PSCmdlet.ParameterSetName -eq 'RequiresAuthentication' -and -not $Global:PPPHeaders.'X-User-Token') { Write-Error -Message 'Setting a note requires an authenticated call.'; return $false } + + $body = @{ + 'password' = @{ + 'payload' = $Payload + } + } + $shouldString = 'Submit {0} push with Payload of length {1}' -f $PSCmdlet.ParameterSetName, $Payload.Length + if ($Note) { + $body.password.note = $note + $shouldString += " with note $note" + } + if ($ExpireAfterDays) { + $body.password.expire_after_days = $ExpireAfterDays + $shouldString += ', expire after {0} days' -f $ExpireAfterDays + } + if ($ExpireAfterViews) { + $body.password.expire_after_views = $ExpireAfterViews + $shouldString += ', expire after {0} views' -f $ExpireAfterViews + } + $body.password.deletable_by_viewer = if ($DeletableByViewer) { + $shouldString += ', deletable by viewer' + $true + } else { + $shouldString += ', NOT deletable by viewer' + $false + } + $body.password.retrieval_step = if ($RetrievalStep) { + $shouldString += ', with a 1-click retrieval step' + $true + } else { + $shouldString += ', with a direct link' + $false + } + if (-not $Language) { $Language = $Global:PPPLanguage } + $shouldString += ' in language "{0}"' -f $Language + if ($VerbosePreference -eq [System.Management.Automation.ActionPreference]::Continue) { + # Sanitize input so we're not logging or outputting the payload + $vBody = $body.Clone() + $vBody.password.payload = "A payload of length $($body.password.payload.Length.ToString())" + $vBs = $vBody | ConvertTo-Json | Out-String + Write-Verbose "Call Body (sanitized): $vBs" + } + + $iwrSplat = @{ + 'Method' = 'Post' + 'ContentType' = 'application/json' + 'Body' = ($body | ConvertTo-Json) + 'Uri' = "$Global:PPPBaseUrl/$Language/p.json" + 'UserAgent' = $Global:PPPUserAgent + } + if ($Global:PPPHeaders.'X-User-Token') { $iwrSplat['Headers'] = $Global:PPPHeaders } + Write-Verbose "Sending HTTP request (minus body): $($iwrSplat | Select-Object Method,ContentType,Uri,UserAgent,Headers | Out-String)" + if ($PSCmdlet.ShouldProcess($shouldString, $iwrSplat.Uri, 'Submit new Push')) { + try { + $response = Invoke-WebRequest @iwrSplat + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name PPPLastCall -Value $response + Write-Debug 'Response to Invoke-WebRequest set to PPPLastCall Global variable' + } + if ($Raw) { + Write-Debug "Returning raw object: $($response.Content)" + return $response.Content + } + return $response.Content | ConvertTo-PasswordPush + } catch { + Write-Verbose "An exception was caught: $($_.Exception.Message)" + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name PPPLastError -Value $_ + Write-Debug -Message 'Response object set to global variable $PPPLastError' + } + } + } + } +} +function Remove-Push { + <# + .SYNOPSIS + Remove a Push + + .DESCRIPTION + Remove (invalidate) an active push. Requires the Push be either set as + deletable by viewer, or that you are authenticated as the creator of the + Push. + + If you have authorization to delete a push (deletable by viewer TRUE or + you are the Push owner) the endpoint will always return 200 OK with a Push + object, regardless if the Push was previously deleted or expired. + + If the Push URL Token is invalid OR you are not authorized to delete the + Push, the endpoint returns 404 and this function returns $false + + .INPUTS + [string] URL Token + [PasswordPush] representing the Push to remove + + .OUTPUTS + [bool] True on success, otherwise False + + .EXAMPLE + Remove-Push -URLToken bwzehzem_xu- + + .EXAMPLE + Remove-Push -URLToken -Raw + {"expired":true,"deleted":true,"expired_on":"2022-11-21T13:23:45.341Z","expire_after_days":1,"expire_after_views":4,"url_token":"bwzehzem_xu-","created_at":"2022-11-21T13:20:08.635Z","updated_at":"2022-11-21T13:23:45.342Z","deletable_by_viewer":true,"retrieval_step":false,"days_remaining":1,"views_remaining":4} + + .LINK + https://github.com/adamburley/PassPushPosh/blob/main/Docs/Remove-Push.md + + .LINK + https://pwpush.com/api/1.0/passwords/destroy.en.html + + .NOTES + TODO testing and debugging + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','',Scope='Function',Justification='Global variables are used for module session helpers.')] + [CmdletBinding(SupportsShouldProcess,DefaultParameterSetName='Token')] + [OutputType([PasswordPush],[string],[bool])] + param( + # URL Token for the secret + [parameter(ValueFromPipeline,ParameterSetName='Token')] + [ValidateNotNullOrEmpty()] + [Alias('Token')] + [string] + $URLToken, + + # PasswordPush object + [Parameter(ValueFromPipeline,ParameterSetName='Object')] + [PasswordPush] + $PushObject, + + # Return the raw response body from the API call + [parameter()] + [switch] + $Raw + ) + process { + try { + if ($PSCmdlet.ParameterSetName -eq 'Object') { + Write-Debug -Message "Remove-Push was passed a PasswordPush object with URLToken: [$($PushObject.URLToken)]" + if (-not $PushObject.IsDeletableByViewer -and -not $Global:PPPHeaders) { #Pre-qualify if this will succeed + Write-Warning -Message 'Unable to remove Push. Push is not marked as deletable by viewer and you are not authenticated.' + return $false + } + if ($PushObject.IsDeletableByViewer) { + Write-Verbose "Push is flagged as deletable by viewer, should be deletable." + } else { Write-Verbose "In an authenticated API session. Push will be deletable if it was created by authenticated user." } + $URLToken = $PushObject.URLToken + } else { + Write-Debug -Message "Remove-Push was passed a URLToken: [$URLToken]" + } + Write-Verbose -Message "Push with URL Token [$URLToken] will be deleted if 'Deletable by viewer' was enabled or you are the creator of the push and are authenticated." + $iwrSplat = @{ + 'Method' = 'Delete' + 'ContentType' = 'application/json' + 'Uri' = "$Global:PPPBaseUrl/p/$URLToken.json" + 'UserAgent' = $Global:PPPUserAgent + } + if ($Global:PPPHeaders) { $iwrSplat['Headers'] = $Global:PPPHeaders } + Write-Verbose "Sending HTTP request: $($iwrSplat | Out-String)" + if ($PSCmdlet.ShouldProcess('Delete',"Push with token [$URLToken]")) { + $response = Invoke-WebRequest @iwrSplat + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name PPPLastCall -Value $response + Write-Debug 'Response to Invoke-WebRequest set to PPPLastCall Global variable' + } + if ($Raw) { + Write-Debug "Returning raw object: $($response.Content)" + return $response.Content + } + return $response.Content | ConvertTo-PasswordPush + } + } catch { + if ($_.Exception.Response.StatusCode -eq 404) { + Write-Warning "Failed to delete Push. This can indicate an invalid URL Token, that the password was not marked deletable, or that you are not the owner." + return $false + } else { + Write-Verbose "An exception was caught: $($_.Exception.Message)" + if ($DebugPreference -eq [System.Management.Automation.ActionPreference]::Continue) { + Set-Variable -Scope Global -Name PPPLastError -Value $_ + Write-Debug -Message 'Response object set to global variable $PPPLastError' + } + $_ + } + } + } +} From 90a4f9c4e206c603153dd89ec6f0aab6d43bd789 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 17:46:55 -0400 Subject: [PATCH 084/138] Update Set-PwPushConfig.ps1 --- Modules/CippExtensions/Private/Set-PwPushConfig.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 b/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 index 72f1a0e5c9f8..0698cc53fe86 100644 --- a/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 +++ b/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 @@ -10,7 +10,7 @@ function Set-PwPushConfig { $null = Connect-AzAccount -Identity $ApiKey = (Get-AzKeyVaultSecret -VaultName $ENV:WEBSITE_DEPLOYMENT_ID -Name 'PWPush' -AsPlainText) if ($ApiKey) { - $InitParams.ApiKey = $ApiKey + $InitParams.APIKey = $ApiKey $InitParams.EmailAddress = $Configuration.EmailAddress } } From b51d0dc53bcfa1084af3ca590e9cf2643af20b66 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 5 Jun 2024 17:51:30 -0400 Subject: [PATCH 085/138] Update Set-PwPushConfig.ps1 --- Modules/CippExtensions/Private/Set-PwPushConfig.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 b/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 index 0698cc53fe86..d43ffa888575 100644 --- a/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 +++ b/Modules/CippExtensions/Private/Set-PwPushConfig.ps1 @@ -7,8 +7,13 @@ function Set-PwPushConfig { $InitParams.BaseUrl = $Configuration.BaseUrl } if ($Configuration.EmailAddress) { - $null = Connect-AzAccount -Identity - $ApiKey = (Get-AzKeyVaultSecret -VaultName $ENV:WEBSITE_DEPLOYMENT_ID -Name 'PWPush' -AsPlainText) + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $ApiKey = (Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'PWPush' and RowKey eq 'PWPush'").APIKey + } else { + $null = Connect-AzAccount -Identity + $ApiKey = Get-AzKeyVaultSecret -VaultName $ENV:WEBSITE_DEPLOYMENT_ID -Name 'PWPush' -AsPlainText + } if ($ApiKey) { $InitParams.APIKey = $ApiKey $InitParams.EmailAddress = $Configuration.EmailAddress From d856a6235dad91de2ec1eccce28026cb5487880d Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 12:39:34 +0200 Subject: [PATCH 086/138] exclude legacy --- .../Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 index 83372682cbac..c0c6e0d17db3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 @@ -18,11 +18,11 @@ function Invoke-CIPPStandardTransportRuleTemplate { 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) -useSystemMailbox $true + $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) -useSystemMailbox $true + $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' } From 0d20db2a06635368dd67873bb4ed6e9632c04625 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 12:56:27 +0200 Subject: [PATCH 087/138] Create new backup functionality --- .../CIPP/Settings/Invoke-ExecRunBackup.ps1 | 33 ++--------------- Modules/CIPPCore/Public/New-CIPPBackup.ps1 | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 29 deletions(-) create mode 100644 Modules/CIPPCore/Public/New-CIPPBackup.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 index 5dd1070a2c49..ef8d564acdca 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRunBackup.ps1 @@ -12,36 +12,11 @@ Function Invoke-ExecRunBackup { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - try { - if ($request.query.Selected) { - $BackupTables = $request.query.Selected -split ',' - } else { - $BackupTables = @( - 'bpa' - 'Config' - 'Domains' - 'ExcludedLicenses' - 'templates' - 'standards' - 'SchedulerConfig' - ) - } - $CSVfile = foreach ($CSVTable in $BackupTables) { - $Table = Get-CippTable -tablename $CSVTable - Get-CIPPAzDataTableEntity @Table | Select-Object *, @{l = 'table'; e = { $CSVTable } } - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' - - $body = [pscustomobject]@{ - 'Results' = 'Created backup' - backup = $CSVfile - } - } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + $CSVfile = New-CIPPBackup -BackupType 'CIPP' + $body = [pscustomobject]@{ + 'Results' = 'Created backup' + backup = $CSVfile } - - # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 new file mode 100644 index 000000000000..3ec96fd0317e --- /dev/null +++ b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 @@ -0,0 +1,37 @@ +function New-CIPPBackup { + [CmdletBinding()] + param ( + $backupType, + $TenantFilter, + $APIName = 'CIPP Backup', + $ExecutingUser + ) + + $BackupData = switch ($backupType) { + #If backup type is CIPP, create CIPP backup. + 'CIPP' { + try { + $BackupTables = @( + 'bpa' + 'Config' + 'Domains' + 'ExcludedLicenses' + 'templates' + 'standards' + 'SchedulerConfig' + ) + $CSVfile = foreach ($CSVTable in $BackupTables) { + $Table = Get-CippTable -tablename $CSVTable + Get-CIPPAzDataTableEntity @Table | Select-Object *, @{l = 'table'; e = { $CSVTable } } + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' + $CSVfile + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + } + } + } + return $BackupData +} + From 8a9d51e6dc79d8cd7cdd788cba67f188880f65db Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 14:16:14 +0200 Subject: [PATCH 088/138] add list backups --- .../CIPP/Core/Invoke-ExecListBackup.ps1 | 21 ++++++++++ .../Invoke-ListConditionalAccessPolicies.ps1 | 4 +- Modules/CIPPCore/Public/Get-CIPPBackup.ps1 | 14 +++++++ Modules/CIPPCore/Public/New-CIPPBackup.ps1 | 38 ++++++++++++++++++- 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 create mode 100644 Modules/CIPPCore/Public/Get-CIPPBackup.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 new file mode 100644 index 000000000000..a0b21d1f8de9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 @@ -0,0 +1,21 @@ +using namespace System.Net + +Function Invoke-ExecAddAlert { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Backup.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Result = Get-CIPPBackup -type $Request.body.Type -TenantFilter $Request.body.TenantFilter + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Alerts' -message $request.body.text -Sev $request.body.Severity + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Result) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 index 337fc9c46ace..9c46ceae1ec4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 @@ -404,8 +404,8 @@ Function Invoke-ListConditionalAccessPolicies { $AllNamedLocations = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -tenantid $tenantfilter $AllApplications = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/applications' -tenantid $tenantfilter $AllRoleDefinitions = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions' -tenantid $tenantfilter - $GroupListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups' -tenantid $tenantfilter - $UserListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users' -tenantid $tenantfilter | Select-Object * -ExcludeProperty *extensionAttribute* + $GroupListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$top=999' -tenantid $tenantfilter + $UserListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$top=999' -tenantid $tenantfilter | Select-Object * -ExcludeProperty *extensionAttribute* $GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { $temp = [PSCustomObject]@{ diff --git a/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 b/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 new file mode 100644 index 000000000000..e463202983a1 --- /dev/null +++ b/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 @@ -0,0 +1,14 @@ +function Get-CIPPBackup { + [CmdletBinding()] + param ( + [string]$Type, + [string]$TenantFilter + ) + $Table = Get-CippTable -tablename "$($Type)Backup" + if ($TenantFilter) { + $Filter = "PartitionKey eq '$($Type)Backup' and TenantFilter eq '$($TenantFilter)'" + $Table.Filter = $Filter + } + $Info = Get-CIPPAzDataTableEntity @Table + return $info +} diff --git a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 index 3ec96fd0317e..b0e960829858 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 @@ -2,6 +2,7 @@ function New-CIPPBackup { [CmdletBinding()] param ( $backupType, + $StorageOutput = 'default', $TenantFilter, $APIName = 'CIPP Backup', $ExecutingUser @@ -28,9 +29,44 @@ function New-CIPPBackup { $CSVfile } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } } } + + #If Backup type is ConditionalAccess, create Conditional Access backup. + 'ConditionalAccess' { + $ConditionalAccessPolicyOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter + $AllNamedLocations = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations' -tenantid $tenantfilter + switch ($StorageOutput) { + 'default' { + [PSCustomObject]@{ + ConditionalAccessPolicies = $ConditionalAccessPolicyOutput + NamedLocations = $AllNamedLocations + } + } + 'table' { + #Store output in tablestorage for Recovery + $RowKey = $TenantFilter + '_' + (Get-Date).ToString('yyyy-MM-dd-HHmm') + $entity = [PSCustomObject]@{ + PartitionKey = 'ConditionalAccessBackup' + RowKey = $RowKey + TenantFilter = $TenantFilter + Policies = [string]($ConditionalAccessPolicyOutput | ConvertTo-Json -Compress -Depth 10) + NamedLocations = [string]($AllNamedLocations | ConvertTo-Json -Compress -Depth 10) + } + $Table = Get-CippTable -tablename 'ConditionalAccessBackup' + try { + $Result = Add-CIPPAzDataTableEntity @Table -entity $entity -Force + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup for Conditional Access Policies' -Sev 'Debug' + $Result + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup for Conditional Access Policies: $($_.Exception.Message)" -Sev 'Error' + [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + } + } + } + } + } return $BackupData } From ea0dc89f329043d1c368345ff8c14daceb715e73 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 17:26:44 +0200 Subject: [PATCH 089/138] Fixed add policy issue https://github.com/KelvinTegelaar/CIPP/issues/2497 --- .../HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 | 3 ++- Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 index a00bc8c60e64..2df6b1541877 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 @@ -27,6 +27,7 @@ Function Invoke-AddPolicy { try { switch ($Request.Body.TemplateType) { 'AppProtection' { + $PlatformType = 'deviceAppManagement' $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 @@ -85,7 +86,7 @@ Function Invoke-AddPolicy { } Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($Displayname)" -Sev 'Info' if ($AssignTo) { - Set-CIPPAssignedPolicy -GroupName $AssignTo -PolicyId $CreateRequest.id -Type $TemplateTypeURL -TenantFilter $tenant + Set-CIPPAssignedPolicy -GroupName $AssignTo -PolicyId $CreateRequest.id -Type $TemplateTypeURL -TenantFilter $tenant -PlatformType $PlatformType } "Successfully added policy for $($Tenant)" } catch { diff --git a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 index 25cc772e5802..15ecab0ea749 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 @@ -5,6 +5,7 @@ function Set-CIPPAssignedPolicy { $PolicyId, $Type, $TenantFilter, + $PlatformType = 'deviceManagement', $APIName = 'Assign Policy', $ExecutingUser ) @@ -69,7 +70,7 @@ function Set-CIPPAssignedPolicy { assignments = @($assignmentsObject) } if ($PSCmdlet.ShouldProcess($GroupName, "Assigning policy $PolicyId")) { - $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$Type('$($PolicyId)')/assign" -tenantid $tenantFilter -type POST -body ($assignmentsObject | ConvertTo-Json -Depth 10) + $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)." From 4457008bb75fd0a2ce978e717b48e08a5ad50995 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 18:43:59 +0200 Subject: [PATCH 090/138] add language option to autopilot profile --- .../Autopilot/Invoke-AddAutopilotConfig.ps1 | 23 +++++++++++++++---- .../Set-CIPPDefaultAPDeploymentProfile.ps1 | 3 ++- .../Standards/Invoke-CIPPStandardAPConfig.ps1 | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 index 38c9161bbabd..a87a2bcb7824 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 @@ -19,16 +19,29 @@ Function Invoke-AddAutopilotConfig { # Input bindings are passed in via param block. $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value - $displayname = $request.body.Displayname - $description = $request.body.Description $AssignTo = if ($request.body.Assignto -ne 'on') { $request.body.Assignto } - $Profbod = $Request.body + $Profbod = [pscustomobject]$Request.body $usertype = if ($Profbod.NotLocalAdmin -eq 'true') { 'standard' } else { 'administrator' } $DeploymentMode = if ($profbod.DeploymentMode -eq 'true') { 'shared' } else { 'singleUser' } + $profileParams = @{ + displayname = $request.body.Displayname + description = $request.body.Description + usertype = $usertype + DeploymentMode = $DeploymentMode + assignto = $AssignTo + devicenameTemplate = $Profbod.deviceNameTemplate + allowWhiteGlove = $Profbod.allowWhiteGlove + CollectHash = $Profbod.collectHash + hideChangeAccount = $Profbod.hideChangeAccount + hidePrivacy = $Profbod.hidePrivacy + hideTerms = $Profbod.hideTerms + Autokeyboard = $Profbod.Autokeyboard + Language = $ProfBod.languages.value + } $results = foreach ($Tenant in $tenants) { - Set-CIPPDefaultAPDeploymentProfile -tenantFilter $tenant -displayname $displayname -description $description -usertype $usertype -DeploymentMode $DeploymentMode -assignto $AssignTo -devicenameTemplate $Profbod.deviceNameTemplate -allowWhiteGlove $Profbod.allowWhiteGlove -CollectHash $Profbod.collectHash -hideChangeAccount $Profbod.hideChangeAccount -hidePrivacy $Profbod.hidePrivacy -hideTerms $Profbod.hideTerms -Autokeyboard $Profbod.Autokeyboard + $profileParams['tenantFilter'] = $Tenant + Set-CIPPDefaultAPDeploymentProfile @profileParams } - $body = [pscustomobject]@{'Results' = $results } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 b/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 index d953ee938285..07f2646a7243 100644 --- a/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 @@ -15,6 +15,7 @@ function Set-CIPPDefaultAPDeploymentProfile { $hideTerms, $Autokeyboard, $ExecutingUser, + $Language = 'os-default', $APIName = 'Add Default Enrollment Status Page' ) try { @@ -23,7 +24,7 @@ function Set-CIPPDefaultAPDeploymentProfile { 'displayName' = "$($displayname)" 'description' = "$($description)" 'deviceNameTemplate' = "$($DeviceNameTemplate)" - 'language' = 'os-default' + 'language' = "$($Language)" 'enableWhiteGlove' = $([bool]($allowWhiteGlove)) 'deviceType' = 'windowsPc' 'extractHardwareHash' = $([bool]($CollectHash)) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 index 6311c6680421..b6ffea3946d5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 @@ -12,7 +12,7 @@ function Invoke-CIPPStandardAPConfig { 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 + 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 } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message #Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Default Autopilot config: $ErrorMessage" -sev 'Error' From d97a92f33ed863f09b06b7a252e0fc3f36b9cf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= Date: Thu, 6 Jun 2024 20:40:45 +0200 Subject: [PATCH 091/138] Fex spamfilter thingys not working --- .../Email-Exchange/Invoke-EditSpamFilter.ps1 | 9 ++++----- Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 index 1c638ab96ea1..931299cb6102 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 @@ -20,13 +20,12 @@ Function Invoke-EditSpamFilter { try { $cmdlet = if ($request.query.state -eq 'enable') { 'Enable-HostedContentFilterRule' } else { 'Disable-HostedContentFilterRule' } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true $Result = "Set Spamfilter rule to $($request.query.State)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Set Spamfilter rule $($Request.query.name) to $($request.query.State)" -sev Info - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Failed setting Spamfilter rule $($Request.query.guid) to $($request.query.State). Error:$($_.Exception.Message)" -Sev 'Error' - $ErrorMessage = Get-NormalizedError -Message $_.Exception + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Failed setting Spamfilter rule $($Request.query.guid) to $($request.query.State). Error:$ErrorMessage" -Sev 'Error' $Result = $ErrorMessage } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 index a1b05e12c312..55f525aa36f2 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 @@ -14,20 +14,20 @@ Function Invoke-RemoveSpamfilter { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Tenantfilter = $request.Query.tenantfilter - $Params = @{ Identity = $request.query.name } try { $cmdlet = 'Remove-HostedContentFilterRule' - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true $cmdlet = 'Remove-HostedContentFilterPolicy' - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params + $GraphRequest = 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 { $ErrorMessage = Get-NormalizedError -Message $_.Exception + Write-LogMessage -API 'TransportRules' -tenant $tenantfilter -message "Failed deleting transport rule $($Request.query.name). Error:$ErrorMessage" -Sev Error $Result = $ErrorMessage } # Associate values to output bindings by calling 'Push-OutputBinding'. From 95715e340df2caa043767f1014f98162023285c4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 22:14:38 +0200 Subject: [PATCH 092/138] fixes https://github.com/KelvinTegelaar/CIPP/issues/2521 --- ...voke-ListUserConditionalAccessPolicies.ps1 | 28 +++++++++++-------- .../Invoke-CIPPStandardEnableMailTips.ps1 | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 index dd0ced4e4e68..c56760788f20 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 @@ -22,20 +22,24 @@ Function Invoke-ListUserConditionalAccessPolicies { $UserID = $Request.Query.UserID try { - $json = '{"conditions":{"users":{"allUsers":2,"included":{"userIds":["' + $UserID + '"],"groupIds":[]},"excluded":{"userIds":[],"groupIds":[]}},"servicePrincipals":{"allServicePrincipals":1,"includeAllMicrosoftApps":false,"excludeAllMicrosoftApps":false,"userActions":[],"stepUpTags":[]},"conditions":{"minUserRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"minSigninRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"servicePrincipalRiskLevels":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"devicePlatforms":{"all":2,"included":{"android":false,"ios":false,"windowsPhone":false,"windows":false,"macOs":false,"linux":false},"excluded":null,"applyCondition":false},"locations":{"applyCondition":true,"includeLocationType":2,"excludeAllTrusted":false},"clientApps":{"applyCondition":false,"specificClientApps":false,"webBrowsers":false,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"mobileDesktop":false},"clientAppsV2":{"applyCondition":false,"webBrowsers":false,"mobileDesktop":false,"modernAuth":false,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"otherClients":false},"deviceState":{"includeDeviceStateType":1,"excludeDomainJoionedDevice":false,"excludeCompliantDevice":false,"applyCondition":true}}},"country":"","device":{}}' - $ConditionalAccessPolicyOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter - } catch { - $ConditionalAccessPolicyOutput = @{} - } - - $GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { - if ($cap.id -in $UserPolicies.policyId) { - $temp = [PSCustomObject]@{ - id = $cap.id - displayName = $cap.displayName + $IncludeApplications = 'All' + $CAContext = @{ + '@odata.type' = '#microsoft.graph.whatIfApplicationContext' + 'includeApplications' = @($IncludeApplications) + } + $ConditionalAccessWhatIfDefinition = @{ + 'conditionalAccessWhatIfSubject' = @{ + '@odata.type' = '#microsoft.graph.userSubject' + 'userId' = "$userId" } - $temp + 'conditionalAccessContext' = $CAContext + 'conditionalAccessWhatIfConditions' = @{} } + $JSONBody = $ConditionalAccessWhatIfDefinition | ConvertTo-Json -Depth 10 + + $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter + } catch { + $GraphRequest = @{} } Write-Host $GraphRequest diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 index 516af7e005ed..05ab9cfbd117 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 @@ -14,7 +14,7 @@ function Invoke-CIPPStandardEnableMailTips { Write-LogMessage -API 'Standards' -tenant $Tenant -message 'All MailTips are already enabled.' -sev Info } else { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdparams @{ MailTipsAllTipsEnabled = $true; MailTipsExternalRecipientsTipsEnabled = $true; MailTipsGroupMetricsEnabled = $true; MailTipsLargeAudienceThreshold = $Settings.MailTipsLargeAudienceThreshold } + New-ExoRequest -useSystemMailbox $true -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdparams @{ MailTipsAllTipsEnabled = $true; MailTipsExternalRecipientsTipsEnabled = $true; MailTipsGroupMetricsEnabled = $true; MailTipsLargeAudienceThreshold = $Settings.MailTipsLargeAudienceThreshold } Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Enabled all MailTips' -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message From 6ca472c12f6d71caf304632f60c00f43da306bf8 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 22:21:02 +0200 Subject: [PATCH 093/138] applied ca policies --- .../Users/Invoke-ListUserConditionalAccessPolicies.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 index c56760788f20..c717f77589f1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserConditionalAccessPolicies.ps1 @@ -22,7 +22,7 @@ Function Invoke-ListUserConditionalAccessPolicies { $UserID = $Request.Query.UserID try { - $IncludeApplications = 'All' + $IncludeApplications = '67ad5377-2d78-4ac2-a867-6300cda00e85' $CAContext = @{ '@odata.type' = '#microsoft.graph.whatIfApplicationContext' 'includeApplications' = @($IncludeApplications) @@ -37,7 +37,7 @@ Function Invoke-ListUserConditionalAccessPolicies { } $JSONBody = $ConditionalAccessWhatIfDefinition | ConvertTo-Json -Depth 10 - $GraphRequest = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies' -tenantid $tenantfilter + $GraphRequest = (New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/evaluate' -tenantid $tenantFilter -type POST -body $JsonBody -AsApp $true).value } catch { $GraphRequest = @{} } From 5c91b0e53546dc9b16be3e33496c9be1efafd866 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 6 Jun 2024 23:23:56 +0200 Subject: [PATCH 094/138] allows sam to retry after error --- .../HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 e61a272a80ac..5da4b48da857 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 @@ -13,13 +13,22 @@ Function Invoke-ExecSAMSetup { $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) if ($Request.query.error) { Add-Type -AssemblyName System.Web + $ErrorCode = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) + if ($Request.Query.ErrorCount -lt 2) { + $NewUrl = "$($Request.headers.'x-ms-original-url')&Errors=$($Request.Query.ErrorCount + 1)" + $body = 'An error occurred. We will try again in 3 seconds. The received error was {0}. Reloading... ' -f $ErrorCode, $NewUrl + } else { + $body = 'An error occurred, and we have reached the maximum amount of retries. The received error was {0}. ' -f $ErrorCode + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ ContentType = 'text/html' StatusCode = [HttpStatusCode]::Forbidden - Body = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) + Body = $body }) exit } + if ('admin' -notin $UserCreds.userRoles) { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ ContentType = 'text/html' From e7dde84076b8cc4efdd1bd8786f65a18b8a64813 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Jun 2024 00:06:35 +0200 Subject: [PATCH 095/138] Add or update the Azure App Service build and deployment workflow config --- .github/workflows/dev_cippdb5ta.yml | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/dev_cippdb5ta.yml diff --git a/.github/workflows/dev_cippdb5ta.yml b/.github/workflows/dev_cippdb5ta.yml new file mode 100644 index 000000000000..05a8b1d3e70a --- /dev/null +++ b/.github/workflows/dev_cippdb5ta.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 - cippdb5ta + +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: 'cippdb5ta' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B9812E9D29B34E42AA8D226BAE4E9147 }} \ No newline at end of file From 2b4d6afd5a168654c69bb04f9aea116e33aaf51e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Fri, 7 Jun 2024 00:07:52 +0200 Subject: [PATCH 096/138] Delete .github/workflows/dev_cippdb5ta.yml --- .github/workflows/dev_cippdb5ta.yml | 30 ----------------------------- 1 file changed, 30 deletions(-) delete mode 100644 .github/workflows/dev_cippdb5ta.yml diff --git a/.github/workflows/dev_cippdb5ta.yml b/.github/workflows/dev_cippdb5ta.yml deleted file mode 100644 index 05a8b1d3e70a..000000000000 --- a/.github/workflows/dev_cippdb5ta.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 - cippdb5ta - -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: 'cippdb5ta' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B9812E9D29B34E42AA8D226BAE4E9147 }} \ No newline at end of file From 2a8067ca3dfdd1f114045ef3fb57aabd6e47f9ba Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 00:21:34 +0200 Subject: [PATCH 097/138] SAM Wizard update --- .../HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5da4b48da857..0fecfa4027e1 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 @@ -14,7 +14,7 @@ Function Invoke-ExecSAMSetup { if ($Request.query.error) { Add-Type -AssemblyName System.Web $ErrorCode = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) - if ($Request.Query.ErrorCount -lt 2) { + if ($Request.Query.ErrorCount -lt 2 -or $Request.Query.ErrorCount -eq $null) { $NewUrl = "$($Request.headers.'x-ms-original-url')&Errors=$($Request.Query.ErrorCount + 1)" $body = 'An error occurred. We will try again in 3 seconds. The received error was {0}. Reloading... ' -f $ErrorCode, $NewUrl } else { From de1cbe691e257e73bb91a77c10eaf27783f083d0 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 00:37:38 +0200 Subject: [PATCH 098/138] added retry logic --- .../CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 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 0fecfa4027e1..d423e863ff0c 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 @@ -13,22 +13,13 @@ Function Invoke-ExecSAMSetup { $UserCreds = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json) if ($Request.query.error) { Add-Type -AssemblyName System.Web - $ErrorCode = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) - if ($Request.Query.ErrorCount -lt 2 -or $Request.Query.ErrorCount -eq $null) { - $NewUrl = "$($Request.headers.'x-ms-original-url')&Errors=$($Request.Query.ErrorCount + 1)" - $body = 'An error occurred. We will try again in 3 seconds. The received error was {0}. Reloading... ' -f $ErrorCode, $NewUrl - } else { - $body = 'An error occurred, and we have reached the maximum amount of retries. The received error was {0}. ' -f $ErrorCode - } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ ContentType = 'text/html' StatusCode = [HttpStatusCode]::Forbidden - Body = $body + Body = Get-normalizedError -Message [System.Web.HttpUtility]::UrlDecode($Request.Query.error_description) }) exit } - if ('admin' -notin $UserCreds.userRoles) { Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ ContentType = 'text/html' @@ -90,18 +81,27 @@ Function Invoke-ExecSAMSetup { 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 } - $AppID = $Rows.appid - if (!$AppID) { $appid = $env:ApplicationId } - $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 - if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { - $clientsecret = $Secret.ApplicationSecret - } else { - $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText - } - if (!$clientsecret) { $clientsecret = $ENV:ApplicationSecret } - $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" + $tries = 0 + do { + $tries ++ + $TenantId = $Rows.tenantid + if (!$TenantId) { $TenantId = $ENV:TenantId } + $AppID = $Rows.appid + if (!$AppID) { $appid = $env:ApplicationId } + $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $clientsecret = $Secret.ApplicationSecret + } else { + $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText + } + if (!$clientsecret) { $clientsecret = $ENV:ApplicationSecret } + try { + $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" + } catch { + $RefreshToken = $null + } + if ($tries -ge 1) { Start-Sleep -Seconds 1 } + } until ($RefreshToken.access_token -or $tries -gt 3) if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $Secret.RefreshToken = $RefreshToken.refresh_token @@ -109,7 +109,7 @@ Function Invoke-ExecSAMSetup { } else { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $RefreshToken.refresh_token -AsPlainText -Force) } - + $Results = 'Authentication is now complete. You may now close this window.' try { $SetupPhase = $rows.validated = $true From 0a94610c6bf5fbb1cb59a7410eddd25d782860e1 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 00:47:28 +0200 Subject: [PATCH 099/138] solving auth issues --- .../HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 d423e863ff0c..1f7a4fe3ccf8 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 @@ -84,6 +84,7 @@ Function Invoke-ExecSAMSetup { $tries = 0 do { $tries ++ + $Auth = Get-CIPPAuthentication $TenantId = $Rows.tenantid if (!$TenantId) { $TenantId = $ENV:TenantId } $AppID = $Rows.appid @@ -101,7 +102,7 @@ Function Invoke-ExecSAMSetup { $RefreshToken = $null } if ($tries -ge 1) { Start-Sleep -Seconds 1 } - } until ($RefreshToken.access_token -or $tries -gt 3) + } until ($RefreshToken.refresh_token -or $tries -gt 3) if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $Secret.RefreshToken = $RefreshToken.refresh_token From 2a8c3bc074cc2af5aecf9eeedc5591c162b90ff0 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 00:56:49 +0200 Subject: [PATCH 100/138] tmp --- .../CIPP/Setup/Invoke-ExecSAMSetup.ps1 | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 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 1f7a4fe3ccf8..3818794ddbb0 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 @@ -81,28 +81,19 @@ Function Invoke-ExecSAMSetup { 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 { - $tries = 0 - do { - $tries ++ - $Auth = Get-CIPPAuthentication - $TenantId = $Rows.tenantid - if (!$TenantId) { $TenantId = $ENV:TenantId } - $AppID = $Rows.appid - if (!$AppID) { $appid = $env:ApplicationId } - $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 - if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { - $clientsecret = $Secret.ApplicationSecret - } else { - $clientsecret = Get-AzKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -AsPlainText - } - if (!$clientsecret) { $clientsecret = $ENV:ApplicationSecret } - try { - $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" - } catch { - $RefreshToken = $null - } - if ($tries -ge 1) { Start-Sleep -Seconds 1 } - } until ($RefreshToken.refresh_token -or $tries -gt 3) + $TenantId = $Rows.tenantid + if (!$TenantId) { $TenantId = $ENV:TenantId } + $AppID = $Rows.appid + if (!$AppID) { $appid = $env:ApplicationId } + $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $clientsecret = $Secret.ApplicationSecret + } else { + $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" if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $Secret.RefreshToken = $RefreshToken.refresh_token @@ -110,7 +101,7 @@ Function Invoke-ExecSAMSetup { } else { Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $RefreshToken.refresh_token -AsPlainText -Force) } - + $Results = 'Authentication is now complete. You may now close this window.' try { $SetupPhase = $rows.validated = $true From 1fac3d8e2ccffd2355e0af775355ab534c9f52c5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Jun 2024 20:56:57 -0400 Subject: [PATCH 101/138] Alert webhook tweaks --- .../Push-PublicWebhookProcess.ps1 | 2 +- .../CIPPCore/Public/Get-SlackAlertBlocks.ps1 | 235 ++++++++++++++++++ .../Public/Invoke-CIPPWebhookProcessing.ps1 | 8 +- .../CIPPCore/Public/New-CIPPAlertTemplate.ps1 | 31 +-- Modules/CIPPCore/Public/Send-CIPPAlert.ps1 | 14 +- 5 files changed, 267 insertions(+), 23 deletions(-) create mode 100644 Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-PublicWebhookProcess.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-PublicWebhookProcess.ps1 index cb8e46acde61..0669c01fabfa 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-PublicWebhookProcess.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-PublicWebhookProcess.ps1 @@ -11,7 +11,7 @@ function Push-PublicWebhookProcess { if ($Webhook.Type -eq 'GraphSubscription') { Invoke-CippGraphWebhookProcessing -Data ($Webhook.Data | ConvertFrom-Json) -CIPPID $Webhook.CIPPID -WebhookInfo ($Webhook.Webhookinfo | ConvertFrom-Json) } elseif ($Webhook.Type -eq 'AuditLog') { - Invoke-CippWebhookProcessing -TenantFilter $Webhook.TenantFilter -Data ($Webhook.Data | ConvertFrom-Json) -CIPPPURL $Webhook.CIPPURL + Invoke-CippWebhookProcessing -TenantFilter $Webhook.TenantFilter -Data ($Webhook.Data | ConvertFrom-Json) -CIPPURL $Webhook.CIPPURL } elseif ($Webhook.Type -eq 'PartnerCenter') { Invoke-CippPartnerWebhookProcessing -Data ($Webhook.Data | ConvertFrom-Json) } diff --git a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 new file mode 100644 index 000000000000..ce4dfc21bff0 --- /dev/null +++ b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 @@ -0,0 +1,235 @@ +function Get-SlackAlertBlocks { + [CmdletBinding()] + Param( + $JSONBody + ) + + $Blocks = [system.collections.generic.list[object]]::new() + + $Payload = $JSONBody | ConvertFrom-Json + + if ($Payload.API -eq 'Alerts') { + foreach ($Entry in $Payload) { + # Alert log alerts + $Blocks.Add([PSCustomObject]@{ + type = 'header' + text = @{ + type = 'plain_text' + text = 'New Alert from CIPP' + emoji = $true + } + }) + $Blocks.Add([PSCustomObject]@{ + type = 'section' + fields = @( + @{ + type = 'mrkdwn' + text = "*Tenant:*`n" + $Entry.Tenant + }, + @{ + type = 'mrkdwn' + text = "*Username:*`n" + $Entry.Username + }, + @{ + type = 'mrkdwn' + text = "*Timestamp:*`n" + ($Entry.Timestamp | Get-Date).ToString('yyyy-MM-dd @ hh:mm:ss tt') + } + ) + }) + + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = "*Message:*`n" + $Entry.Message + } + }) + } + } elseif ($Payload.TaskInfo -is [object]) { + #Scheduler + $Blocks.Add([PSCustomObject]@{ + type = 'header' + text = @{ + type = 'plain_text' + text = 'New Alert from CIPP' + emoji = $true + } + }) + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = "*Task Name:*`n" + $Payload.TaskInfo.Name + } + }) + $Blocks.Add([PSCustomObject]@{ + type = 'section' + fields = @( + @{ + type = 'mrkdwn' + text = "*Timestamp:*`n" + ($Payload.TaskInfo.Timestamp | Get-Date).ToString('yyyy-MM-dd @ hh:mm:ss tt') + }, + @{ + type = 'mrkdwn' + text = "*Tenant:*`n" + $Payload.Tenant + } + ) + }) + $Blocks.Add([PSCustomObject]@{ + type = 'divider' + }) + foreach ($Result in $Payload.Results) { + # Check if results is [string] and create text section + if ($Result -is [string]) { + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = $Result + } + }) + } else { + #Iterate through property names and create fields + $Fields = [system.collections.generic.list[object]]::new() + foreach ($Key in $Result.PSObject.Properties.Name) { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key):*`n" + $Result.$Key + }) + } + $Blocks.Add([PSCustomObject]@{ + type = 'section' + fields = @($Fields) + + }) + } + } + } elseif ($Payload.RawData -is [object]) { + # Webhook alert + $Blocks.Add([PSCustomObject]@{ + type = 'header' + text = @{ + type = 'plain_text' + text = 'New Alert from CIPP' + emoji = $true + } + }) + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = "*Title:*`n" + $Payload.Title + } + }) + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = "*Action URL:*`n<" + $Payload.ActionUrl + '|Go to CIPP>' + } + }) + $Blocks.Add([PSCustomObject]@{ + type = 'divider' + }) + + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = '*Webhook Data:*' + } + }) + #loop through rawdata properties and create key value fields + $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) -and (Test-Json -Json $Payload.RawData.$Key -ErrorAction SilentlyContinue)) { + continue + } + + if ([string]::IsNullOrEmpty($Payload.RawData.$Key)) { + continue + } + # if value is date object + if ($Payload.RawData.$Key -is [datetime]) { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key):*`n" + $Payload.RawData.$Key.ToString('yyyy-MM-dd @ hh:mm:ss tt') + }) + } elseif ($Payload.RawData.$Key.PSObject.Properties.Name -is [array] -and $Payload.RawData.$Key.PSObject.Properties.Name.Count -gt 0) { + foreach ($SubKey in $Payload.RawData.$Key.PSObject.Properties.Name) { + if ([string]::IsNullOrEmpty($Payload.RawData.$Key.$SubKey)) { + continue + } elseif ($Payload.RawData.$Key.$SubKey -is [datetime]) { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key)/$($SubKey):*`n" + $Payload.RawData.$Key.$SubKey.ToString('yyyy-MM-dd @ hh:mm:ss tt') + }) + } else { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key)/$($SubKey):*`n" + $Payload.RawData.$Key.$SubKey + }) + } + } + } else { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key):*`n" + $Payload.RawData.$Key + }) + } + } + + $FieldBatch = [system.collections.generic.list[object]]::new() + for ($i = 0; $i -lt $Fields.Count; $i += 10) { + $FieldBatch.Add($Fields[$i..[math]::Min($i + 9, $Fields.Count - 1)]) + } + foreach ($Batch in $FieldBatch) { + $Blocks.Add([PSCustomObject]@{ + type = 'section' + fields = @($Batch) + }) + } + + # if potentiallocationinfo is present + if ($Payload.PotentialLocationInfo) { + # add divider + $Blocks.Add([PSCustomObject]@{ + type = 'divider' + }) + # add text section for location + $Blocks.Add([PSCustomObject]@{ + type = 'section' + text = @{ + type = 'mrkdwn' + text = '*Potential Location Info:*' + } + }) + # loop through location properties and add fields + $LocationFields = [system.collections.generic.list[object]]::new() + foreach ($Key in $Payload.PotentialLocationInfo.PSObject.Properties.Name) { + $LocationFields.Add(@{ + type = 'mrkdwn' + text = "*$($Key):*`n" + $Payload.PotentialLocationInfo.$Key + }) + } + # add fields to section in groups of 10 + $LocationFieldBatch = [system.collections.generic.list[object]]::new() + for ($i = 0; $i -lt $LocationFields.Count; $i += 10) { + $LocationFieldBatch.Add($LocationFields[$i..[math]::Min($i + 9, $LocationFields.Count - 1)]) + } + foreach ($Batch in $LocationFieldBatch) { + $Blocks.Add([PSCustomObject]@{ + type = 'section' + fields = @($Batch) + }) + } + } + } + + if (($Blocks | Measure-Object).Count -gt 0) { + [PSCustomObject]@{ + blocks = $Blocks + } | ConvertTo-Json -Depth 10 + } +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 index 402e91d285ff..d9a5ec18d4c3 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 @@ -5,7 +5,7 @@ function Invoke-CippWebhookProcessing { $Data, $Resource, $Operations, - $CIPPPURL, + $CIPPURL, $APIName = 'Process webhook', $ExecutingUser ) @@ -62,19 +62,19 @@ function Invoke-CippWebhookProcessing { switch ($action) { 'generatemail' { Write-Host 'Going to create the email' - $GenerateEmail = New-CIPPAlertTemplate -format 'html' -data $Data -ActionResults $ActionResults + $GenerateEmail = New-CIPPAlertTemplate -format 'html' -data $Data -ActionResults $ActionResults -CIPPURL $CIPPURL Write-Host 'Going to send the mail' Send-CIPPAlert -Type 'email' -Title $GenerateEmail.title -HTMLContent $GenerateEmail.htmlcontent -TenantFilter $TenantFilter Write-Host 'email should be sent' } 'generatePSA' { - $GenerateEmail = New-CIPPAlertTemplate -format 'html' -data $Data -ActionResults $ActionResults + $GenerateEmail = New-CIPPAlertTemplate -format 'html' -data $Data -ActionResults $ActionResults -CIPPURL $CIPPURL Send-CIPPAlert -Type 'psa' -Title $GenerateEmail.title -HTMLContent $GenerateEmail.htmlcontent -TenantFilter $TenantFilter } 'generateWebhook' { Write-Host 'Generating the webhook content' $LocationInfo = $Data.CIPPLocationInfo | ConvertFrom-Json -ErrorAction SilentlyContinue - $GenerateJSON = New-CIPPAlertTemplate -format 'json' -data $Data -ActionResults $ActionResults + $GenerateJSON = New-CIPPAlertTemplate -format 'json' -data $Data -ActionResults $ActionResults -CIPPURL $CIPPURL $JsonContent = @{ Title = $GenerateJSON.Title ActionUrl = $GenerateJSON.ButtonUrl diff --git a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 index c502a2ea1bf7..a394435e225f 100644 --- a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 @@ -5,7 +5,8 @@ function New-CIPPAlertTemplate { [Parameter(Mandatory = $true)] $Format, $LocationInfo, - $ActionResults + $ActionResults, + $CIPPURL ) $Appname = '[{"Application Name":"ACOM Azure Website","Application IDs":"23523755-3a2b-41ca-9315-f81f3f566a95"},{"Application Name":"AEM-DualAuth","Application IDs":"69893ee3-dd10-4b1c-832d-4870354be3d8"},{"Application Name":"ASM Campaign Servicing","Application IDs":"0cb7b9ec-5336-483b-bc31-b15b5788de71"},{"Application Name":"Azure Advanced Threat Protection","Application IDs":"7b7531ad-5926-4f2d-8a1d-38495ad33e17"},{"Application Name":"Azure Data Lake","Application IDs":"e9f49c6b-5ce5-44c8-925d-015017e9f7ad"},{"Application Name":"Azure Lab Services Portal","Application IDs":"835b2a73-6e10-4aa5-a979-21dfda45231c"},{"Application Name":"Azure Portal","Application IDs":"c44b4083-3bb0-49c1-b47d-974e53cbdf3c"},{"Application Name":"AzureSupportCenter","Application IDs":"37182072-3c9c-4f6a-a4b3-b3f91cacffce"},{"Application Name":"Bing","Application IDs":"9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7"},{"Application Name":"CPIM Service","Application IDs":"bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4"},{"Application Name":"CRM Power BI Integration","Application IDs":"e64aa8bc-8eb4-40e2-898b-cf261a25954f"},{"Application Name":"Dataverse","Application IDs":"00000007-0000-0000-c000-000000000000"},{"Application Name":"Enterprise Roaming and Backup","Application IDs":"60c8bde5-3167-4f92-8fdb-059f6176dc0f"},{"Application Name":"IAM Supportability","Application IDs":"a57aca87-cbc0-4f3c-8b9e-dc095fdc8978"},{"Application Name":"IrisSelectionFrontDoor","Application IDs":"16aeb910-ce68-41d1-9ac3-9e1673ac9575"},{"Application Name":"MCAPI Authorization Prod","Application IDs":"d73f4b35-55c9-48c7-8b10-651f6f2acb2e"},{"Application Name":"Media Analysis and Transformation Service","Application IDs":"944f0bd1-117b-4b1c-af26-804ed95e767e
0cd196ee-71bf-4fd6-a57c-b491ffd4fb1e"},{"Application Name":"Microsoft 365 Support Service","Application IDs":"ee272b19-4411-433f-8f28-5c13cb6fd407"},{"Application Name":"Microsoft App Access Panel","Application IDs":"0000000c-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Approval Management","Application IDs":"65d91a3d-ab74-42e6-8a2f-0add61688c74
38049638-cc2c-4cde-abe4-4479d721ed44"},{"Application Name":"Microsoft Authentication Broker","Application IDs":"29d9ed98-a469-4536-ade2-f981bc1d605e"},{"Application Name":"Microsoft Azure CLI","Application IDs":"04b07795-8ddb-461a-bbee-02f9e1bf7b46"},{"Application Name":"Microsoft Azure PowerShell","Application IDs":"1950a258-227b-4e31-a9cf-717495945fc2"},{"Application Name":"Microsoft Bing Search","Application IDs":"cf36b471-5b44-428c-9ce7-313bf84528de"},{"Application Name":"Microsoft Bing Search for Microsoft Edge","Application IDs":"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8"},{"Application Name":"Microsoft Bing Default Search Engine","Application IDs":"1786c5ed-9644-47b2-8aa0-7201292175b6"},{"Application Name":"Microsoft Defender for Cloud Apps","Application IDs":"3090ab82-f1c1-4cdf-af2c-5d7a6f3e2cc7"},{"Application Name":"Microsoft Docs","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Dynamics ERP","Application IDs":"00000015-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Edge Insider Addons Prod","Application IDs":"6253bca8-faf2-4587-8f2f-b056d80998a7"},{"Application Name":"Microsoft Exchange Online Protection","Application IDs":"00000007-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Forms","Application IDs":"c9a559d2-7aab-4f13-a6ed-e7e9c52aec87"},{"Application Name":"Microsoft Graph","Application IDs":"00000003-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Intune Web Company Portal","Application IDs":"74bcdadc-2fdc-4bb3-8459-76d06952a0e9"},{"Application Name":"Microsoft Intune Windows Agent","Application IDs":"fc0f3af4-6835-4174-b806-f7db311fd2f3"},{"Application Name":"Microsoft Learn","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Office","Application IDs":"d3590ed6-52b3-4102-aeff-aad2292ab01c"},{"Application Name":"Microsoft Office 365 Portal","Application IDs":"00000006-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Office Web Apps Service","Application IDs":"67e3df25-268a-4324-a550-0de1c7f97287"},{"Application Name":"Microsoft Online Syndication Partner Portal","Application IDs":"d176f6e7-38e5-40c9-8a78-3998aab820e7"},{"Application Name":"Microsoft password reset service","Application IDs":"93625bc8-bfe2-437a-97e0-3d0060024faa"},{"Application Name":"Microsoft Power BI","Application IDs":"871c010f-5e61-4fb1-83ac-98610a7e9110"},{"Application Name":"Microsoft Storefronts","Application IDs":"28b567f6-162c-4f54-99a0-6887f387bbcc"},{"Application Name":"Microsoft Stream Portal","Application IDs":"cf53fce8-def6-4aeb-8d30-b158e7b1cf83"},{"Application Name":"Microsoft Substrate Management","Application IDs":"98db8bd6-0cc0-4e67-9de5-f187f1cd1b41"},{"Application Name":"Microsoft Support","Application IDs":"fdf9885b-dd37-42bf-82e5-c3129ef5a302"},{"Application Name":"Microsoft Teams","Application IDs":"1fec8e78-bce4-4aaf-ab1b-5451cc387264"},{"Application Name":"Microsoft Teams Services","Application IDs":"cc15fd57-2c6c-4117-a88c-83b1d56b4bbe"},{"Application Name":"Microsoft Teams Web Client","Application IDs":"5e3ce6c0-2b1f-4285-8d4b-75ee78787346"},{"Application Name":"Microsoft Whiteboard Services","Application IDs":"95de633a-083e-42f5-b444-a4295d8e9314"},{"Application Name":"O365 Suite UX","Application IDs":"4345a7b9-9a63-4910-a426-35363201d503"},{"Application Name":"Office 365 Exchange Online","Application IDs":"00000002-0000-0ff1-ce00-000000000000"},{"Application Name":"Office 365 Management","Application IDs":"00b41c95-dab0-4487-9791-b9d2c32c80f2"},{"Application Name":"Office 365 Search Service","Application IDs":"66a88757-258c-4c72-893c-3e8bed4d6899"},{"Application Name":"Office 365 SharePoint Online","Application IDs":"00000003-0000-0ff1-ce00-000000000000"},{"Application Name":"Office Delve","Application IDs":"94c63fef-13a3-47bc-8074-75af8c65887a"},{"Application Name":"Office Online Add-in SSO","Application IDs":"93d53678-613d-4013-afc1-62e9e444a0a5"},{"Application Name":"Office Online Client AAD- Augmentation Loop","Application IDs":"2abdc806-e091-4495-9b10-b04d93c3f040"},{"Application Name":"Office Online Client AAD- Loki","Application IDs":"b23dd4db-9142-4734-867f-3577f640ad0c"},{"Application Name":"Office Online Client AAD- Maker","Application IDs":"17d5e35f-655b-4fb0-8ae6-86356e9a49f5"},{"Application Name":"Office Online Client MSA- Loki","Application IDs":"b6e69c34-5f1f-4c34-8cdf-7fea120b8670"},{"Application Name":"Office Online Core SSO","Application IDs":"243c63a3-247d-41c5-9d83-7788c43f1c43"},{"Application Name":"Office Online Search","Application IDs":"a9b49b65-0a12-430b-9540-c80b3332c127"},{"Application Name":"Office.com","Application IDs":"4b233688-031c-404b-9a80-a4f3f2351f90"},{"Application Name":"Office365 Shell WCSS-Client","Application IDs":"89bee1f7-5e6e-4d8a-9f3d-ecd601259da7"},{"Application Name":"OfficeClientService","Application IDs":"0f698dd4-f011-4d23-a33e-b36416dcb1e6"},{"Application Name":"OfficeHome","Application IDs":"4765445b-32c6-49b0-83e6-1d93765276ca"},{"Application Name":"OfficeShredderWacClient","Application IDs":"4d5c2d63-cf83-4365-853c-925fd1a64357"},{"Application Name":"OMSOctopiPROD","Application IDs":"62256cef-54c0-4cb4-bcac-4c67989bdc40"},{"Application Name":"OneDrive SyncEngine","Application IDs":"ab9b8c07-8f02-4f72-87fa-80105867a763"},{"Application Name":"OneNote","Application IDs":"2d4d3d8e-2be3-4bef-9f87-7875a61c29de"},{"Application Name":"Outlook Mobile","Application IDs":"27922004-5251-4030-b22d-91ecd9a37ea4"},{"Application Name":"Partner Customer Delegated Admin Offline Processor","Application IDs":"a3475900-ccec-4a69-98f5-a65cd5dc5306"},{"Application Name":"Password Breach Authenticator","Application IDs":"bdd48c81-3a58-4ea9-849c-ebea7f6b6360"},{"Application Name":"Power BI Service","Application IDs":"00000009-0000-0000-c000-000000000000"},{"Application Name":"SharedWithMe","Application IDs":"ffcb16e8-f789-467c-8ce9-f826a080d987"},{"Application Name":"SharePoint Online Web Client Extensibility","Application IDs":"08e18876-6177-487e-b8b5-cf950c1e598c"},{"Application Name":"Signup","Application IDs":"b4bddae8-ab25-483e-8670-df09b9f1d0ea"},{"Application Name":"Skype for Business Online","Application IDs":"00000004-0000-0ff1-ce00-000000000000"},{"Application Name":"Sway","Application IDs":"905fcf26-4eb7-48a0-9ff0-8dcc7194b5ba"},{"Application Name":"Universal Store Native Client","Application IDs":"268761a2-03f3-40df-8a8b-c3db24145b6b"},{"Application Name":"Vortex [wsfed enabled]","Application IDs":"5572c4c0-d078-44ce-b81c-6cbf8d3ed39e"},{"Application Name":"Windows Azure Active Directory","Application IDs":"00000002-0000-0000-c000-000000000000"},{"Application Name":"Windows Azure Service Management API","Application IDs":"797f4846-ba00-4fd7-ba43-dac1f8f63013"},{"Application Name":"WindowsDefenderATP Portal","Application IDs":"a3b79187-70b2-4139-83f9-6016c58cd27b"},{"Application Name":"Windows Search","Application IDs":"26a7ee05-5602-4d76-a7ba-eae8b7b67941"},{"Application Name":"Windows Spotlight","Application IDs":"1b3c667f-cde3-4090-b60b-3d2abd0117f0"},{"Application Name":"Windows Store for Business","Application IDs":"45a330b1-b1ec-4cc1-9161-9f03992aa49f"},{"Application Name":"Yammer","Application IDs":"00000005-0000-0ff1-ce00-000000000000"},{"Application Name":"Yammer Web","Application IDs":"c1c74fed-04c9-4704-80dc-9f79a2e515cb"},{"Application Name":"Yammer Web Embed","Application IDs":"e1ef36fd-b883-4dbf-97f0-9ece4b576fc6"}]' | ConvertFrom-Json | Where-Object -Property 'Application IDs' -EQ $data.applicationId $HTMLTemplate = Get-Content 'TemplateEmail.HTML' -Raw | Out-String @@ -21,14 +22,14 @@ function New-CIPPAlertTemplate { 'New-InboxRule' { $Title = "$($TenantFilter) - New Rule Detected for $($data.UserId)" $RuleTable = ($Data.CIPPParameters | ConvertFrom-Json | ConvertTo-Html -Fragment | Out-String).Replace('
', '
') - + $IntroText = "

A new rule has been created for the user $($data.UserId). You should check if this rule is not malicious. The rule information can be found in the table below.

$RuleTable" if ($ActionResults) { $IntroText = $IntroText + "

Based on the rule, the following actions have been taken: $($ActionResults -join '
' )

" } if ($LocationInfo) { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/ViewBec?userId=$($data.UserId)&tenantDomain=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/ViewBec?userId=$($data.UserId)&tenantDomain=$($data.OrganizationId)" $ButtonText = 'Start BEC Investigation' $AfterButtonText = '

If you believe this is a suspect rule, you can click the button above to start the investigation.

' } @@ -41,7 +42,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/ViewBec?userId=$($data.UserId)&tenantDomain=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/ViewBec?userId=$($data.UserId)&tenantDomain=$($data.OrganizationId)" $ButtonText = 'Start BEC Investigation' $AfterButtonText = '

If you believe this is a suspect rule, you can click the button above to start the investigation.

' } @@ -54,7 +55,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/roles?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/roles?customerId=$($data.OrganizationId)" $ButtonText = 'Role Management' $AfterButtonText = '

If this role is incorrect, or you need more information, use the button to jump to the Role Management page.

' @@ -67,14 +68,14 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/users?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/users?customerId=$($data.OrganizationId)" $ButtonText = 'User Management' $AfterButtonText = '

If this is incorrect, use the user management screen to unblock the users sign-in

' } 'Enable account.' { $Title = "$($TenantFilter) - $($data.ObjectId) has been enabled" $IntroText = "$($data.ObjectId) has been enabled by $($data.UserId)." - $ButtonUrl = "$CIPPPURL/identity/administration/users?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/users?customerId=$($data.OrganizationId)" if ($ActionResults) { $IntroText = $IntroText + "

Based on the rule, the following actions have been taken: $($ActionResults -join '
' )

" } if ($LocationInfo) { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') @@ -86,7 +87,7 @@ function New-CIPPAlertTemplate { 'Update StsRefreshTokenValidFrom Timestamp.' { $Title = "$($TenantFilter) - $($data.ObjectId) has had all sessions revoked" $IntroText = "$($data.ObjectId) has had their sessions revoked by $($data.UserId)." - $ButtonUrl = "$CIPPPURL/identity/administration/users?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/users?customerId=$($data.OrganizationId)" if ($ActionResults) { $IntroText = $IntroText + "

Based on the rule, the following actions have been taken: $($ActionResults -join '
' )

" } if ($LocationInfo) { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') @@ -103,7 +104,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/users?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/users?customerId=$($data.OrganizationId)" $ButtonText = 'User Management' $AfterButtonText = '

If this is incorrect, use the user management screen to reenable MFA

' } @@ -116,7 +117,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/roles?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/roles?customerId=$($data.OrganizationId)" $ButtonText = 'Role Management' $AfterButtonText = '

If this role change is incorrect, or you need more information, use the button to jump to the Role Management page.

' @@ -130,7 +131,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/users?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/users?customerId=$($data.OrganizationId)" $ButtonText = 'User Management' $AfterButtonText = '

If this is incorrect, use the user management screen to unblock the users sign-in

' @@ -145,7 +146,7 @@ function New-CIPPAlertTemplate { $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } $IntroText = "$($data.ObjectId) has been added by $($data.UserId)." - $ButtonUrl = "$CIPPPURL/tenant/administration/enterprise-apps?customerId=?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/tenant/administration/enterprise-apps?customerId=?customerId=$($data.OrganizationId)" $ButtonText = 'Enterprise Apps' } 'Remove service principal.' { @@ -158,7 +159,7 @@ function New-CIPPAlertTemplate { $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } $IntroText = "$($data.ObjectId) has been added by $($data.UserId)." - $ButtonUrl = "$CIPPPURL/tenant/administration/enterprise-apps?customerId=?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/tenant/administration/enterprise-apps?customerId=?customerId=$($data.OrganizationId)" $ButtonText = 'Enterprise Apps' } 'UserLoggedIn' { @@ -171,7 +172,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/ViewBec?userId=$($data.ObjectId)&tenantDomain=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/ViewBec?userId=$($data.ObjectId)&tenantDomain=$($data.OrganizationId)" $ButtonText = 'User Management' $AfterButtonText = '

If this is incorrect, use the user management screen to block the user and revoke the sessions

' } @@ -184,7 +185,7 @@ function New-CIPPAlertTemplate { $LocationTable = ($LocationInfo | ConvertTo-Html -Fragment -As List | Out-String).Replace('
', '
') $IntroText = $IntroText + "

The (potential) location information for this IP is as follows:

$LocationTable" } - $ButtonUrl = "$CIPPPURL/identity/administration/users?customerId=$($data.OrganizationId)" + $ButtonUrl = "$CIPPURL/identity/administration/users?customerId=$($data.OrganizationId)" $ButtonText = 'User Management' } } diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index 59395211a55a..1d62375b5ada 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -53,12 +53,20 @@ function Send-CIPPAlert { if ($PSCmdlet.ShouldProcess($Config.webhook, 'Sending webhook')) { switch -wildcard ($config.webhook) { '*webhook.office.com*' { - $JSonBody = "{`"text`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log.

$JSONContent`"}" + $JSONBody = "{`"text`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log.

$JSONContent`"}" Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody } - '*discord.com*' { - $JSonBody = "{`"content`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log. $JSONContent`"}" + $JSONBody = "{`"content`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log. $JSONContent`"}" + Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody + } + '*slack.com*' { + $SlackBlocks = Get-SlackAlertBlocks -JSONBody $JSONContent + if ($SlackBlocks.blocks) { + $JSONBody = $SlackBlocks + } else { + $JSONBody = "{`"text`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log. $JSONContent`"}" + } Invoke-RestMethod -Uri $config.webhook -Method POST -ContentType 'Application/json' -Body $JSONBody } default { From 74044a39294045a1acba0436475e950715837cf5 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Jun 2024 21:20:57 -0400 Subject: [PATCH 102/138] alert tweaks --- .../CIPPCore/Public/Get-SlackAlertBlocks.ps1 | 20 +++++++++++++------ .../Public/Invoke-CIPPWebhookProcessing.ps1 | 1 + .../CIPPCore/Public/New-CIPPAlertTemplate.ps1 | 5 +++-- Modules/CIPPCore/Public/Send-CIPPAlert.ps1 | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 index ce4dfc21bff0..8f63195f905f 100644 --- a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 +++ b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 @@ -114,6 +114,7 @@ function Get-SlackAlertBlocks { emoji = $true } }) + $Blocks.Add([PSCustomObject]@{ type = 'section' text = @{ @@ -122,11 +123,18 @@ function Get-SlackAlertBlocks { } }) $Blocks.Add([PSCustomObject]@{ - type = 'section' - text = @{ - type = 'mrkdwn' - text = "*Action URL:*`n<" + $Payload.ActionUrl + '|Go to CIPP>' - } + type = 'actions' + elements = @( + @{ + type = 'button' + text = @{ + type = 'plain_text' + text = $Payload.ActionText ?? 'Go to CIPP' + } + url = $Payload.ActionUrl + style = 'primary' + } + ) }) $Blocks.Add([PSCustomObject]@{ type = 'divider' @@ -230,6 +238,6 @@ function Get-SlackAlertBlocks { if (($Blocks | Measure-Object).Count -gt 0) { [PSCustomObject]@{ blocks = $Blocks - } | ConvertTo-Json -Depth 10 + } } } \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 index d9a5ec18d4c3..a1787ddbae34 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPWebhookProcessing.ps1 @@ -78,6 +78,7 @@ function Invoke-CippWebhookProcessing { $JsonContent = @{ Title = $GenerateJSON.Title ActionUrl = $GenerateJSON.ButtonUrl + ActionText = $GenerateJSON.ButtonText RawData = $Data IP = $data.ClientIP PotentialLocationInfo = $LocationInfo diff --git a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 index a394435e225f..ff9853aca307 100644 --- a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 @@ -197,8 +197,9 @@ function New-CIPPAlertTemplate { } } elseif ($Format -eq 'json') { return [pscustomobject]@{ - title = $Title - buttonurl = $ButtonUrl + title = $Title + buttonurl = $ButtonUrl + buttontext = $ButtonText } } } diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index 1d62375b5ada..8fc9e31f7bdf 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -63,7 +63,7 @@ function Send-CIPPAlert { '*slack.com*' { $SlackBlocks = Get-SlackAlertBlocks -JSONBody $JSONContent if ($SlackBlocks.blocks) { - $JSONBody = $SlackBlocks + $JSONBody = $SlackBlocks | ConvertTo-Json -Depth 10 -Compress } else { $JSONBody = "{`"text`": `"You've setup your alert policies to be alerted whenever specific events happen. We've found some of these events in the log. $JSONContent`"}" } From ee9bc311475bdfd046c1c74fd6acc48a0cd95f58 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Jun 2024 22:38:57 -0400 Subject: [PATCH 103/138] Update Invoke-PublicWebhooks.ps1 --- .../Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1 | 1 + 1 file changed, 1 insertion(+) 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 d4633158b895..36eb80645c89 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 @@ -12,6 +12,7 @@ function Invoke-PublicWebhooks { $Webhooks = Get-CIPPAzDataTableEntity @WebhookTable Write-Host 'Received request' $url = ($request.headers.'x-ms-original-url').split('/API') | Select-Object -First 1 + $CIPPURL = [string]$url Write-Host $url if ($Webhooks.Resource -eq 'M365AuditLogs') { Write-Host "Found M365AuditLogs - This is an old entry, we'll deny so Microsoft stops sending it." From cd5f9cfc1adee20bd49e433abcfcb8f9c5441a71 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 6 Jun 2024 23:54:02 -0400 Subject: [PATCH 104/138] Update Invoke-PublicWebhooks.ps1 --- .../Alerts/Invoke-PublicWebhooks.ps1 | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) 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 36eb80645c89..12f1e78a38c4 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 @@ -94,7 +94,6 @@ function Invoke-PublicWebhooks { 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) { @@ -167,23 +166,25 @@ function Invoke-PublicWebhooks { $Where = $Configuration | ForEach-Object { $conditions = $_.Conditions | ConvertFrom-Json | Where-Object { $_.Input.value -ne '' } $actions = $_.Actions - $conditionStrings = foreach ($condition in $conditions) { + $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)'" } - "`$(`$_.$($condition.Property.label)) -$($condition.Operator.value) $value" - } - if ($conditionStrings.Count -gt 1) { - $finalCondition = $conditionStrings -join ' -AND ' - } else { - $finalCondition = $conditionStrings + + $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 } } @@ -196,7 +197,7 @@ function Invoke-PublicWebhooks { if ($ReturnedData) { $ReturnedData = foreach ($item in $ReturnedData) { $item.CIPPAction = $clause.expectedAction - $item.CIPPClause = ($clause.clause | ForEach-Object { "When $($_.Property.label) is $($_.Operator.label) $($_.input.value)" }) -join ' and ' + $item.CIPPClause = $clause.CIPPClause -join ' and ' $item } } From bd386eb542671e010ec2fddc1e3fe9166e03d480 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Jun 2024 00:09:16 -0400 Subject: [PATCH 105/138] limit configurations to content type --- .../Tenant/Administration/Alerts/Invoke-PublicWebhooks.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 12f1e78a38c4..78cded90ff19 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 @@ -74,7 +74,7 @@ function Invoke-PublicWebhooks { $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' } | ForEach-Object { + $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 From 730a940bff3aeb028f3097d878447119932298af Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 12:25:31 +0200 Subject: [PATCH 106/138] adds update policies and driver policies --- .../Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 | 7 +++++++ .../Endpoint/MEM/Invoke-AddPolicy.ps1 | 13 +++++++++++++ .../Public/Entrypoints/Invoke-ListIntunePolicy.ps1 | 3 ++- .../Standards/Invoke-CIPPStandardIntuneTemplate.ps1 | 13 +++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) 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 d01025dc080a..60d86236ca22 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 @@ -61,6 +61,13 @@ Function Invoke-AddIntuneTemplate { $DisplayName = $Template.name + } + 'windowsDriverUpdateProfiles' { + $Type = 'windowsDriverUpdateProfiles' + $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)/$($ID)" -tenantid $tenantfilter | Select-Object * -ExcludeProperty id, lastModifiedDateTime, '@odata.context', 'ScopeTagIds', 'supportsScopeTags', 'createdDateTime' + Write-Host ($Template | ConvertTo-Json) + $DisplayName = $Template.displayName + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress } 'deviceConfigurations' { $Type = 'Device' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 index 2df6b1541877..aca7c04ca269 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 @@ -82,6 +82,19 @@ Function Invoke-AddPolicy { } $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenant -type POST -body $RawJSON } + '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' + } + } } Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Added policy $($Displayname)" -Sev 'Info' diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 index dbccf5a4004e..6bbf36a98274 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 @@ -26,7 +26,8 @@ Function Invoke-ListIntunePolicy { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)('$ID')" -tenantid $tenantfilter } else { - $GraphURLS = @("https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations?`$select=id,displayName,lastModifiedDateTime,roleScopeTagIds,microsoft.graph.unsupportedDeviceConfiguration/originalEntityTypeName&`$expand=assignments&top=1000", + $GraphURLS = @("https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations?`$select=id,displayName,lastModifiedDateTime,roleScopeTagIds,microsoft.graph.unsupportedDeviceConfiguration/originalEntityTypeName&`$expand=assignments&top=1000" + 'https://graph.microsoft.com/beta/deviceManagement/windowsDriverUpdateProfiles' "https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=1000" "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index 39af5a0f9402..9263b386bb23 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -98,6 +98,19 @@ function Invoke-CIPPStandardIntuneTemplate { 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' + } + } } From 8a9e078258d2db4c11327be9b6d6d80809292f93 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Jun 2024 07:08:35 -0400 Subject: [PATCH 107/138] Update Invoke-ExecJITAdmin.ps1 --- .../Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 | 5 +++++ 1 file changed, 5 insertions(+) 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 ad887810061a..1c1c575a598f 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 @@ -103,6 +103,11 @@ Function Invoke-ExecJITAdmin { } Parameters = $Parameters ScheduledTime = $Request.Body.StartDate + PostExecution = @{ + Webhook = [bool]$Request.Body.PostExecution.Webhook + Email = [bool]$Request.Body.PostExecution.Email + PSA = [bool]$Request.Body.PostExecution.PSA + } } Add-CIPPScheduledTask -Task $TaskBody -hidden $false Set-CIPPUserJITAdminProperties -TenantFilter $Request.Body.TenantFilter -UserId $Request.Body.UserId -Expiration $Expiration From e51d7119d6dba7a285ba831cadff9a927b4c4267 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 13:14:09 +0200 Subject: [PATCH 108/138] adds autobackup CIPP --- .../CIPP/Core/Invoke-ExecListBackup.ps1 | 2 +- .../Core/Invoke-ExecSetCIPPAutoBackup.ps1 | 43 +++++++++++++++++++ .../Scheduler/Invoke-RemoveScheduledItem.ps1 | 2 - Modules/CIPPCore/Public/New-CIPPBackup.ps1 | 18 +++++++- 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 index a0b21d1f8de9..90b7e41bc4c9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ExecAddAlert { +Function Invoke-ExecListBackup { <# .FUNCTIONALITY Entrypoint diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 new file mode 100644 index 000000000000..2d04df48933c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 @@ -0,0 +1,43 @@ +using namespace System.Net + +Function Invoke-ExecSetCIPPAutoBackup { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Backup.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + $unixtime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds + if ($Request.query.Enabled -eq 'True') { + $Table = Get-CIPPTable -TableName 'ScheduledTasks' + $AutomatedCIPPBackupTask = Get-AzDataTableEntity @table -Filter "Name eq 'Automated CIPP Backup'" + $task = @{ + RowKey = $AutomatedCIPPBackupTask.RowKey + PartitionKey = 'ScheduledTask' + } + Remove-AzDataTableEntity @Table -Entity $task | Out-Null + + $TaskBody = @{ + TenantFilter = 'AllTenants' + Name = 'Automated CIPP Backup' + Command = @{ + value = 'New-CIPPBackup' + label = 'New-CIPPBackup' + } + Parameters = @{ backupType = 'CIPP' } + ScheduledTime = $unixtime + Recurrence = '1d' + } + Add-CIPPScheduledTask -Task $TaskBody -hidden $false + $Result = @{ 'Results' = 'Scheduled Task Successfully created' } + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Alerts' -message $request.body.text -Sev $request.body.Severity + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Result + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 index 257902f03726..f21b1b88e275 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 @@ -14,8 +14,6 @@ Function Invoke-RemoveScheduledItem { RowKey = $Request.Query.ID PartitionKey = 'ScheduledTask' } - - $Table = Get-CIPPTable -TableName 'ScheduledTasks' Remove-AzDataTableEntity @Table -Entity $task diff --git a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 index b0e960829858..3c9acd37e9cd 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 @@ -23,10 +23,26 @@ function New-CIPPBackup { ) $CSVfile = foreach ($CSVTable in $BackupTables) { $Table = Get-CippTable -tablename $CSVTable - Get-CIPPAzDataTableEntity @Table | Select-Object *, @{l = 'table'; e = { $CSVTable } } + Get-CIPPAzDataTableEntity @Table } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' $CSVfile + $RowKey = 'CIPPBackup' + '_' + (Get-Date).ToString('yyyy-MM-dd-HHmm') + $entity = [PSCustomObject]@{ + PartitionKey = 'CIPPBackup' + RowKey = $RowKey + TenantFilter = 'CIPPBackup' + Backup = [string]($CSVfile | ConvertTo-Json -Compress -Depth 100) + } + $Table = Get-CippTable -tablename 'CIPPBackup' + try { + $Result = Add-CIPPAzDataTableEntity @Table -entity $entity -Force + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created CIPP Backup' -Sev 'Debug' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup for CIPP: $($_.Exception.Message)" -Sev 'Error' + [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + } + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } From 5217464bb21c48b0415260a731a5414241b242bc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Fri, 7 Jun 2024 07:30:18 -0400 Subject: [PATCH 109/138] tweak output for slack --- .../CIPPCore/Public/Get-SlackAlertBlocks.ps1 | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 index 8f63195f905f..b59ce99a3160 100644 --- a/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 +++ b/Modules/CIPPCore/Public/Get-SlackAlertBlocks.ps1 @@ -151,11 +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) -and (Test-Json -Json $Payload.RawData.$Key -ErrorAction SilentlyContinue)) { - continue - } - - if ([string]::IsNullOrEmpty($Payload.RawData.$Key)) { + if ($Payload.RawData.$Key -is [string] -and ![string]::IsNullOrEmpty($Payload.RawData.$Key)) { continue } # if value is date object @@ -164,6 +160,22 @@ function Get-SlackAlertBlocks { type = 'mrkdwn' text = "*$($Key):*`n" + $Payload.RawData.$Key.ToString('yyyy-MM-dd @ hh:mm:ss tt') }) + } elseif ($Payload.RawData.$Key -is [array] -and $Payload.RawData.$Key.Count -gt 0) { + foreach ($SubKey in $Payload.RawData.$Key) { + if ([string]::IsNullOrEmpty($SubKey)) { + continue + } elseif ($SubKey -is [datetime]) { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key):*`n" + $SubKey.ToString('yyyy-MM-dd @ hh:mm:ss tt') + }) + } else { + $Fields.Add(@{ + type = 'mrkdwn' + text = "*$($Key):*`n" + $SubKey + }) + } + } } elseif ($Payload.RawData.$Key.PSObject.Properties.Name -is [array] -and $Payload.RawData.$Key.PSObject.Properties.Name.Count -gt 0) { foreach ($SubKey in $Payload.RawData.$Key.PSObject.Properties.Name) { if ([string]::IsNullOrEmpty($Payload.RawData.$Key.$SubKey)) { @@ -173,6 +185,15 @@ function Get-SlackAlertBlocks { type = 'mrkdwn' text = "*$($Key)/$($SubKey):*`n" + $Payload.RawData.$Key.$SubKey.ToString('yyyy-MM-dd @ hh:mm:ss tt') }) + } elseif (Test-Json $Payload.RawData.$Key.$SubKey -ErrorAction SilentlyContinue) { + # parse json and iterate through properties + $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' From 83edf14e7de427ead136b5221318c50e765482ba Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 13:43:29 +0200 Subject: [PATCH 110/138] convert BPA to use tables instead of files --- .../Tenant/Standards/Invoke-ListBPA.ps1 | 10 ++++++--- .../Standards/Invoke-ListBPATemplates.ps1 | 22 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 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 df3e849a19e8..22e078617475 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 @@ -20,14 +20,18 @@ Function Invoke-ListBPA { # Get all possible JSON files for reports, find the correct one, select the Columns $JSONFields = @() $Columns = $null -(Get-ChildItem -Path 'Config\*.BPATemplate.json' -Recurse | Select-Object -ExpandProperty FullName | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json + $BPATemplateTable = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'BPATemplate'" + $Templates = (Get-CIPPAzDataTableEntity @BPATemplateTable -Filter $Filter).JSON | ConvertFrom-Json + + $Templates | ForEach-Object { + $Template = $_ if ($Template.Name -eq $NAME) { $JSONFields = $Template.Fields | Where-Object { $_.StoreAs -eq 'JSON' } | ForEach-Object { $_.name } $Columns = $Template.fields.FrontendFields | Where-Object -Property name -NE $null $Style = $Template.Style } - }) + } if ($Request.query.tenantFilter -ne 'AllTenants' -and $Style -eq 'Tenant') { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 index 7f7c110fcd9f..376a1f4e592b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPATemplates.ps1 @@ -14,17 +14,27 @@ Function Invoke-ListBPATemplates { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' Write-Host 'PowerShell HTTP trigger function processed a request.' - Write-Host $Request.query.id + + $Table = Get-CippTable -tablename 'templates' - $Templates = Get-ChildItem 'Config\*.BPATemplate.json' + $Templates = Get-ChildItem 'Config\*.BPATemplate.json' | ForEach-Object { + $Entity = @{ + JSON = "$(Get-Content $_)" + RowKey = "$($_.name)" + PartitionKey = 'BPATemplate' + GUID = "$($_.name)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + } + + $Filter = "PartitionKey eq 'BPATemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json if ($Request.Query.RawJson) { - $Templates = $Templates | ForEach-Object { - $(Get-Content $_) | ConvertFrom-Json - } + $Templates } else { $Templates = $Templates | ForEach-Object { - $Template = $(Get-Content $_) | ConvertFrom-Json + $Template = $_ @{ Data = $Template.fields Name = $Template.Name From c702dd63ce53500951c75e5e8535e05723dacae2 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 15:02:57 +0200 Subject: [PATCH 111/138] added publish to bpa reports --- .../Tenant/Tools/Invoke-AddBPATemplate.ps1 | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 new file mode 100644 index 000000000000..15c2d49afc0d --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-AddBPATemplate.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-AddBPATemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.BestPracticeAnalyser.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' + + try { + + $Table = Get-CippTable -tablename 'templates' + $Table.Force = $true + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = "$($Request.body | ConvertTo-Json -Depth 10)" + RowKey = $Request.body.name + PartitionKey = 'BPATemplate' + GUID = $Request.body.name + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created BPA named $($Request.body.name)" -Sev 'Debug' + + $body = [pscustomobject]@{'Results' = 'Successfully added template' } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "BPA Template Creation failed: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "BPA Template Creation failed: $($_.Exception.Message)" } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} From ca839d9a0bbd6c1e2ff2e62752e7d869f2f29399 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 7 Jun 2024 15:20:37 +0200 Subject: [PATCH 112/138] version up --- version_latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_latest.txt b/version_latest.txt index dfa102a57492..edb1d397cf28 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -5.7.4 +5.8.0 \ No newline at end of file From 7f1339631e3f02699367579ddb9774719006e70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= <31723128+kris6673@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:17:42 +0200 Subject: [PATCH 113/138] Merge pull request #58 from KelvinTegelaar/dev [pull] dev from KelvinTegelaar:dev From 5b98c82fbd2bca16924057b04ada750ef3a56532 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:40:37 +0200 Subject: [PATCH 114/138] Merge pull request #861 from Ren-Roros-Digital/editorconfig 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 38d45dc2d999af1916fa0511ce9f14001cb5051b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20Kj=C3=A6rg=C3=A5rd?= <31723128+kris6673@users.noreply.github.com> Date: Mon, 10 Jun 2024 17:38:51 +0200 Subject: [PATCH 115/138] Merge branch 'KelvinTegelaar:dev' into dev From a253d76c46b748b4af969751f6daef102eef4959 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 116/138] 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 e8f7a55cd26ee4870db0c1b870f7639caa6056a9 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Mon, 10 Jun 2024 23:17:01 +0200 Subject: [PATCH 117/138] Merge pull request #885 from kris6673/dev Add roles to second SAMManifest file From 64f4965b5bc6c116d8761f4f39ac2571e87d4ecc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 10 Jun 2024 19:02:16 -0400 Subject: [PATCH 118/138] 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 5056fcf2a533a8123f11c8d103ab0b0c36368f08 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 12 Jun 2024 20:57:30 +0200 Subject: [PATCH 119/138] 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 8d3b66b3518e6679e18ff8171bafb99b4c1cfd0f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Wed, 12 Jun 2024 20:59:30 +0200 Subject: [PATCH 120/138] 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 62ee4fb81d2ee62c2e3d720012ee84156034f906 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Jun 2024 15:43:02 -0400 Subject: [PATCH 121/138] 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 28e88e204d79..65a5edca23f2 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -52,7 +52,9 @@ function New-GraphGetRequest { if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' } } } 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 cd8b2929fcc7e9047d15d42c49ca298cb609c01a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Jun 2024 15:43:16 -0400 Subject: [PATCH 122/138] 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 7d61557ced6385d885b646be5fb2227fb2323766 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 00:04:13 +0200 Subject: [PATCH 123/138] 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 cda510e736803575fe2f7ba26fc4a6185d303298 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 01:36:30 +0200 Subject: [PATCH 124/138] 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 2f97db6ed4530f18f090d5994edf131141dbfb75 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 01:38:16 +0200 Subject: [PATCH 125/138] 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 0914e2f161531f023c59831d17f660f337ff858b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 02:20:40 +0200 Subject: [PATCH 126/138] 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 82a0f19ec177707949c2ae650d7ef9a28f5457b3 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 12 Jun 2024 23:53:01 -0400 Subject: [PATCH 127/138] 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 eedab329061c..5bb406658e37 100644 --- a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 @@ -1,30 +1,68 @@ 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 = @{ + PerUserState = $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' } } } + $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 3f7d424de3600dbe384fc1ccd8e092df7b99bf94 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 12:16:45 +0200 Subject: [PATCH 128/138] changes for CIPP From 425830028e56a7f67845980588ed3ffd289d3d07 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 12:22:04 +0200 Subject: [PATCH 129/138] 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 aa755aec0c9a101b479fae135470bdf74151e25f Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 12:48:07 +0200 Subject: [PATCH 130/138] 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 72412d479b16f71434e76557d019d663f34fdc70 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Thu, 13 Jun 2024 13:56:56 +0200 Subject: [PATCH 131/138] 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 92c253dc357e11acaecde7108083b3d0a25e56c2 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 00:14:15 +0200 Subject: [PATCH 132/138] 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 09c2cf5986b29fa32a20ca06bbe7243001e26d22 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:03:02 +0200 Subject: [PATCH 133/138] 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 455ad75884349e21c9a6efe903f35330aef04e13 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:06:02 +0200 Subject: [PATCH 134/138] 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 e094d8cecbdeeb5488265d18b883fba1d2077c58 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:26:27 +0200 Subject: [PATCH 135/138] 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 9b3b9de38e888917268bf1e70811f85802e1c4c4 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 12:27:42 +0200 Subject: [PATCH 136/138] 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 d5f7c5e245193be58f0281189aac556fbb373295 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 14:59:43 +0200 Subject: [PATCH 137/138] 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 285e24c791375e1ecfb36b434487ebde9e9ccdca Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Fri, 14 Jun 2024 15:27:54 +0200 Subject: [PATCH 138/138] final touches prerelease --- Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 | 3 ++- .../Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 b/Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1 index 5bb406658e37..1c92a5e9c5d2 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 = @{ - PerUserState = $State + perUserMFAstate = $State } $Requests = foreach ($id in $userId) { @{ @@ -48,6 +48,7 @@ function Set-CIPPPerUserMFA { } } + $Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true "Successfully set Per user MFA State for $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