diff --git a/.github/workflows/dev_cippz6s4d.yml b/.github/workflows/dev_cipp4i6t3.yml similarity index 87% rename from .github/workflows/dev_cippz6s4d.yml rename to .github/workflows/dev_cipp4i6t3.yml index d58532dffc2f..88825a14b52c 100644 --- a/.github/workflows/dev_cippz6s4d.yml +++ b/.github/workflows/dev_cipp4i6t3.yml @@ -1,7 +1,7 @@ # 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 - cippz6s4d +name: Build and deploy Powershell project to Azure Function App - cipp4i6t3 on: push: @@ -24,7 +24,7 @@ jobs: uses: Azure/functions-action@v1 id: fa with: - app-name: 'cippz6s4d' + app-name: 'cipp4i6t3' slot-name: 'Production' package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_D27E7CF0887F4E4591F3957CCA96F0FD }} \ No newline at end of file + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_9D257A31ACA24925A112AF5FFC2BEAFE }} \ No newline at end of file diff --git a/.github/workflows/dev_cipphfjdq.yml b/.github/workflows/dev_cipphfjdq.yml deleted file mode 100644 index 92f528b5e404..000000000000 --- a/.github/workflows/dev_cipphfjdq.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 - cipphfjdq - -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: 'cipphfjdq' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_194504F3E0EE4941A2206C7E71DA4915 }} \ No newline at end of file diff --git a/.github/workflows/dev_cippacnqv.yml b/.github/workflows/dev_cippkwn4s.yml similarity index 73% rename from .github/workflows/dev_cippacnqv.yml rename to .github/workflows/dev_cippkwn4s.yml index 67a58b70c7ff..f45e9d0712fd 100644 --- a/.github/workflows/dev_cippacnqv.yml +++ b/.github/workflows/dev_cippkwn4s.yml @@ -1,7 +1,7 @@ # Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action # More GitHub Actions for Azure: https://github.com/Azure/actions -name: Build and deploy Powershell project to Azure Function App - cippacnqv +name: Build and deploy Powershell project to Azure Function App - cippkwn4s on: push: @@ -23,17 +23,17 @@ jobs: uses: actions/checkout@v4 - name: Login to Azure - uses: azure/login@v1 + uses: azure/login@v2 with: - client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_6085081ED1124B799258E9FF743FF4B9 }} - tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_9BDB2DDBFAFA4BC19C20A58B204BFAF3 }} - subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_02B5224812794971B05EDD557AF2B867 }} + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_B6BCC8886F40482FB8B43907FCDA6596 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_0D1C65B9099F48FABDF7F7052EA6887F }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_76518AE5ECB34375A414DEEE1119C161 }} - name: 'Run Azure Functions Action' uses: Azure/functions-action@v1 id: fa with: - app-name: 'cippacnqv' + app-name: 'cippkwn4s' slot-name: 'Production' package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} \ No newline at end of file diff --git a/.github/workflows/dev_cippckdtz.yml b/.github/workflows/dev_cipplwwww.yml similarity index 87% rename from .github/workflows/dev_cippckdtz.yml rename to .github/workflows/dev_cipplwwww.yml index c81980006ad4..7fe7c6279bb1 100644 --- a/.github/workflows/dev_cippckdtz.yml +++ b/.github/workflows/dev_cipplwwww.yml @@ -1,7 +1,7 @@ # Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action # More GitHub Actions for Azure: https://github.com/Azure/actions -name: Build and deploy Powershell project to Azure Function App - cippckdtz +name: Build and deploy Powershell project to Azure Function App - cipplwwww on: push: @@ -24,7 +24,7 @@ jobs: uses: Azure/functions-action@v1 id: fa with: - app-name: 'cippckdtz' + app-name: 'cipplwwww' slot-name: 'Production' package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_726578DA8A7243BF9D82FE123C2F6E7F }} \ No newline at end of file + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_00A9A6DFE9244C2EA8952190FFF10F45 }} \ No newline at end of file diff --git a/.github/workflows/dev_cippopy3o.yml b/.github/workflows/dev_cippopy3o.yml deleted file mode 100644 index b4f3617bccdf..000000000000 --- a/.github/workflows/dev_cippopy3o.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 - cippopy3o - -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: 'cippopy3o' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B5A7200CF39F4853A33349B80D54DC99 }} \ No newline at end of file diff --git a/.github/workflows/dev_cipppwrro.yml b/.github/workflows/dev_cipppwrro.yml deleted file mode 100644 index ad786fd522fe..000000000000 --- a/.github/workflows/dev_cipppwrro.yml +++ /dev/null @@ -1,29 +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 - cipppwrro - -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: - build-and-deploy: - runs-on: windows-latest - steps: - - name: 'Checkout GitHub Action' - uses: actions/checkout@v2 - - - name: 'Run Azure Functions Action' - uses: Azure/functions-action@v1 - id: fa - with: - app-name: 'cipppwrro' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_9E109464904540339CA94F283ACE1312 }} diff --git a/.github/workflows/ninjaone_cipp426ns.yml b/.github/workflows/ninjaone_cipp426ns.yml deleted file mode 100644 index 6df7b1bab0e9..000000000000 --- a/.github/workflows/ninjaone_cipp426ns.yml +++ /dev/null @@ -1,29 +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 - cipp426ns - -on: - push: - branches: - - NinjaOne - workflow_dispatch: - -env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root - -jobs: - build-and-deploy: - runs-on: windows-latest - steps: - - name: 'Checkout GitHub Action' - uses: actions/checkout@v2 - - - name: 'Run Azure Functions Action' - uses: Azure/functions-action@v1 - id: fa - with: - app-name: 'cipp426ns' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_198DAF92160A4302B5AA0C145DE72796 }} diff --git a/Config/SharePoint.BPATemplate.json b/Config/SharePoint.BPATemplate.json index da945a5d1f4f..fd279d368fda 100644 --- a/Config/SharePoint.BPATemplate.json +++ b/Config/SharePoint.BPATemplate.json @@ -31,18 +31,18 @@ }, { "name": "Resharing by external users", - "value": "isResharingByExternalUsersEnabled", - "formatter": "reverseBool" + "value": "SharepointSettings.isResharingByExternalUsersEnabled", + "formatter": "bool" }, { "name": "Allow users to sync from unmanaged devices", "value": "SharepointSettings.isUnmanagedSyncAppForTenantRestricted", - "formatter": "bool" + "formatter": "reverseBool" }, { - "name": "Site creation by standards users enabled", + "name": "Site creation by standard users enabled", "value": "SharepointSettings.isSiteCreationEnabled", - "formatter": "reverseBool" + "formatter": "bool" }, { "name": "Deleted user data rention(days)", diff --git a/Config/standards.json b/Config/standards.json index d33bb8a39889..da8c98b3a014 100644 --- a/Config/standards.json +++ b/Config/standards.json @@ -2235,7 +2235,7 @@ "value": "none" }, { - "label": "Restirct sharing to specific domains", + "label": "Restrict sharing to specific domains", "value": "allowList" }, { diff --git a/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 b/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 index b63db8aeb3f8..b4b6c7d177ca 100644 --- a/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1 @@ -11,7 +11,26 @@ function Add-CIPPApplicationPermission { } Set-Location (Get-Item $PSScriptRoot).FullName if ($RequiredResourceAccess -eq 'CIPPDefaults') { - $RequiredResourceAccess = (Get-Content '.\SAMManifest.json' | ConvertFrom-Json).requiredResourceAccess + #$RequiredResourceAccess = (Get-Content '.\SAMManifest.json' | ConvertFrom-Json).requiredResourceAccess + + $Permissions = Get-CippSamPermissions -NoDiff + $RequiredResourceAccess = [System.Collections.Generic.List[object]]::new() + + foreach ($AppId in $Permissions.Permissions.PSObject.Properties.Name) { + $AppPermissions = @($Permissions.Permissions.$AppId.applicationPermissions) + $Resource = @{ + resourceAppId = $AppId + resourceAccess = [System.Collections.Generic.List[object]]::new() + } + foreach ($Permission in $AppPermissions) { + $Resource.ResourceAccess.Add(@{ + id = $Permission.id + type = 'Role' + }) + } + + $RequiredResourceAccess.Add($Resource) + } } $ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -skipTokenCache $true -tenantid $Tenantfilter -NoAuthCheck $true $ourSVCPrincipal = $ServicePrincipalList | Where-Object -Property AppId -EQ $ApplicationId diff --git a/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 b/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 index 03be9e2a44d6..37932d98b9e6 100644 --- a/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 @@ -15,8 +15,24 @@ function Add-CIPPDelegatedPermission { } if ($RequiredResourceAccess -eq 'CIPPDefaults') { - $RequiredResourceAccess = (Get-Content '.\SAMManifest.json' | ConvertFrom-Json).requiredResourceAccess - $AdditionalPermissions = Get-Content '.\AdditionalPermissions.json' | ConvertFrom-Json + $Permissions = Get-CippSamPermissions -NoDiff + $NoTranslateRequired = $Permissions.Type -eq 'Table' + $RequiredResourceAccess = [System.Collections.Generic.List[object]]::new() + foreach ($AppId in $Permissions.Permissions.PSObject.Properties.Name) { + $DelegatedPermissions = @($Permissions.Permissions.$AppId.delegatedPermissions) + $ResourceAccess = [System.Collections.Generic.List[object]]::new() + foreach ($Permission in $DelegatedPermissions) { + $ResourceAccess.Add(@{ + id = $Permission.value + type = 'Scope' + }) + } + $Resource = @{ + resourceAppId = $AppId + resourceAccess = @($ResourceAccess) + } + $RequiredResourceAccess.Add($Resource) + } if ($Tenantfilter -eq $env:TenantID) { $RequiredResourceAccess = $RequiredResourceAccess + ($AdditionalPermissions | Where-Object { $RequiredResourceAccess.resourceAppId -notcontains $_.resourceAppId }) @@ -24,7 +40,6 @@ function Add-CIPPDelegatedPermission { # remove the partner center permission if not pushing to partner tenant $RequiredResourceAccess = $RequiredResourceAccess | Where-Object { $_.resourceAppId -ne 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd' } } - $RequiredResourceAccess = $RequiredResourceAccess + ($AdditionalPermissions | Where-Object { $RequiredResourceAccess.resourceAppId -notcontains $_.resourceAppId }) } $Translator = Get-Content '.\PermissionsTranslator.json' | ConvertFrom-Json $ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -tenantid $Tenantfilter -skipTokenCache $true -NoAuthCheck $true @@ -46,16 +61,22 @@ function Add-CIPPDelegatedPermission { continue } } - $AdditionalScopes = ($AdditionalPermissions | Where-Object -Property resourceAppId -EQ $App.resourceAppId).resourceAccess | Where-Object -Property type -EQ 'Scope' + $DelegatedScopes = $App.resourceAccess | Where-Object -Property type -EQ 'Scope' - if ($AdditionalScopes) { - $NewScope = (@(($Translator | Where-Object { $_.id -in $DelegatedScopes.id }).value) + @($AdditionalScopes.id | Select-Object -Unique)) -join ' ' + if ($NoTranslateRequired) { + $NewScope = @($DelegatedScopes | ForEach-Object { $_.id } | Sort-Object -Unique) -join ' ' } else { - if ($NoTranslateRequired) { - $NewScope = @($DelegatedScopes | ForEach-Object { $_.id } | Sort-Object -Unique) -join ' ' - } else { - $NewScope = @(($Translator | Where-Object { $_.id -in $DelegatedScopes.id }).value | Sort-Object -Unique) -join ' ' + $NewScope = foreach ($Scope in $DelegatedScopes.id) { + if ($Scope -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') { + $TranslatedScope = ($Translator | Where-Object -Property id -EQ $Scope).value + if ($TranslatedScope) { + $TranslatedScope + } + } else { + $Scope + } } + $NewScope = (@($NewScope) | Sort-Object -Unique) -join ' ' } $OldScope = ($CurrentDelegatedScopes | Where-Object -Property Resourceid -EQ $svcPrincipalId.id) @@ -83,7 +104,7 @@ function Add-CIPPDelegatedPermission { # Added permissions $Added = ($Compare | Where-Object { $_.SideIndicator -eq '=>' }).InputObject -join ' ' $Removed = ($Compare | Where-Object { $_.SideIndicator -eq '<=' }).InputObject -join ' ' - $Results.add("Successfully updated permissions for $($svcPrincipalId.displayName). $(if ($Added) { "Added: $Added"}) $(if ($Removed) { "Removed: $Removed"})") + $Results.add("Successfully updated permissions for $($svcPrincipalId.displayName). $(if ($Added) { "Added: $Added"}) $(if ($Removed) { "Removed: $Removed"})") } } diff --git a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 index 4b08eda522bb..30aa79cffaa2 100644 --- a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 @@ -51,6 +51,10 @@ function Add-CIPPScheduledTask { $task.Recurrence.value } + if ([int64]$task.ScheduledTime -eq 0 -or [string]::IsNullOrEmpty($task.ScheduledTime)) { + $task.ScheduledTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds + } + $entity = @{ PartitionKey = [string]'ScheduledTask' TaskState = [string]'Planned' diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertHuntressRogueApps.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertHuntressRogueApps.ps1 new file mode 100644 index 000000000000..efd1326fbcc5 --- /dev/null +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertHuntressRogueApps.ps1 @@ -0,0 +1,44 @@ +function Get-CIPPAlertHuntressRogueApps { + <# + .SYNOPSIS + Check for rogue apps in a Tenant + .DESCRIPTION + This function checks for rogue apps in the tenant by comparing the service principals in the tenant with a list of known rogue apps provided by Huntress. + .FUNCTIONALITY + Entrypoint + .LINK + https://huntresslabs.github.io/rogueapps/ + #> + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $false)] + [Alias('input')] + $InputValue, + $TenantFilter + ) + + try { + $RogueApps = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/huntresslabs/rogueapps/main/public/rogueapps.json' + $RogueAppFilter = $RogueApps.appId -join "','" + $ServicePrincipals = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$filter=appId in ('$RogueAppFilter')" -tenantid $TenantFilter + + if (($ServicePrincipals | Measure-Object).Count -gt 0) { + $AlertData = foreach ($ServicePrincipal in $ServicePrincipals) { + $RogueApp = $RogueApps | Where-Object { $_.appId -eq $ServicePrincipal.appId } + [pscustomobject]@{ + 'App Name' = $RogueApp.appDisplayName + 'App Id' = $RogueApp.appId + 'Description' = $RogueApp.description + 'Enabled' = $ServicePrincipal.accountEnabled + 'Created' = $ServicePrincipal.createdDateTime + 'Tags' = $RogueApp.tags -join ', ' + 'References' = $RogueApp.references -join ', ' + 'Huntress Added' = $RogueApp.dateAdded + } + } + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + } + } catch { + #Write-AlertMessage -tenant $($TenantFilter) -message "Failed to check for rogue apps for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)" + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index f157dd0884b9..65ce3ff5d36a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -4,6 +4,7 @@ function Push-ExecScheduledCommand { Entrypoint #> param($Item) + $item = $Item | ConvertTo-Json -Depth 100 | ConvertFrom-Json Write-Host "We are going to be running a scheduled task: $($Item.TaskInfo | ConvertTo-Json -Depth 10)" $Table = Get-CippTable -tablename 'ScheduledTasks' @@ -99,8 +100,16 @@ function Push-ExecScheduledCommand { '(\d+)d$' { [int64]$matches[1] * 86400 } default { throw "Unsupported recurrence format: $($task.Recurrence)" } } + + if ($secondsToAdd -gt 0) { + $unixtimeNow = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds + if ([int64]$task.ScheduledTime -lt ($unixtimeNow - $secondsToAdd)) { + $task.ScheduledTime = $unixtimeNow + } + } + $nextRunUnixTime = [int64]$task.ScheduledTime + [int64]$secondsToAdd - Write-Host "The job is recurring and should occur again at: $nextRunUnixTime" + Write-Host "The job is recurring. It was scheduled for $($task.ScheduledTime). The next runtime should be $nextRunUnixTime" Update-AzDataTableEntity @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 index b16829c6a3a7..e74208b8887c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 @@ -1,15 +1,24 @@ function Push-AuditLogTenant { Param($Item) + # Get Table contexts $AuditBundleTable = Get-CippTable -tablename 'AuditLogBundles' - $SchedulerConfig = Get-CIPPTable -TableName 'SchedulerConfig' - $CIPPURL = Get-CIPPAzDataTableEntity @SchedulerConfig -Filter "PartitionKey eq 'webhookcreation'" | Select-Object -First 1 -ExpandProperty CIPPURL + $SchedulerConfig = Get-CippTable -TableName 'SchedulerConfig' $WebhookTable = Get-CippTable -tablename 'webhookTable' + $ConfigTable = Get-CippTable -TableName 'WebhookRules' + + # Query CIPPURL for linking + $CIPPURL = Get-CIPPAzDataTableEntity @SchedulerConfig -Filter "PartitionKey eq 'webhookcreation'" | Select-Object -First 1 -ExpandProperty CIPPURL + + # Get all webhooks for the tenant $Webhooks = Get-CIPPAzDataTableEntity @WebhookTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and Version eq '3'" | Where-Object { $_.Resource -match '^Audit' } - $ExistingBundles = Get-CIPPAzDataTableEntity @AuditBundleTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and ContentType eq '$ContentType'" - $ConfigTable = Get-CIPPTable -TableName 'WebhookRules' + + # Get webhook rules $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable + # Date filter for existing bundles + $LastHour = (Get-Date).AddHours(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss') + $NewBundles = [System.Collections.Generic.List[object]]::new() foreach ($Webhook in $Webhooks) { # only process webhooks that are configured in the webhookrules table @@ -28,6 +37,7 @@ function Push-AuditLogTenant { EndTime = $Item.EndTime } $LogBundles = Get-CIPPAuditLogContentBundles @ContentBundleQuery + $ExistingBundles = Get-CIPPAzDataTableEntity @AuditBundleTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and ContentType eq '$LogType' and Timestamp ge datetime'$($LastHour)'" foreach ($Bundle in $LogBundles) { if ($ExistingBundles.RowKey -notcontains $Bundle.contentId) { @@ -61,5 +71,4 @@ function Push-AuditLogTenant { $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) Write-Host "Started orchestration with ID = '$InstanceId'" } - } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 new file mode 100644 index 000000000000..c2fe14c59131 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 @@ -0,0 +1,69 @@ +function Invoke-ExecServicePrincipals { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Core.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $TenantFilter = $env:TenantId + + $Success = $true + + $Action = $Request.Query.Action ?? 'Default' + try { + switch ($Request.Query.Action) { + 'Create' { + $Action = 'Create' + if ($Request.Query.AppId -match '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$') { + $Body = @{ + 'appId' = $Request.Query.AppId + } | ConvertTo-Json -Compress + try { + $Results = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body + } catch { + $Results = "Unable to create service principal: $($_.Exception.Message)" + $Success = $false + } + } else { + $Results = 'Invalid AppId' + $Success = $false + } + } + default { + if ($Request.Query.AppId) { + $Action = 'Get' + $Results = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/servicePrincipals(appId='$($Request.Query.AppId)')" -tenantid $TenantFilter -NoAuthCheck $true + } else { + $Action = 'List' + $Results = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$orderby=displayName&$count=true' -ComplexFilter -tenantid $TenantFilter -NoAuthCheck $true + } + } + } + } catch { + $Results = $_.Exception.Message + $Success = $false + } + + $Metadata = @{ + 'Action' = $Action + 'Success' = $Success + } + + if ($Request.Query.AppId) { + $Metadata.AppId = $Request.Query.AppId + } + + $Body = @{ + 'Results' = $Results + 'Metadata' = $Metadata + } + + $Json = $Body | ConvertTo-Json -Depth 10 -Compress + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Json + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 new file mode 100644 index 000000000000..bf73ed18cd93 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecOffloadFunctions.ps1 @@ -0,0 +1,56 @@ + +Function Invoke-ExecOffloadFunctions { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $roles = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json).userRoles + if ('superadmin' -notin $roles) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::Forbidden + Body = @{ error = 'You do not have permission to perform this action.' } + }) + return + } else { + $Table = Get-CippTable -tablename 'Config' + + if ($Request.Query.Action -eq 'ListCurrent') { + $CurrentState = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'OffloadFunctions' and RowKey eq 'OffloadFunctions'" + $CurrentState = if (!$CurrentState) { + [PSCustomObject]@{ + OffloadFunctions = $false + } + } else { + [PSCustomObject]@{ + OffloadFunctions = $CurrentState.state + } + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $CurrentState + }) + } else { + Add-CIPPAzDataTableEntity @Table -Entity @{ + PartitionKey = 'OffloadFunctions' + RowKey = 'OffloadFunctions' + state = $request.Body.OffloadFunctions + } -Force + + if ($Request.Body.OffloadFunctions) { + $Results = 'Enabled Offload Functions' + } else { + $Results = 'Disabled Offload Functions' + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ results = $Results } + }) + } + + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecSAMAppPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecSAMAppPermissions.ps1 new file mode 100644 index 000000000000..a3c442c85656 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecSAMAppPermissions.ps1 @@ -0,0 +1,42 @@ +function Invoke-ExecSAMAppPermissions { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + switch ($Request.Query.Action) { + 'Update' { + try { + $Permissions = $Request.Body.Permissions + $Entity = @{ + 'PartitionKey' = 'CIPP-SAM' + 'RowKey' = 'CIPP-SAM' + 'Permissions' = [string]($Permissions.Permissions | ConvertTo-Json -Depth 10 -Compress) + } + $Table = Get-CIPPTable -TableName 'AppPermissions' + $null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + $Body = @{ + 'Results' = 'Permissions Updated' + } + } catch { + $Body = @{ + 'Results' = $_.Exception.Message + } + } + } + default { + $Body = Get-CippSamPermissions + } + } + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = ConvertTo-Json -Depth 10 -InputObject $Body + }) + +} 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 bc94e7cf5851..59527aa0dc92 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 @@ -35,8 +35,14 @@ Function Invoke-AddDefenderDeployment { iosMobileApplicationManagementEnabled = [bool]$Compliance.appSync microsoftDefenderForEndpointAttachEnabled = [bool]$true } | ConvertTo-Json -Compress - $SettingsRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/' -tenantid $tenant -type POST -body $SettingsObj -AsApp $true - "$($Tenant): Successfully set Defender Compliance and Reporting settings" + $ExistingSettings = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/fc780465-2017-40d4-a0c5-307022471b92' -tenantid $tenant + if ($ExistingSettings) { + "Defender Intune Configuration already active for $($Tenant). Skipping" + } else { + $SettingsRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/' -tenantid $tenant -type POST -body $SettingsObj -AsApp $true + "$($Tenant): Successfully set Defender Compliance and Reporting settings" + } + $Settings = switch ($PolicySettings) { { $_.ScanArchives } { @@ -210,11 +216,11 @@ Function Invoke-AddDefenderDeployment { settings = @($EDRSettings) } Write-Host ( $EDRbody) - $CheckExististingEDR = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant + $CheckExististingEDR = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant | Where-Object -Property Name -EQ 'EDR Configuration' if ('EDR Configuration' -in $CheckExististingEDR.Name) { "$($Tenant): EDR Policy already exists. Skipping" } else { - #$EDRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $EDRbody + $EDRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $EDRbody if ($ASR.AssignTo -ne 'none') { $AssignBody = if ($ASR.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($asr.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($EDRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody 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 51e7e429beb7..680460302a7f 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 @@ -136,7 +136,7 @@ Function Invoke-ExecJITAdmin { } } - $Parameters = [pscustomobject]@{ + $Parameters = @{ TenantFilter = $Request.Body.TenantFilter User = @{ 'UserPrincipalName' = $Username @@ -153,7 +153,7 @@ Function Invoke-ExecJITAdmin { value = 'Set-CIPPUserJITAdmin' label = 'Set-CIPPUserJITAdmin' } - Parameters = $Parameters + Parameters = [pscustomobject]$Parameters ScheduledTime = $Request.Body.StartDate PostExecution = @{ Webhook = [bool]$Request.Body.PostExecution.Webhook 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 1667958aa7a1..881f35afbf93 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 @@ -13,31 +13,44 @@ Function Invoke-ExecResetMFA { $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-Host "$($Request.query.ID)" # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter + $UserID = $Request.Query.ID try { - $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') - $tenantid = (Get-Tenants | Where-Object -Property defaultDomainName -EQ $TenantFilter).customerId - $TrackingGuid = (New-Guid).GUID - $LogonPost = @" -http://provisioning.microsoftonline.com/IProvisioningWebService/MsolConnecturn:uuid:$TrackingGuidhttp://www.w3.org/2005/08/addressing/anonymous$($AADGraphtoken['Authorization'])50afce61-c917-435b-8c6d-60aa5a8b8aa71.2.183.57Version47$($TrackingGuid)https://provisioningapi.microsoftonline.com/provisioningwebservice.svcVersion4 -"@ - $DataBlob = (Invoke-RestMethod -Method POST -Uri 'https://provisioningapi.microsoftonline.com/provisioningwebservice.svc' -ContentType 'application/soap+xml; charset=utf-8' -Body $LogonPost).envelope.header.BecContext.DataBlob.'#text' - $MSOLXML = @" -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' + Write-Host "Getting auth methods for $UserID" + $AuthMethods = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$UserID/authentication/methods" -tenantid $TenantFilter -AsApp $true + $Requests = [System.Collections.Generic.List[object]]::new() + foreach ($Method in $AuthMethods) { + if ($Method.'@odata.type' -and $Method.'@odata.type' -ne '#microsoft.graph.passwordAuthenticationMethod') { + $MethodType = ($Method.'@odata.type' -split '\.')[-1] -replace 'Authentication', '' + $Requests.Add(@{ + id = "$MethodType-$($Method.id)" + method = 'DELETE' + url = ('users/{0}/authentication/{1}s/{2}' -f $UserID, $MethodType, $Method.id) + }) + } + } + if (($Requests | Measure-Object).Count -eq 0) { + $Results = [pscustomobject]@{'Results' = "No MFA methods found for user $($Request.Query.ID)" } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + return + } + + $Results = New-GraphBulkRequest -Requests $Requests -tenantid $TenantFilter -asapp $true -erroraction stop + + + if ($Results.status -eq 204) { + $Results = [pscustomobject]@{'Results' = "Successfully completed request. User $($Request.Query.ID) must supply MFA at next logon" } + } else { + $FailedAuthMethods = (($Results | Where-Object { $_.status -ne 204 }).id -split '-')[0] -join ', ' + $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $FailedAuthMethods" } + } } catch { - $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $($Request.query.id): $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset MFA: $($_.Exception.Message)" -Sev 'Error' - + $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $($Request.Query.ID): $(Get-NormalizedError -message $_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset MFA for user $($Request.Query.ID): $($_.Exception.Message)" -Sev 'Error' -LogData (Get-CippException -Exception $_) } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecRemoveTeamsVoicePhoneNumberAssignment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecRemoveTeamsVoicePhoneNumberAssignment.ps1 new file mode 100644 index 000000000000..55619f07deb5 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecRemoveTeamsVoicePhoneNumberAssignment.ps1 @@ -0,0 +1,31 @@ +using namespace System.Net + +Function Invoke-ExecRemoveTeamsVoicePhoneNumberAssignment { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Teams.Voice.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' + + $tenantFilter = $Request.Body.TenantFilter + try { + $null = New-TeamsRequest -TenantFilter $TenantFilter -Cmdlet 'Remove-CsPhoneNumberAssignment' -CmdParams @{Identity = $Request.Body.AssignedTo; PhoneNumber = $Request.Body.PhoneNumber; PhoneNumberType = $Request.Body.PhoneNumberType; ErrorAction = 'stop'} + $Results = [pscustomobject]@{'Results' = "Successfully unassigned $($Request.Body.PhoneNumber) from $($Request.Body.AssignedTo)"} + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev 'Info' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Results = [pscustomobject]@{'Results' = $ErrorMessage} + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev 'Error' + } + # 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-ExecTeamsVoicePhoneNumberAssignment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecTeamsVoicePhoneNumberAssignment.ps1 new file mode 100644 index 000000000000..fa04ac2c41d8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecTeamsVoicePhoneNumberAssignment.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecTeamsVoicePhoneNumberAssignment { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Teams.Voice.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' + + $tenantFilter = $Request.Body.TenantFilter + try { + if ($Request.Body.locationOnly) { + $null = New-TeamsRequest -TenantFilter $TenantFilter -Cmdlet 'Set-CsPhoneNumberAssignment' -CmdParams @{LocationId = $Request.Body.input; PhoneNumber = $Request.Body.PhoneNumber; ErrorAction = 'stop'} + $Results = [pscustomobject]@{'Results' = "Successfully assigned emergency location to $($Request.Body.PhoneNumber)"} + } else { + $null = New-TeamsRequest -TenantFilter $TenantFilter -Cmdlet 'Set-CsPhoneNumberAssignment' -CmdParams @{Identity = $Request.Body.input; PhoneNumber = $Request.Body.PhoneNumber; PhoneNumberType = $Request.Body.PhoneNumberType; ErrorAction = 'stop'} + $Results = [pscustomobject]@{'Results' = "Successfully assigned $($Request.Body.PhoneNumber) to $($Request.Body.input)"} + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev 'Info' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Results = [pscustomobject]@{'Results' = $ErrorMessage} + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev 'Error' + } + # 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-ListTeamsLisLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsLisLocation.ps1 new file mode 100644 index 000000000000..198f83c4680a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsLisLocation.ps1 @@ -0,0 +1,31 @@ +using namespace System.Net + +Function Invoke-ListTeamsLisLocation { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Teams.Voice.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' + + $TenantFilter = $Request.Query.TenantFilter + try { + $EmergencyLocations = New-TeamsRequest -TenantFilter $TenantFilter -Cmdlet 'Get-CsOnlineLisLocation' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $EmergencyLocations = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($EmergencyLocations) + }) + +} 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 e3baf6e4a607..cca477e4a3ce 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 @@ -17,11 +17,10 @@ Function Invoke-EditCAPolicy { $ID = $request.query.guid $results = try { $EditBody = "{`"state`": `"$($request.query.state)`"}" - $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta//identity/conditionalAccess/policies/$($id)" -tenantid $tenant -type PATCH -body $EditBody + $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta//identity/conditionalAccess/policies/$($id)" -tenantid $tenant -type PATCH -body $EditBody -asapp $true Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Edited CA policy: $($ID)" -Sev 'Info' "Successfully edited CA policy: $($ID)" - } - catch { + } catch { "Failed to add CA policy: $($_.Exception.Message)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Failed editing CA policy $($ID). Error: $($_.Exception.Message)" -Sev 'Error' continue 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 39dd529a4ceb..9bf0ae558577 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 @@ -90,284 +90,14 @@ Function Invoke-ListConditionalAccessPolicies { param ( [Parameter()] $ID, - $Applications + $Applications, + $ServicePrincipals ) 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' } - } + + $return = $ServicePrincipals | Where-Object { $_.appId -eq $ID } | Select-Object -ExpandProperty DisplayName if ([string]::IsNullOrEmpty($return)) { $return = $Applications | Where-Object { $_.Appid -eq $ID } | Select-Object -ExpandProperty DisplayName @@ -390,12 +120,53 @@ Function Invoke-ListConditionalAccessPolicies { # 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?$top=999' -tenantid $tenantfilter - $UserListOutput = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$top=999' -tenantid $tenantfilter | Select-Object * -ExcludeProperty *extensionAttribute* + $Requests = @( + @{ + id = 'policies' + url = 'identity/conditionalAccess/policies' + method = 'GET' + } + @{ + id = 'namedLocations' + url = 'identity/conditionalAccess/namedLocations' + method = 'GET' + } + @{ + id = 'applications' + url = 'applications?$top=999&$select=appId,displayName' + method = 'GET' + } + @{ + id = 'roleDefinitions' + url = 'roleManagement/directory/roleDefinitions?$select=id,displayName' + method = 'GET' + } + @{ + id = 'groups' + url = 'groups?$top=999&$select=id,displayName' + method = 'GET' + } + @{ + id = 'users' + url = 'users?$top=999&$select=id,displayName,userPrincipalName' + method = 'GET' + } + @{ + id = 'servicePrincipals' + url = 'servicePrincipals?$top=999&$select=appId,displayName' + method = 'GET' + } + ) + + $GraphRequest = New-GraphBulkRequest -Requests $Requests -tenantid $tenantfilter -asapp $true + + $ConditionalAccessPolicyOutput = ($GraphRequest | Where-Object { $_.id -eq 'policies' }).body.value + $AllNamedLocations = ($GraphRequest | Where-Object { $_.id -eq 'namedLocations' }).body.value + $AllApplications = ($GraphRequest | Where-Object { $_.id -eq 'applications' } ).body.value + $AllRoleDefinitions = ($GraphRequest | Where-Object { $_.id -eq 'roleDefinitions' }).body.value + $GroupListOutput = ($GraphRequest | Where-Object { $_.id -eq 'groups' }).body.value + $UserListOutput = ($GraphRequest | Where-Object { $_.id -eq 'users' }).body.value + $GraphRequest = foreach ($cap in $ConditionalAccessPolicyOutput) { $temp = [PSCustomObject]@{ 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 f200e4729272..032bdea91f1f 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 @@ -13,7 +13,7 @@ Function Invoke-ExecStandardsRun { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $tenantfilter = if ($Request.Query.TenantFilter) { $Request.Query.TenantFilter } else { 'allTenants' } try { - $null = Invoke-CIPPStandardsRun -Tenantfilter $tenantfilter + $null = Invoke-CIPPStandardsRun -Tenantfilter $tenantfilter -Force $Results = "Successfully Started Standards Run for Tenant $tenantfilter" } catch { $Results = "Failed to start standards run for $tenantfilter. Error: $($_.Exception.Message)" diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 1adc1799debd..c8fc8085e27e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -9,7 +9,7 @@ Function Invoke-ExecListAppId { #> [CmdletBinding()] param($Request, $TriggerMetadata) - + Get-CIPPAuthentication $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'))" diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 index 105bdf0df0d8..74fc86ca5da8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-PublicPhishingCheck.ps1 @@ -6,39 +6,16 @@ Function Invoke-PublicPhishingCheck { Entrypoint #> [CmdletBinding()] - param($Request, $TriggerMetadata) - Write-Host ($request | ConvertTo-Json) - - # List valid referers - $validList = @( - 'https://login.microsoftonline.com', - 'https://login.microsoft.net', - 'https://login.microsoft.com', - 'https://autologon.microsoftazuread-sso.com', - 'https://tasks.office.com', - 'https://login.windows.net' - ) - - $matchedUrls = $validList | Where-Object { ([uri]$_).Host -in ([uri]$($request.headers.Referer)).Host } - if ($matchedUrls) { - 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')" - } else { - "Potential Phishing page detected. Detected Information: Access by IP $($request.headers.'x-forwarded-for')" - } - Write-AlertMessage -message $AlertMessage -sev 'Alert' -tenant $Request.query.TenantId + #this has been switched to the external free service by cyberdrain at clone.cipp.app due to extreme numbers of executions if selfhosted. + param($Request, $TriggerMetadata) + if ($Request.body.Cloned) { + Write-AlertMessage -message $Request.body.AlertMessage -sev 'Alert' -tenant $Request.body.TenantId } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - ContentType = 'image/png' - Body = $bytes + StatusCode = [HttpStatusCode]::OK + Body = 'OK' }) - } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 new file mode 100644 index 000000000000..cd5a5e7997c8 --- /dev/null +++ b/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 @@ -0,0 +1,154 @@ +function Get-CippSamPermissions { + <# + .SYNOPSIS + This script retrieves the CIPP-SAM permissions. + + .DESCRIPTION + The Get-CippSamManifest function is used to retrieve the CIPP-SAM permissions either from the manifest files or table. + + .EXAMPLE + Get-CippSamManifest + Retrieves the CIPP SAM manifest located in the module root + + .FUNCTIONALITY + Internal + #> + [CmdletBinding(DefaultParameterSetName = 'Default')] + Param( + [Parameter(ParameterSetName = 'ManifestOnly')] + [switch]$ManifestOnly, + [Parameter(ParameterSetName = 'Default')] + [switch]$SavedOnly, + [Parameter(ParameterSetName = 'Diff')] + [switch]$NoDiff + ) + + if (!$SavedOnly.IsPresent) { + $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase + $SamManifest = Get-Item "$ModuleBase\Public\SAMManifest.json" + $AdditionalPermissions = Get-Item "$ModuleBase\Public\AdditionalPermissions.json" + + $ServicePrincipals = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$select=appId,displayName,appRoles,publishedPermissionScopes' -tenantid $env:TenantID -NoAuthCheck $true + $SAMManifest = Get-Content -Path $SamManifest.FullName | ConvertFrom-Json + $AdditionalPermissions = Get-Content -Path $AdditionalPermissions.FullName | ConvertFrom-Json + + $RequiredResources = $SamManifest.requiredResourceAccess + + $AppIds = ($RequiredResources.resourceAppId + $AdditionalPermissions.resourceAppId) | Sort-Object -Unique + + $Permissions = @{} + foreach ($AppId in $AppIds) { + $ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId + $AppPermissions = [System.Collections.Generic.List[object]]@() + $ManifestPermissions = ($RequiredResources | Where-Object -Property resourceAppId -EQ $AppId).resourceAccess + $UnpublishedPermissions = ($AdditionalPermissions | Where-Object -Property resourceAppId -EQ $AppId).resourceAccess + + foreach ($Permission in $ManifestPermissions) { + $AppPermissions.Add($Permission) + } + if ($UnpublishedPermissions) { + foreach ($Permission in $UnpublishedPermissions) { + $AppPermissions.Add($Permission) + } + } + + $ApplicationPermissions = [system.collections.generic.list[object]]@() + $DelegatedPermissions = [system.collections.generic.list[object]]@() + foreach ($Permission in $AppPermissions) { + if ($Permission.id -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') { + if ($Permission.type -eq 'Role') { + $PermissionName = ($ServicePrincipal.appRoles | Where-Object -Property id -EQ $Permission.id).value + } else { + $PermissionName = ($ServicePrincipal.publishedPermissionScopes | Where-Object -Property id -EQ $Permission.id).value + } + } else { + $PermissionName = $Permission.id + } + + if ($Permission.type -eq 'Role') { + $ApplicationPermissions.Add([PSCustomObject]@{ + id = $Permission.id + value = $PermissionName + + }) + } else { + $DelegatedPermissions.Add([PSCustomObject]@{ + id = $Permission.id + value = $PermissionName + }) + } + } + + $ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId + $Permissions.$AppId = @{ + applicationPermissions = @($ApplicationPermissions | Sort-Object -Property label) + delegatedPermissions = @($DelegatedPermissions | Sort-Object -Property label) + } + } + } + if ($ManifestOnly) { + return [PSCustomObject]@{ + Permissions = $Permissions + Type = 'Manifest' + } + } + + $Table = Get-CippTable -tablename 'AppPermissions' + $SavedPermissions = Get-CippAzDataTableEntity @Table -Filter "PartitionKey eq 'CIPP-SAM' and RowKey eq 'CIPP-SAM'" + if ($SavedPermissions.Permissions) { + $SavedPermissions.Permissions = $SavedPermissions.Permissions | ConvertFrom-Json + } else { + $SavedPermissions = @{ + Permissions = [PSCustomObject]@{} + } + } + + if ($SavedOnly.IsPresent) { + $SavedPermissions | Add-Member -MemberType NoteProperty -Name Type -Value 'Table' + return $SavedPermissions + } + + if (!$NoDiff -and $SavedPermissions.Permissions) { + $DiffPermissions = @{} + foreach ($AppId in $AppIds) { + $ManifestSpPermissions = $Permissions.$AppId + $SavedSpPermission = $SavedPermissions.Permissions.$AppId + $MissingApp = [System.Collections.Generic.List[object]]::new() + $MissingDelegated = [System.Collections.Generic.List[object]]::new() + foreach ($Permission in $ManifestSpPermissions.applicationPermissions) { + if ($SavedSpPermission.applicationPermissions.id -notcontains $Permission.id) { + $MissingApp.Add($Permission) + } + } + foreach ($Permission in $ManifestSpPermissions.delegatedPermissions) { + if ($SavedSpPermission.delegatedPermissions.id -notcontains $Permission.id) { + $MissingDelegated.Add($Permission) + } + } + if ($MissingApp -or $MissingDelegated) { + $DiffPermissions.$AppId = @{ + applicationPermissions = $MissingApp + delegatedPermissions = $MissingDelegated + } + } + } + } + + $SamAppPermissions = @{} + if (($SavedPermissions.Permissions.PSObject.Properties.Name | Measure-Object).Count -gt 0) { + $SamAppPermissions.Permissions = $SavedPermissions.Permissions + $SamAppPermissions.Type = 'Table' + } else { + $SamAppPermissions.Permissions = $Permissions + $SamAppPermissions.Type = 'Manifest' + } + + if (!$NoDiff.IsPresent) { + $SamAppPermissions.MissingPermissions = $DiffPermissions + } + + $SamAppPermissions = $SamAppPermissions | ConvertTo-Json -Depth 10 -Compress | ConvertFrom-Json + + return $SamAppPermissions +} + diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 index 46f092f6aff3..1755a9f58378 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 @@ -21,16 +21,16 @@ function Get-NormalizedError { #We need to check if the message is in one of these fields, and if so, return it. if ($JSONMsg.error.innererror.message) { - Write-Host 'innererror.message found' + Write-Host "innererror.message found: $($JSONMsg.error.innererror.message)" $message = $JSONMsg.error.innererror.message } elseif ($JSONMsg.error.message) { - Write-Host 'error.message found' + Write-Host "error.message found: $($JSONMsg.error.message)" $message = $JSONMsg.error.message } elseif ($JSONMsg.error.details.message) { - Write-Host 'error.details.message found' + Write-Host "error.details.message found: $($JSONMsg.error.details.message)" $message = $JSONMsg.error.details.message } elseif ($JSONMsg.error.innererror.internalException.message) { - Write-Host 'error.innererror.internalException.message found' + Write-Host "error.innererror.internalException.message found: $($JSONMsg.error.innererror.internalException.message)" $message = $JSONMsg.error.innererror.internalException.message } diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 index 08b06d792cc6..5828884a19d1 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 @@ -25,7 +25,6 @@ function Write-LogMessage { if (!$tenant) { $tenant = 'None' } if (!$username) { $username = 'CIPP' } if ($sev -eq 'Debug' -and $env:DebugMode -ne $true) { - Write-Information 'Not writing to log file - Debug mode is not enabled.' return } $PartitionKey = (Get-Date -UFormat '%Y%m%d').ToString() @@ -48,4 +47,4 @@ function Write-LogMessage { $Table.Entity = $TableRow Add-CIPPAzDataTableEntity @Table | Out-Null -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 index dee975be7ca1..0c1f3b3df1d3 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 @@ -3,12 +3,20 @@ function Invoke-CIPPStandardsRun { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - [string]$TenantFilter = 'allTenants' + [string]$TenantFilter = 'allTenants', + [switch]$Force ) Write-Host "Starting process for standards - $($tenantFilter)" $AllTasks = Get-CIPPStandards -TenantFilter $TenantFilter + if ($Force.IsPresent) { + Write-Host 'Clearing Rerun Cache' + foreach ($Task in $AllTasks) { + $null = Test-CIPPRerun -Type Standard -Tenant $Task.Tenant -Settings @{} -API $Task.Standard + } + } + #For each item in our object, run the queue. $Queue = New-CippQueueEntry -Name "Applying Standards ($TenantFilter)" -TotalTasks ($AllTasks | Measure-Object).Count @@ -26,4 +34,4 @@ function Invoke-CIPPStandardsRun { $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) Write-Host "Started orchestration with ID = '$InstanceId'" #$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index 5c24954b1d7e..45df45352603 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -113,7 +113,6 @@ { "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" }, { "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" }, { "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" }, - { "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" }, { "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" }, { "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" }, { "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" }, @@ -154,7 +153,8 @@ { "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" }, { "id": "19da66cb-0fb0-4390-b071-ebc76a349482", "type": "Role" }, { "id": "818c620a-27a9-40bd-a6a5-d96f7d610b4b", "type": "Scope" }, - { "id": "6931bccd-447a-43d1-b442-00a195474933", "type": "Role" } + { "id": "6931bccd-447a-43d1-b442-00a195474933", "type": "Role" }, + { "id": "c5366453-9fb0-48a5-a156-24f0c49a4b84", "type": "Scope" } ] }, { diff --git a/Modules/CIPPCore/Public/Set-CIPPAlwaysShowFrom.ps1 b/Modules/CIPPCore/Public/Set-CIPPAlwaysShowFrom.ps1 new file mode 100644 index 000000000000..56a8b2575678 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPAlwaysShowFrom.ps1 @@ -0,0 +1,89 @@ + +Function Set-CIPPAlwaysShowFrom { + <# + .SYNOPSIS + Sets the "Always Show From" property for a user or all users in a tenant. + + .DESCRIPTION + The Set-CIPPAlwaysShowFrom function is used to set the "Always Show From" property for a specified user or all users in a specified tenant. The "Always Show From" property determines whether the from field is always shown in Outlook. + + .PARAMETER UserID + Specifies the user ID for which to set the "Always Show From" property. This can be UserPrincipalName, SamAccountName, GUID or Email address. + This parameter is mandatory unless the RunOnAllUsersInTenant switch is used. + + .PARAMETER TenantFilter + Specifies the tenant for which to set the "Always Show From" property. This parameter is mandatory. + + .PARAMETER APIName + Specifies the name of the API. The default value is "Always Show From". + + .PARAMETER ExecutingUser + Specifies the user who is executing the function. + + .PARAMETER AlwaysShowFrom + Specifies whether to set the "Always Show From" property to true or false. This parameter is mandatory. + + .PARAMETER RunOnAllUsersInTenant + If this switch is present, the function will set the "Always Show From" property for all users in the specified tenant. + + .EXAMPLE + Set-CIPPAlwaysShowFrom -UserID "john.doe@example.com" -TenantFilter "example.com" -AlwaysShowFrom $true + Sets the "Always Show From" property to true for the user "john.doe@example.com" in the "example.com" tenant. + + .EXAMPLE + Set-CIPPAlwaysShowFrom -TenantFilter "example.com" -AlwaysShowFrom $true -RunOnAllUsersInTenant + Sets the "Always Show From" property to true for all users in the "example.com" tenant. + #> + [CmdletBinding(DefaultParameterSetName = 'User')] + param ( + [Parameter(Mandatory = $true, ParameterSetName = 'User')] + [Parameter(Mandatory = $false, ParameterSetName = 'AllUsers')] + [Alias('Username')][string]$UserID, + + [Parameter(Mandatory = $true, ParameterSetName = 'User')] + [Parameter(Mandatory = $true, ParameterSetName = 'AllUsers')] + $TenantFilter, + + [Parameter(ParameterSetName = 'User')] + [Parameter(ParameterSetName = 'AllUsers')] + $APIName = 'Always Show From', + + [Parameter(ParameterSetName = 'User')] + [Parameter(ParameterSetName = 'AllUsers')] + $ExecutingUser, + + [Parameter(Mandatory = $true, ParameterSetName = 'User')] + [Parameter(Mandatory = $true, ParameterSetName = 'AllUsers')] + [bool]$AlwaysShowFrom, + + [Parameter(ParameterSetName = 'AllUsers')] + [switch]$RunOnAllUsersInTenant + ) + + + if ($RunOnAllUsersInTenant.IsPresent -eq $true) { + $AllUsers = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams @{ ResultSize = 'Unlimited' } + Write-LogMessage -user $ExecutingUser -API $APIName -message "Setting Always Show From to $AlwaysShowFrom for all $($AllUsers.Count) users in $TenantFilter" -Sev 'Info' -tenant $TenantFilter + $ErrorCount = 0 + foreach ($User in $AllUsers) { + try { + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-MailboxMessageConfiguration' -anchor $User.UserPrincipalName -cmdParams @{AlwaysShowFrom = $AlwaysShowFrom; Identity = $User.UserPrincipalName } + # Write-Information "Set Always Show From to $AlwaysShowFrom for $($User.UserPrincipalName)" + } catch { + $ErrorCount++ + } + } + Write-LogMessage -user $ExecutingUser -API $APIName -message "Set Always Show From to $AlwaysShowFrom for $($AllUsers.Count - $ErrorCount) users in $TenantFilter" -Sev 'Info' -tenant $TenantFilter + return "Set Always Show From to $AlwaysShowFrom for $($AllUsers.Count - $ErrorCount) users in $TenantFilter" + } else { + try { + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-MailboxMessageConfiguration' -anchor $UserID -cmdParams @{AlwaysShowFrom = $AlwaysShowFrom; Identity = $UserID } + Write-LogMessage -user $ExecutingUser -API $APIName -message "Set Always Show From to $AlwaysShowFrom for $UserID" -Sev 'Info' -tenant $TenantFilter + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not set Always Show From to $AlwaysShowFrom for $UserID. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + return "Could not set Always Show From to $AlwaysShowFrom for $UserID. Error: $($ErrorMessage.NormalizedError)" + } + return "Set Always Show From to $AlwaysShowFrom for $UserID" + } +} diff --git a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 index c9f4cb5bbcff..9541e8f7e1d1 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 @@ -80,6 +80,6 @@ function Set-CIPPAssignedPolicy { } catch { #$ErrorMessage = Get-CippException -Exception $_ $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to assign $GroupName to Policy $PolicyId. Error:$ErrorMessage" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to assign $GroupName to Policy $PolicyId, using Platform $PlatformType and $Type. The error is:$ErrorMessage" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage } } diff --git a/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 b/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 index 1b56d3816aa9..592425f6d973 100644 --- a/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 @@ -58,26 +58,31 @@ function Set-CIPPDefaultAPDeploymentProfile { } if (!$Profiles) { if ($PSCmdlet.ShouldProcess($displayName, 'Add Autopilot profile')) { + $Type = 'Add' $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles' -body $body -tenantid $tenantfilter Write-LogMessage -user $User -API $APIName -tenant $($tenantfilter) -message "Added Autopilot profile $($displayname)" -Sev 'Info' } } else { - #patch the profile + $Type = 'Edit' $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles/$($Profiles.id)" -tenantid $tenantfilter -body $body -type PATCH - $GraphRequest = $Profiles + $GraphRequest = $Profiles | Select-Object -Last 1 } if ($AssignTo -eq $true) { $AssignBody = '{"target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}}' if ($PSCmdlet.ShouldProcess($AssignTo, "Assign Autopilot profile $displayname")) { - $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles/$($GraphRequest.id)/assignments" -tenantid $tenantfilter -type POST -body $AssignBody + #Get assignments + $Assignments = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles/$($GraphRequest.id)/assignments" -tenantid $tenantfilter + if (!$Assignments) { + $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles/$($GraphRequest.id)/assignments" -tenantid $tenantfilter -type POST -body $AssignBody + } Write-LogMessage -user $User -API $APIName -tenant $($tenantfilter) -message "Assigned autopilot profile $($Displayname) to $AssignTo" -Sev 'Info' } } - "Successfully added profile for $($tenantfilter)" + "Successfully $($Type)ed profile for $($tenantfilter)" } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -user $User -API $APIName -tenant $($tenantfilter) -message "Failed adding Autopilot Profile $($Displayname). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + Write-LogMessage -user $User -API $APIName -tenant $($tenantfilter) -message "Failed $($Type)ing Autopilot Profile $($Displayname). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage throw "Failed to add profile for $($tenantfilter): $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 index 42d9e87c5c1c..a4f93470b033 100644 --- a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 @@ -21,8 +21,8 @@ function Set-CIPPIntunePolicy { $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenantFilter if ($displayname -in $CheckExististing.displayName) { $PostType = 'edited' - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName } else { $PostType = 'added' $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON @@ -33,17 +33,17 @@ function Set-CIPPIntunePolicy { $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter $JSON = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty id, createdDateTime, lastModifiedDateTime, version, 'scheduledActionsForRule@odata.context', '@odata.context' $JSON.scheduledActionsForRule = @($JSON.scheduledActionsForRule | Select-Object * -ExcludeProperty 'scheduledActionConfigurations@odata.context') - $RawJSON = ConvertTo-Json -InputObject $JSON -Depth 20 -Compress - Write-Host $RawJSON if ($displayname -in $CheckExististing.displayName) { + $RawJSON = ConvertTo-Json -InputObject ($JSON | Select-Object * -ExcludeProperty 'scheduledActionsForRule') -Depth 20 -Compress $PostType = 'edited' - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($PolicyName) to template defaults" -Sev 'info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($DisplayName) to template defaults" -Sev 'info' + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName } else { + $RawJSON = ConvertTo-Json -InputObject $JSON -Depth 20 -Compress $PostType = 'added' $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($PolicyName) via template" -Sev 'info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } 'Admin' { @@ -52,13 +52,14 @@ function Set-CIPPIntunePolicy { $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter if ($displayname -in $CheckExististing.displayName) { $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname - $ExistingData = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/definitionValues" -tenantid $tenantFilter + $ExistingData = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($ExistingID.id)')/definitionValues" -tenantid $tenantFilter $DeleteJson = $RawJSON | ConvertFrom-Json -Depth 10 $DeleteJson.deletedIds = @($ExistingData.id) $DeleteJson.added = @() $DeleteJson = ConvertTo-Json -Depth 10 -InputObject $DeleteJson - $DeleteRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $DeleteJson - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($existingId.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $RawJSON + $DeleteRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($ExistingID.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $DeleteJson + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($ExistingID.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($Displayname) to template defaults" -Sev 'info' $PostType = 'edited' } else { @@ -76,46 +77,47 @@ function Set-CIPPIntunePolicy { $null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'displayName' -Value $displayname -Force $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 20 $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter - if ($PolicyName -in $PolicyFile.displayName) { + if ($PolicyFile.displayName -in $CheckExististing.displayName) { $PostType = 'edited' - $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON - $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $PolicyName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($PolicyName) to template defaults" -Sev 'info' + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($DisplayName) to template defaults" -Sev 'info' } else { $PostType = 'added' $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($PolicyName) via template" -Sev 'info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } 'Catalog' { $TemplateTypeURL = 'configurationPolicies' - $PolicyName = ($RawJSON | ConvertFrom-Json).Name + $DisplayName = ($RawJSON | ConvertFrom-Json).Name $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter - if ($PolicyName -in $CheckExististing.name) { - $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $PolicyName + if ($DisplayName -in $CheckExististing.name) { + $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $DisplayName $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON - $CreateRequest = $CheckExististing | Where-Object -Property Name -EQ $PolicyName + $CreateRequest = $CheckExististing | Where-Object -Property Name -EQ $DisplayName $PostType = 'edited' } else { $PostType = 'added' $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($PolicyName) via template" -Sev 'info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } 'windowsDriverUpdateProfiles' { $TemplateTypeURL = 'windowsDriverUpdateProfiles' - $PolicyName = ($RawJSON | ConvertFrom-Json).Name + $DisplayName = ($RawJSON | ConvertFrom-Json).Name $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter - if ($PolicyName -in $CheckExististing.name) { + if ($DisplayName -in $CheckExististing.name) { $PostType = 'edited' - $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $PolicyName $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName + } else { $PostType = 'added' $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($PolicyName) via template" -Sev 'info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } @@ -123,6 +125,7 @@ function Set-CIPPIntunePolicy { Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $($tenantFilter) -message "$($PostType) policy $($Displayname)" -Sev 'Info' if ($AssignTo) { Write-Host "Assigning policy to $($AssignTo) with ID $($CreateRequest.id) and type $TemplateTypeURL for tenant $tenantFilter" + Write-Host "ID is $($CreateRequest.id)" Set-CIPPAssignedPolicy -GroupName $AssignTo -PolicyId $CreateRequest.id -Type $TemplateTypeURL -TenantFilter $tenantFilter } return "Successfully $($PostType) policy for $($tenantFilter) with display name $($Displayname)" diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index 84ad06e660a2..8e1517c6f5b1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -21,6 +21,7 @@ function Invoke-CIPPStandardAntiPhishPolicy { "mdo_phisspamacation" "mdo_spam_notifications_only_for_admins" "mdo_antiphishingpolicies" + "mdo_phishthresholdlevel" ADDEDCOMPONENT {"type":"number","label":"Phishing email threshold. (Default 1)","name":"standards.AntiPhishPolicy.PhishThresholdLevel","default":1} {"type":"boolean","label":"Show first contact safety tip","name":"standards.AntiPhishPolicy.EnableFirstContactSafetyTips","default":true} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 index fc47d448d5cb..41e4616c230c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 @@ -18,7 +18,7 @@ function Invoke-CIPPStandardBranding { {"type":"input","name":"standards.Branding.signInPageText","label":"Sign-in page text"} {"type":"input","name":"standards.Branding.usernameHintText","label":"Username hint Text"} {"type":"boolean","name":"standards.Branding.hideAccountResetCredentials","label":"Hide self-service password reset"} - {"type":"Select","label":"Visual Template","name":"standards.Branding.layoutTemplateType","values":[{"label":"Full-screen background","value":"default"},{"label":"Parial-screen background","value":"verticalSplit"}]} + {"type":"Select","label":"Visual Template","name":"standards.Branding.layoutTemplateType","values":[{"label":"Full-screen background","value":"default"},{"label":"Partial-screen background","value":"verticalSplit"}]} {"type":"boolean","name":"standards.Branding.isHeaderShown","label":"Show header"} {"type":"boolean","name":"standards.Branding.isFooterShown","label":"Show footer"} IMPACT diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 index 2df323fdcd8a..54308b5f7a9f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 @@ -7,15 +7,15 @@ function Invoke-CIPPStandardDeletedUserRentention { .SYNOPSIS (Label) Set deleted user retention time in OneDrive .DESCRIPTION - (Helptext) Sets the retention period for deleted users OneDrive to the specified number of years. The default is 1 year. - (DocsDescription) When a OneDrive user gets deleted, the personal SharePoint site is saved for selected time in years and data can be retrieved from it. + (Helptext) Sets the retention period for deleted users OneDrive to the specified period of time. The default is 30 days. + (DocsDescription) When a OneDrive user gets deleted, the personal SharePoint site is saved for selected amount of time that data can be retrieved from it. .NOTES CAT SharePoint Standards TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","name":"standards.DeletedUserRentention.Days","label":"Retention in years (Default 1)","values":[{"label":"1 year","value":"365"},{"label":"2 years","value":"730"},{"label":"3 years","value":"1095"},{"label":"4 years","value":"1460"},{"label":"5 years","value":"1825"},{"label":"6 years","value":"2190"},{"label":"7 years","value":"2555"},{"label":"8 years","value":"2920"},{"label":"9 years","value":"3285"},{"label":"10 years","value":"3650"}]} + {"type":"Select","name":"standards.DeletedUserRentention.Days","label":"Retention time (Default 30 days)","values":[{"label":"30 days","value":"30"},{"label":"90 days","value":"90"},{"label":"1 year","value":"365"},{"label":"2 years","value":"730"},{"label":"3 years","value":"1095"},{"label":"4 years","value":"1460"},{"label":"5 years","value":"1825"},{"label":"6 years","value":"2190"},{"label":"7 years","value":"2555"},{"label":"8 years","value":"2920"},{"label":"9 years","value":"3285"},{"label":"10 years","value":"3650"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -50,7 +50,6 @@ function Invoke-CIPPStandardDeletedUserRentention { } $StateSetCorrectly = if ($CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays -eq $WantedState) { $true } else { $false } - $RetentionInYears = $WantedState / 365 If ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' @@ -63,21 +62,21 @@ function Invoke-CIPPStandardDeletedUserRentention { $body = ConvertTo-Json -InputObject $body -Depth 5 -Compress New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type PATCH -Body $body -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set deleted user rentention of OneDrive to $RetentionInYears year(s)" -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Set deleted user rentention of OneDrive to $WantedState days(s)" -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set deleted user rentention of OneDrive to $RetentionInYears year(s). Error: $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set deleted user rentention of OneDrive to $WantedState days(s). Error: $ErrorMessage" -sev Error } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is already set to $RetentionInYears year(s)" -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is already set to $WantedState days(s)" -sev Info } } if ($Settings.alert -eq $true) { if ($StateSetCorrectly -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is set to $RetentionInYears year(s)" -sev Info + Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is set to $WantedState days(s)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is not set to $RetentionInYears year(s). Value is: $($CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays) " -sev Alert + Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is not set to $WantedState days(s). Value is: $($CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays) day(s)." -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 index aaa236c0a68d..dda4ba27b51b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 @@ -15,6 +15,7 @@ function Invoke-CIPPStandardDisableSharePointLegacyAuth { TAG "mediumimpact" "CIS" + "spo_legacy_auth" ADDEDCOMPONENT IMPACT Medium Impact diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 index 5ed7f3d68401..bbfb458bab6f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 @@ -34,7 +34,7 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'EXODisableAutoForwarding' $CurrentInfo = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedOutboundSpamFilterPolicy' -cmdparams @{Identity = 'Default' } -useSystemMailbox $true - $StateIsCorrect = $CurrentInfo.AutoForwardingMode -eq 'Off' -or $CurrentInfo.AutoForwardingMode -eq 'Automatic' + $StateIsCorrect = $CurrentInfo.AutoForwardingMode -eq 'Off' If ($Settings.remediate -eq $true) { Write-Host 'Time to remediate!' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index 6e904b80c722..7eddbd5eecfc 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -20,10 +20,11 @@ function Invoke-CIPPStandardIntuneTemplate { $displayname = $request.body.Displayname $description = $request.body.Description $RawJSON = $Request.body.RawJSON + $TemplateTypeURL = $Request.body.Type - Set-CIPPIntunePolicy -TemplateType $Request.body.Type -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $null -tenantFilter $Tenant + Set-CIPPIntunePolicy -TemplateType $Request.body.Type -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $Template.AssignedTo -tenantFilter $Tenant - #Legacy assign. + #Legacy assign, only required for older templates. if ($Settings.AssignTo) { Write-Host "Assigning Policy to $($Settings.AssignTo) the create ID is $($CreateRequest)" if ($Settings.AssignTo -eq 'customGroup') { $Settings.AssignTo = $Settings.customGroup } @@ -36,16 +37,6 @@ function Invoke-CIPPStandardIntuneTemplate { } } - if ($Template.AssignedTo) { - Write-Host "New: Assigning Policy to $($Template.AssignedTo) the create ID is $($CreateRequest)" - if ($ExistingID) { - Set-CIPPAssignedPolicy -PolicyId $ExistingID.id -TenantFilter $tenant -GroupName $Template.AssignedTo -Type $TemplateTypeURL - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully updated Intune Template $PolicyName policy for $($Tenant)" -sev 'Info' - } else { - Set-CIPPAssignedPolicy -PolicyId $CreateRequest.id -TenantFilter $tenant -GroupName $Template.AssignedTo -Type $TemplateTypeURL - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully created Intune Template $PolicyName policy for $($Tenant)" -sev 'Info' - } - } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template $PolicyName, Error: $ErrorMessage" -sev 'Error' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index 38cd1c123153..f9cd47acee18 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -20,6 +20,7 @@ function Invoke-CIPPStandardMalwareFilterPolicy { "mdo_zapmalware" ADDEDCOMPONENT {"type":"Select","label":"FileTypeAction","name":"standards.MalwareFilterPolicy.FileTypeAction","values":[{"label":"Reject","value":"Reject"},{"label":"Quarantine the message","value":"Quarantine"}]} + {"type":"input","name":"standards.MalwareFilterPolicy.OptionalFileTypes","label":"Optional File Types, Comma separated"} {"type":"Select","label":"QuarantineTag","name":"standards.MalwareFilterPolicy.QuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} {"type":"boolean","label":"Enable Internal Sender Admin Notifications","name":"standards.MalwareFilterPolicy.EnableInternalSenderAdminNotifications"} {"type":"input","name":"standards.MalwareFilterPolicy.InternalSenderAdminAddress","label":"Internal Sender Admin Address"} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index 86f215bfa54f..35eb01b0cbf5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -59,6 +59,7 @@ function Invoke-CIPPStandardNudgeMFA { $Body = $CurrentInfo $body.registrationEnforcement.authenticationMethodsRegistrationCampaign.state = $Settings.state $body.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays = $Settings.snoozeDurationInDays + $body.registrationEnforcement.authenticationMethodsRegistrationCampaign.enforceRegistrationAfterAllowedSnoozes = $true $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' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 index afb62bb5ab61..d336e2d7528b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 @@ -14,6 +14,7 @@ function Invoke-CIPPStandardOauthConsentLowSec { Entra (AAD) Standards TAG "mediumimpact" + "IntegratedApps" IMPACT Medium Impact POWERSHELLEQUIVALENT diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 index 571801fe31be..e07f2e3c4dcf 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardPhishProtection { } $CSS = @" .ext-sign-in-box { - background-image: url($($Settings.URL)/api/PublicPhishingCheck?Tenantid=$($tenant)); + background-image: url(https://clone.cipp.app/api/PublicPhishingCheck?Tenantid=$($tenant)&URL=$($Settings.URL)); } "@ If ($Settings.remediate -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 index 493405ec4777..ded1d34833c5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardSPEmailAttestation { if ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Sharepoint reauthentication with verification code is already restriction.' -Sev Info + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Sharepoint reauthentication with verification code is already restricted.' -Sev Info } else { $Properties = @{ EmailAttestationReAuthDays = $Settings.Days @@ -59,9 +59,9 @@ function Invoke-CIPPStandardSPEmailAttestation { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is restriction' -Sev Info + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is restricted.' -Sev Info } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is not restricted' -Sev Alert + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is not restricted.' -Sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index a9cb8967c28c..c2b983accdb4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -15,16 +15,16 @@ function Invoke-CIPPStandardSpamFilterPolicy { TAG "mediumimpact" ADDEDCOMPONENT - { "type": "number", "label": "Bulk email threshold (Default 7)", "name": "standards.SpamFilterPolicy.BulkThreshold", "default": 7 } - { "type": "Select", "label": "Spam Action", "name": "standards.SpamFilterPolicy.SpamAction", "values": [ { "label": "Move message to Junk Email folder", "value": "MoveToJmf" }, { "label": "Quarantine the message", "value": "Quarantine" } ] } - { "type": "Select", "label": "Spam Quarantine Tag", "name": "standards.SpamFilterPolicy.SpamQuarantineTag", "values": [ { "label": "AdminOnlyAccessPolicy", "value": "AdminOnlyAccessPolicy" }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" }, { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" } ] } - { "type": "Select", "label": "High Confidence Spam Action", "name": "standards.SpamFilterPolicy.HighConfidenceSpamAction", "values": [ { "label": "Quarantine the message", "value": "Quarantine" }, { "label": "Move message to Junk Email folder", "value": "MoveToJmf" } ] } - { "type": "Select", "label": "High Confidence Spam Quarantine Tag", "name": "standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag", "values": [ { "label": "AdminOnlyAccessPolicy", "value": "AdminOnlyAccessPolicy" }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" }, { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" } ] } - { "type": "Select", "label": "Bulk Spam Action", "name": "standards.SpamFilterPolicy.BulkSpamAction", "values": [ { "label": "Move message to Junk Email folder", "value": "MoveToJmf" }, { "label": "Quarantine the message", "value": "Quarantine" } ] } - { "type": "Select", "label": "Bulk Quarantine Tag", "name": "standards.SpamFilterPolicy.BulkQuarantineTag", "values": [ { "label": "AdminOnlyAccessPolicy", "value": "AdminOnlyAccessPolicy" }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" }, { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" } ] } - { "type": "Select", "label": "Phish Spam Action", "name": "standards.SpamFilterPolicy.PhishSpamAction", "values": [ { "label": "Quarantine the message", "value": "Quarantine" }, { "label": "Move message to Junk Email folder", "value": "MoveToJmf" } ] } - { "type": "Select", "label": "Phish Quarantine Tag", "name": "standards.SpamFilterPolicy.PhishQuarantineTag", "values": [ { "label": "AdminOnlyAccessPolicy", "value": "AdminOnlyAccessPolicy" }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" }, { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" } ] } - { "type": "Select", "label": "High Confidence Phish Quarantine Tag", "name": "standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag", "values": [ { "label": "AdminOnlyAccessPolicy", "value": "AdminOnlyAccessPolicy" }, { "label": "DefaultFullAccessPolicy", "value": "DefaultFullAccessPolicy" }, { "label": "DefaultFullAccessWithNotificationPolicy", "value": "DefaultFullAccessWithNotificationPolicy" } ] } + {"type":"number","label":"Bulk email threshold (Default 7)","name":"standards.SpamFilterPolicy.BulkThreshold","default":7} + {"type":"Select","label":"Spam Action","name":"standards.SpamFilterPolicy.SpamAction","values":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"Select","label":"Spam Quarantine Tag","name":"standards.SpamFilterPolicy.SpamQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"Select","label":"High Confidence Spam Action","name":"standards.SpamFilterPolicy.HighConfidenceSpamAction","values":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"Select","label":"High Confidence Spam Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"Select","label":"Bulk Spam Action","name":"standards.SpamFilterPolicy.BulkSpamAction","values":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"Select","label":"Bulk Quarantine Tag","name":"standards.SpamFilterPolicy.BulkQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"Select","label":"Phish Spam Action","name":"standards.SpamFilterPolicy.PhishSpamAction","values":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"Select","label":"Phish Quarantine Tag","name":"standards.SpamFilterPolicy.PhishQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"Select","label":"High Confidence Phish Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} IMPACT Medium Impact POWERSHELLEQUIVALENT diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 index 67ba8d5f0e1e..dc21121c0e3f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 @@ -15,15 +15,15 @@ Function Invoke-CIPPStandardTeamsExternalFileSharing { TAG "lowimpact" ADDEDCOMPONENT - {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowGoogleDrive","label":"Allow Google Drive","default":false} - {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowShareFile","label":"Allow ShareFile","default":false} - {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowBox","label":"Allow Box","default":false} - {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowDropbox","label":"Allow Dropbox","default":false} - {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowEgnyte","label":"Allow Egnyte","default":false} + {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowGoogleDrive","label":"Allow Google Drive"} + {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowShareFile","label":"Allow ShareFile"} + {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowBox","label":"Allow Box"} + {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowDropBox","label":"Allow Dropbox"} + {"type":"boolean","name":"standards.TeamsExternalFileSharing.AllowEgnyte","label":"Allow Egnyte"} IMPACT Low Impact POWERSHELLEQUIVALENT - Set-CsTeamsClientConfiguration -AllowGoogleDrive \$false -AllowShareFile \$false -AllowBox \$false -AllowDroBbox \$false -AllowEgnyte \$false + Set-CsTeamsClientConfiguration -AllowGoogleDrive \$false -AllowShareFile \$false -AllowBox \$false -AllowDropBox \$false -AllowEgnyte \$false RECOMMENDEDBY "CIS 3.0" UPDATECOMMENTBLOCK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 index 186892ee96ad..9ea89a31897b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardsharingDomainRestriction { "highimpact" "CIS" ADDEDCOMPONENT - {"type":"Select","name":"standards.sharingDomainRestriction.Mode","label":"Limit external sharing by domains","values":[{"label":"Off","value":"none"},{"label":"Restirct sharing to specific domains","value":"allowList"},{"label":"Block sharing to specific domains","value":"blockList"}]} + {"type":"Select","name":"standards.sharingDomainRestriction.Mode","label":"Limit external sharing by domains","values":[{"label":"Off","value":"none"},{"label":"Restrict sharing to specific domains","value":"allowList"},{"label":"Block sharing to specific domains","value":"blockList"}]} {"type":"input","name":"standards.sharingDomainRestriction.Domains","label":"Domains to allow/block, comma separated"} IMPACT High Impact diff --git a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 index 743ed7bd79a6..5723734a14d2 100644 --- a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 @@ -7,87 +7,117 @@ function Invoke-HuduExtensionSync { $Configuration, $TenantFilter ) - Connect-HuduAPI -configuration $Configuration - - # Get mapping configuration - $MappingTable = Get-CIPPTable -TableName 'CippMapping' - $Mappings = Get-CIPPAzDataTableEntity @MappingTable -Filter "PartitionKey eq 'HuduMapping' or PartitionKey eq 'HuduFieldMapping'" - #Write-Host ($Mappings | ConvertTo-Json) - $defaultdomain = $TenantFilter - $Tenant = Get-Tenants -IncludeErrors | Where-Object { $_.defaultDomainName -eq $TenantFilter } - $TenantMap = $Mappings | Where-Object { $_.RowKey -eq $Tenant.customerId } + try { + Connect-HuduAPI -configuration $Configuration + + $CompanyResult = [PSCustomObject]@{ + Name = $Tenant.displayName + Users = 0 + Devices = 0 + Errors = [System.Collections.Generic.List[string]]@() + Logs = [System.Collections.Generic.List[string]]@() + } - $HuduAssetCache = Get-CippTable -tablename 'CacheHuduAssets' + # Get mapping configuration + $MappingTable = Get-CIPPTable -TableName 'CippMapping' + $Mappings = Get-CIPPAzDataTableEntity @MappingTable -Filter "PartitionKey eq 'HuduMapping' or PartitionKey eq 'HuduFieldMapping'" - if (!$TenantMap) { - return 'Tenant not found in mapping table' - } + $defaultdomain = $TenantFilter + $Tenant = Get-Tenants -IncludeErrors | Where-Object { $_.defaultDomainName -eq $TenantFilter } + $TenantMap = $Mappings | Where-Object { $_.RowKey -eq $Tenant.customerId } - $CompanyResult = [PSCustomObject]@{ - Name = $Tenant.displayName - Users = 0 - Devices = 0 - Errors = [System.Collections.Generic.List[string]]@() - Logs = [System.Collections.Generic.List[string]]@() - } + # Get Asset cache + $HuduAssetCache = Get-CippTable -tablename 'CacheHuduAssets' - $PeopleLayoutId = $Mappings | Where-Object { $_.RowKey -eq 'Users' } | Select-Object -ExpandProperty IntegrationId - $CreateUsers = $Configuration.CreateMissingUsers - $DeviceLayoutId = $Mappings | Where-Object { $_.RowKey -eq 'Devices' } | Select-Object -ExpandProperty IntegrationId - $CreateDevices = $Configuration.CreateMissingDevices + # Import license mapping + Set-Location (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName + $LicTable = Import-Csv Conversiontable.csv - if ($PeopleLayoutId) { - $null = Add-HuduAssetLayoutM365Field -AssetLayoutId $PeopleLayoutId - } - if ($DeviceLayoutId) { - $null = Add-HuduAssetLayoutM365Field -AssetLayoutId $DeviceLayoutId - } + $CompanyResult.Logs.Add('Starting Hudu Extension Sync') - $importDomains = $Configuration.ImportDomains - $monitordomains = $Configuration.MonitorDomains - $IntuneDesktopDeviceTypes = 'windowsRT,macMDM' -split ',' + # Get CIPP URL + $ConfigTable = Get-Cipptable -tablename 'Config' + $Config = Get-CippAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'InstanceProperties' and RowKey eq 'CIPPURL'" + $CIPPURL = 'https://{0}' -f $Config.Value + $EnableCIPP = $true - $DefaultSerials = [System.Collections.Generic.List[string]]@('SystemSerialNumber', 'To Be Filled By O.E.M.', 'System Serial Number', '0123456789', '123456789', 'TobefilledbyO.E.M.') + # Get Hudu Extension Cache + $ExtensionCache = Get-ExtensionCacheData -TenantFilter $Tenant.defaultDomainName + $company_id = $TenantMap.IntegrationId - if ($Configuration.ExcludeSerials) { - $ExcludeSerials = $DefaultSerials.AddRange($Configuration.ExcludeSerials -split ',') - } else { - $ExcludeSerials = $DefaultSerials - } + # If tenant not found in mapping table, return error + if (!$TenantMap) { + return 'Tenant not found in mapping table' + } - Set-Location (Get-Item $PSScriptRoot).Parent.Parent.Parent.Parent.FullName - $LicTable = Import-Csv Conversiontable.csv + # Get Hudu Layout mappings + $PeopleLayoutId = $Mappings | Where-Object { $_.RowKey -eq 'Users' } | Select-Object -ExpandProperty IntegrationId + $DeviceLayoutId = $Mappings | Where-Object { $_.RowKey -eq 'Devices' } | Select-Object -ExpandProperty IntegrationId - $CompanyResult.Logs.Add('Starting Hudu Extension Sync') + try { + if (![string]::IsNullOrEmpty($PeopleLayoutId)) { + $null = Add-HuduAssetLayoutM365Field -AssetLayoutId $PeopleLayoutId + $CreateUsers = $Configuration.CreateMissingUsers + $PeopleLayout = Get-HuduAssetLayouts -Id $PeopleLayoutId + if ($PeopleLayout.id) { + $People = Get-HuduAssets -CompanyId $company_id -AssetLayoutId $PeopleLayout.id + } else { + $CreateUsers = $false + $People = @() + } + } else { + $CreateUsers = $false + $People = @() + } + } catch { + $CreateUsers = $false + $People = @() + $CompanyResult.Errors.add("Company: Unable to fetch People $_") + Write-Host "Hudu People - Error: $_" + } - #$AssignedMap = Get-AssignedMap - #$AssignedNameMap = Get-AssignedNameMap + Write-Host "CreateUsers: $CreateUsers" - $EnableCIPP = $true - $ConfigTable = Get-Cipptable -tablename 'Config' - $Config = Get-CippAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'InstanceProperties' and RowKey eq 'CIPPURL'" - $CIPPURL = 'https://{0}' -f $Config.Value + try { + if (![string]::IsNullOrEmpty($DeviceLayoutId)) { + $null = Add-HuduAssetLayoutM365Field -AssetLayoutId $DeviceLayoutId + $CreateDevices = $Configuration.CreateMissingDevices + $DesktopsLayout = Get-HuduAssetLayouts -Id $DeviceLayoutId + if ($DesktopsLayout.id) { + $HuduDesktopDevices = Get-HuduAssets -CompanyId $company_id -AssetLayoutId $DesktopsLayout.id + $HuduDevices = $HuduDesktopDevices + } else { + $CreateDevices = $false + $HuduDevices = @() + } + } else { + $CreateDevices = $false + $HuduDevices = @() + } + } catch { + $CreateDevices = $false + $HuduDevices = @() + $CompanyResult.Errors.add("Company: Unable to fetch Devices $_") + Write-Host "Hudu Devices - Error: $_" + } - $ExtensionCache = Get-ExtensionCacheData -TenantFilter $Tenant.defaultDomainName + Write-Host "CreateDevices: $CreateDevices" - try { - $company_id = $TenantMap.IntegrationId + $importDomains = $Configuration.ImportDomains + $monitordomains = $Configuration.MonitorDomains - if ($PeopleLayoutId) { - $PeopleLayout = Get-HuduAssetLayouts -Id $PeopleLayoutId - $People = Get-HuduAssets -CompanyId $company_id -AssetLayoutId $PeopleLayout.id - } + # Defaults + $IntuneDesktopDeviceTypes = 'windowsRT,macMDM' -split ',' + $DefaultSerials = [System.Collections.Generic.List[string]]@('SystemSerialNumber', 'To Be Filled By O.E.M.', 'System Serial Number', '0123456789', '123456789', 'TobefilledbyO.E.M.') - if ($DeviceLayoutId) { - $DesktopsLayout = Get-HuduAssetLayouts -Id $DeviceLayoutId - $HuduDesktopDevices = Get-HuduAssets -CompanyId $company_id -AssetLayoutId $DesktopsLayout.id + if ($Configuration.ExcludeSerials) { + $ExcludeSerials = $DefaultSerials.AddRange($Configuration.ExcludeSerials -split ',') + } else { + $ExcludeSerials = $DefaultSerials } $HuduRelations = Get-HuduRelations - - $HuduDevices = $HuduDesktopDevices - $Links = @( @{ Title = 'M365 Admin Portal' @@ -605,7 +635,7 @@ function Invoke-HuduExtensionSync { if ($EnableCIPP) { $CIPPLinksFormatted.add((Get-HuduLinkBlock -URL "$($CIPPURL)/identity/administration/users/view?customerId=$($Tenant.customerid)&userId=$($User.id)&tenantDomain=$($Tenant.defaultDomainName)&userEmail=$($User.userPrincipalName)" -Icon 'far fa-eye' -Title 'CIPP - View User')) $CIPPLinksFormatted.add((Get-HuduLinkBlock -URL "$($CIPPURL)/identity/administration/users/edit?customerId=$($Tenant.customerid)&userId=$($User.id)&tenantDomain=$($Tenant.defaultDomainName)&userEmail=$($User.userPrincipalName)" -Icon 'fas fa-user-cog' -Title 'CIPP - Edit User')) - $CIPPLinksFormatted.add((Get-HuduLinkBlock -URL "$($CIPPURL)/identity/administration/ViewBec?customerId=$($Tenant.customerid)&userId=$($User.id)&tenantDomain=$($Tenant.defaultDomainName)&userEmail=$($User.userPrincipalName)" -Icon 'fas fa-user-secret' -Title 'CIPP - BEC Tool')) + $CIPPLinksFormatted.add((Get-HuduLinkBlock -URL "$($CIPPURL)/identity/administration/ViewBec?customerId=$($Tenant.customerid)&userId=$($User.id)&tenantDomain=$($Tenant.defaultDomainName)&ID=$($User.userPrincipalName)" -Icon 'fas fa-user-secret' -Title 'CIPP - BEC Tool')) } [System.Collections.Generic.List[PSCustomObject]]$UserLinksFormatted = @() @@ -626,7 +656,7 @@ function Invoke-HuduExtensionSync { $UserBody = "
$AssignedPlansBlock
$UserLinksBlock
$($UserOverviewBlock)$($UserMailDetailsBlock)$($OneDriveBlock)$($UserMailSettingsBlock)$($UserPoliciesBlock)
$($UserDevicesDetailsBlock)
$($UserGroupsBlock)
" - if ($PeopleLayoutId) { + if (![string]::IsNullOrEmpty($PeopleLayoutId)) { $UserAssetFields = @{ microsoft_365 = $UserBody email_address = $user.userPrincipalName @@ -772,6 +802,9 @@ function Invoke-HuduExtensionSync { $HuduDevice = $HuduDevices | Where-Object { $_.name -eq $device.deviceName -or ($_.cards.integrator_name -eq 'cw_manage' -and $_.cards.data.name -contains $device.deviceName) } } else { $HuduDevice = $HuduDevices | Where-Object { $_.primary_serial -eq $device.serialNumber -or ($_.cards.integrator_name -eq 'cw_manage' -and $_.cards.data.serialNumber -eq $device.serialNumber) } + if (!$HuduDevice) { + $HuduDevice = $HuduDevices | Where-Object { $_.name -eq $device.deviceName -or ($_.cards.integrator_name -eq 'cw_manage' -and $_.cards.data.name -contains $device.deviceName) } + } } [System.Collections.Generic.List[PSCustomObject]]$DeviceLinksFormatted = @() @@ -799,7 +832,7 @@ function Invoke-HuduExtensionSync { } $NewHash = Get-StringHash -String $DeviceIntuneDetailshtml - if ($DeviceLayoutId) { + if (![string]::IsNullOrEmpty($DeviceLayoutId)) { if ($HuduDevice) { if (($HuduDevice | Measure-Object).count -eq 1) { $ExistingAsset = Get-CIPPAzDataTableEntity @HuduAssetCache -Filter "PartitionKey eq 'HuduDevice' and CompanyId eq '$company_id' and RowKey eq '$($HuduDevice.id)'" diff --git a/Scheduler_GetQueue/run.ps1 b/Scheduler_GetQueue/run.ps1 index 87d355d1476c..f359db7de9c4 100644 --- a/Scheduler_GetQueue/run.ps1 +++ b/Scheduler_GetQueue/run.ps1 @@ -27,6 +27,10 @@ $Tasks = foreach ($Tenant in $Tenants) { } } +if (($Tasks | Measure-Object).Count -eq 0) { + return +} + $Queue = New-CippQueueEntry -Name 'Scheduler' -TotalTasks ($Tasks | Measure-Object).Count $Batch = foreach ($Task in $Tasks) { @@ -49,4 +53,4 @@ $InputObject = [PSCustomObject]@{ #Write-Information ($InputObject | ConvertTo-Json) $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) Write-Information "Started orchestration with ID = '$InstanceId'" -#$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId \ No newline at end of file +#$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId diff --git a/Scheduler_PollAuditLogs/run.ps1 b/Scheduler_PollAuditLogs/run.ps1 index 4913f8570d52..3c7e8668355c 100644 --- a/Scheduler_PollAuditLogs/run.ps1 +++ b/Scheduler_PollAuditLogs/run.ps1 @@ -1,6 +1,14 @@ param($Timer) try { + $ConfigTable = Get-CIPPTable -tablename Config + $Config = Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'OffloadFunctions' and RowKey eq 'OffloadFunctions'" + + if ($Config -and $Config.state -eq $true) { + Write-Host 'Offload functions are enabled. Exiting.' + return 0 + } + $webhookTable = Get-CIPPTable -tablename webhookTable $Webhooks = Get-CIPPAzDataTableEntity @webhookTable -Filter "Version eq '3'" | Where-Object { $_.Resource -match '^Audit' -and $_.Status -ne 'Disabled' } if (($Webhooks | Measure-Object).Count -eq 0) { diff --git a/version_latest.txt b/version_latest.txt index 024b066c0bb7..798e38995c4d 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.2.1 +6.3.0