diff --git a/.github/workflows/PR_Branch_Check.yml b/.github/workflows/PR_Branch_Check.yml new file mode 100644 index 000000000000..2fd5b8e65249 --- /dev/null +++ b/.github/workflows/PR_Branch_Check.yml @@ -0,0 +1,62 @@ +name: PR Branch Check + +on: + # Using pull_request_target instead of pull_request for secure handling of fork PRs + pull_request_target: + # Only run on these PR events + types: [opened, synchronize, reopened] + # Only check PRs targeting these branches + branches: + - main + - master + +permissions: + pull-requests: write + issues: write + +jobs: + check-branch: + runs-on: ubuntu-latest + steps: + - name: Check and Comment on PR + # Only process fork PRs with specific branch conditions + # Must be a fork AND (source is main/master OR target is main/master) + if: | + github.event.pull_request.head.repo.fork == true && + ((github.event.pull_request.head.ref == 'main' || github.event.pull_request.head.ref == 'master') || + (github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master')) + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + let message = ''; + + message += '🔄 If you are attempting to update your CIPP repo please follow the instructions at: https://docs.cipp.app/setup/self-hosting-guide/updating '; + message += '\n\n'; + + // Check if PR is targeting main/master + if (context.payload.pull_request.base.ref === 'main' || context.payload.pull_request.base.ref === 'master') { + message += '⚠️ PRs cannot target the main branch directly. If you are attempting to contribute code please PR to the dev branch.\n\n'; + } + + // Check if PR is from a fork's main/master branch + if (context.payload.pull_request.head.repo.fork && + (context.payload.pull_request.head.ref === 'main' || context.payload.pull_request.head.ref === 'master')) { + message += '⚠️ This PR cannot be merged because it originates from your fork\'s main/master branch. If you are attempting to contribute code please PR from your dev branch or another non-main/master branch.\n\n'; + } + + message += '🔒 This PR will now be automatically closed due to the above violation(s).'; + + // Post the comment + await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + body: message + }); + + // Close the PR + await github.rest.pulls.update({ + ...context.repo, + pull_number: context.issue.number, + state: 'closed' + }); diff --git a/.github/workflows/dev_cipp4i6t3.yml b/.github/workflows/dev_cippbcaom.yml similarity index 87% rename from .github/workflows/dev_cipp4i6t3.yml rename to .github/workflows/dev_cippbcaom.yml index 88825a14b52c..c4bcf1198e74 100644 --- a/.github/workflows/dev_cipp4i6t3.yml +++ b/.github/workflows/dev_cippbcaom.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 - cipp4i6t3 +name: Build and deploy Powershell project to Azure Function App - cippbcaom on: push: @@ -24,7 +24,7 @@ jobs: uses: Azure/functions-action@v1 id: fa with: - app-name: 'cipp4i6t3' + app-name: 'cippbcaom' slot-name: 'Production' package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_9D257A31ACA24925A112AF5FFC2BEAFE }} \ No newline at end of file + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_0FE8CACBBF7D409DAAF132988BECEC4B }} \ No newline at end of file diff --git a/.github/workflows/dev_cippkkxvm.yml b/.github/workflows/dev_cippjta72.yml similarity index 87% rename from .github/workflows/dev_cippkkxvm.yml rename to .github/workflows/dev_cippjta72.yml index 665a3bcf8afa..23c0cd3668d6 100644 --- a/.github/workflows/dev_cippkkxvm.yml +++ b/.github/workflows/dev_cippjta72.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 - cippkkxvm +name: Build and deploy Powershell project to Azure Function App - cippjta72 on: push: @@ -24,7 +24,7 @@ jobs: uses: Azure/functions-action@v1 id: fa with: - app-name: 'cippkkxvm' + app-name: 'cippjta72' slot-name: 'Production' package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_171C3E2B1E2346AAA333905DFCA62F2D }} \ No newline at end of file + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_5B44448119C645C099EE192346D7433A }} \ No newline at end of file diff --git a/.github/workflows/dev_cippkwn4s-auditlog.yml b/.github/workflows/dev_cippkwn4s-auditlog.yml deleted file mode 100644 index b27c1832c8c6..000000000000 --- a/.github/workflows/dev_cippkwn4s-auditlog.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 - cippkwn4s-auditlog - -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: 'cippkwn4s-auditlog' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_4CBFBE8BE62240D789C371767B49278E }} \ No newline at end of file diff --git a/.github/workflows/dev_cippkwn4s.yml b/.github/workflows/dev_cippkwn4s.yml deleted file mode 100644 index f45e9d0712fd..000000000000 --- a/.github/workflows/dev_cippkwn4s.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action -# More GitHub Actions for Azure: https://github.com/Azure/actions - -name: Build and deploy Powershell project to Azure Function App - cippkwn4s - -on: - push: - branches: - - dev - workflow_dispatch: - -env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root - -jobs: - deploy: - runs-on: windows-latest - permissions: - id-token: write #This is required for requesting the JWT - - steps: - - name: 'Checkout GitHub Action' - uses: actions/checkout@v4 - - - name: Login to Azure - uses: azure/login@v2 - with: - 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: 'cippkwn4s' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - \ No newline at end of file diff --git a/.github/workflows/dev_cipplwwww-proc.yml b/.github/workflows/dev_cipplwwww-proc.yml deleted file mode 100644 index d5f9c210f7e0..000000000000 --- a/.github/workflows/dev_cipplwwww-proc.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 - cipplwwww-proc - -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: 'cipplwwww-proc' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B8CE64E970E74E6AB2D6655823D95B1A }} \ No newline at end of file diff --git a/.github/workflows/dev_cipplwwww.yml b/.github/workflows/dev_cipppwrro.yml similarity index 87% rename from .github/workflows/dev_cipplwwww.yml rename to .github/workflows/dev_cipppwrro.yml index 7fe7c6279bb1..a62bd3026748 100644 --- a/.github/workflows/dev_cipplwwww.yml +++ b/.github/workflows/dev_cipppwrro.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 - cipplwwww +name: Build and deploy Powershell project to Azure Function App - cipppwrro on: push: @@ -24,7 +24,7 @@ jobs: uses: Azure/functions-action@v1 id: fa with: - app-name: 'cipplwwww' + app-name: 'cipppwrro' slot-name: 'Production' package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_00A9A6DFE9244C2EA8952190FFF10F45 }} \ No newline at end of file + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_D5D7DFF930C04B519206F25DDCD88324 }} \ No newline at end of file diff --git a/.github/workflows/publish_prerelease.yml b/.github/workflows/publish_prerelease.yml new file mode 100644 index 000000000000..f97a41057070 --- /dev/null +++ b/.github/workflows/publish_prerelease.yml @@ -0,0 +1,93 @@ +name: Generate Release Notes and Upload + +on: + push: + branches: + - pre-release + +permissions: + contents: write + +jobs: + release: + if: github.event.repository.fork == false && github.event_name == 'push' + name: Generate Release Notes and Upload to Azure + runs-on: ubuntu-latest + + steps: + # Checkout the repository + - name: Checkout Code + uses: actions/checkout@v3 + + # Read and Trim Version + - name: Read and Trim Version + id: get_version + run: | + if [ ! -f version_latest.txt ]; then + echo "Error: version_latest.txt not found!" + exit 1 + fi + VERSION=$(cat version_latest.txt | tr -d '[:space:]') + if [ -z "$VERSION" ]; then + echo "Error: version_latest.txt is empty after trimming!" + exit 1 + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Exit if Tag Already Exists + - name: Check if Tag Exists + id: tag_check + run: | + git fetch --tags + if git rev-parse "refs/tags/${{ steps.get_version.outputs.version }}" >/dev/null 2>&1; then + echo "tag_exists=true" >> $GITHUB_ENV + echo "Tag ${{ steps.get_version.outputs.version }} already exists. Exiting workflow successfully." + else + echo "tag_exists=false" >> $GITHUB_ENV + fi + + # Generate Release Notes + - name: Generate Release Notes + id: changelog + if: env.tag_exists == 'false' + uses: mikepenz/release-changelog-builder-action@v5.0.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Create a new release tag + - name: Create GitHub Release + if: env.tag_exists == 'false' + uses: ncipollo/release-action@v1.14.0 + with: + tag: ${{ steps.get_version.outputs.version }} + name: "v${{ steps.get_version.outputs.version }}" + draft: false + prerelease: true + body: ${{ steps.changelog.outputs.changelog }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Create ZIP File in a New Source Directory + - name: Prepare and Zip Release Files + if: env.tag_exists == 'false' + run: | + mkdir -p src/releases + zip -r src/releases/release_${{ steps.get_version.outputs.version }}.zip . \ + --exclude "./src/releases/*" \ + --exclude ".*" \ + --exclude ".*/**" + zip -r src/releases/beta.zip . \ + --exclude "./src/releases/*" \ + --exclude ".*" \ + --exclude ".*/**" + + # Upload to Azure Blob Storage + - name: Azure Blob Upload with Destination folder defined + if: env.tag_exists == 'false' + uses: LanceMcCarthy/Action-AzureBlobUpload@v3.3.0 + with: + connection_string: ${{ secrets.AZURE_CONNECTION_STRING }} + container_name: cipp-api + source_folder: src/releases/ + destination_folder: / + delete_if_exists: true \ No newline at end of file diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml new file mode 100644 index 000000000000..b1a2146b9fad --- /dev/null +++ b/.github/workflows/publish_release.yml @@ -0,0 +1,94 @@ +name: Generate Release Notes and Upload Production to Azure + +on: + push: + branches: + - master + +permissions: + contents: write + +jobs: + release: + if: github.event.repository.fork == false && github.event_name == 'push' + name: Generate Release Notes and Upload to Azure + runs-on: ubuntu-latest + + steps: + # Checkout the repository + - name: Checkout Code + uses: actions/checkout@v3 + + # Read and Trim Version + - name: Read and Trim Version + id: get_version + run: | + if [ ! -f version_latest.txt ]; then + echo "Error: version_latest.txt not found!" + exit 1 + fi + VERSION=$(cat version_latest.txt | tr -d '[:space:]') + if [ -z "$VERSION" ]; then + echo "Error: version_latest.txt is empty after trimming!" + exit 1 + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Exit if Tag Already Exists + - name: Check if Tag Exists + id: tag_check + run: | + git fetch --tags + if git rev-parse "refs/tags/${{ steps.get_version.outputs.version }}" >/dev/null 2>&1; then + echo "tag_exists=true" >> $GITHUB_ENV + echo "Tag ${{ steps.get_version.outputs.version }} already exists. Exiting workflow successfully." + else + echo "tag_exists=false" >> $GITHUB_ENV + fi + + # Generate Release Notes + - name: Generate Release Notes + id: changelog + if: env.tag_exists == 'false' + uses: mikepenz/release-changelog-builder-action@v5.0.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Create a new release tag + - name: Create GitHub Release + if: env.tag_exists == 'false' + uses: ncipollo/release-action@v1.14.0 + with: + tag: ${{ steps.get_version.outputs.version }} + name: "v${{ steps.get_version.outputs.version }}" + draft: false + prerelease: false + makeLatest: true + body: ${{ steps.changelog.outputs.changelog }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Create ZIP File in a New Source Directory + - name: Prepare and Zip Release Files + if: env.tag_exists == 'false' + run: | + mkdir -p src/releases + zip -r src/releases/release_${{ steps.get_version.outputs.version }}.zip . \ + --exclude "./src/releases/*" \ + --exclude ".*" \ + --exclude ".*/**" + zip -r src/releases/latest.zip . \ + --exclude "./src/releases/*" \ + --exclude ".*" \ + --exclude ".*/**" + + # Upload to Azure Blob Storage + - name: Azure Blob Upload with Destination folder defined + if: env.tag_exists == 'false' + uses: LanceMcCarthy/Action-AzureBlobUpload@v3.3.0 + with: + connection_string: ${{ secrets.AZURE_CONNECTION_STRING }} + container_name: cipp-api + source_folder: src/releases/ + destination_folder: / + delete_if_exists: true \ No newline at end of file diff --git a/CIPPTimers.json b/CIPPTimers.json index 0d1d6dca1038..12988efc9c8c 100644 --- a/CIPPTimers.json +++ b/CIPPTimers.json @@ -1,5 +1,6 @@ [ { + "Id": "c0c48d71-7918-4828-bc25-0e8c28a171a2", "Command": "Start-DurableCleanup", "Description": "Timer function to cleanup durable functions", "Cron": "0 */15 * * * *", @@ -8,6 +9,7 @@ "IsSystem": true }, { + "Id": "76dc2e2e-eb89-47f7-bd9f-8aaebfe854c7", "Command": "Start-UserTasksOrchestrator", "Description": "Orchestrator to process user scheduled tasks", "Cron": "0 */15 * * * *", @@ -16,6 +18,7 @@ "PreferredProcessor": "usertasks" }, { + "Id": "168decf3-7ddd-471e-ab46-8b40be0f18ae", "Command": "Start-CIPPProcessorQueue", "Description": "Timer to handle user initiated tasks", "Cron": "0 */15 * * * *", @@ -23,6 +26,7 @@ "RunOnProcessor": true }, { + "Id": "44a40668-ed71-403c-8c26-b32e320086ad", "Command": "Start-AuditLogOrchestrator", "Description": "Orchestrator to process audit logs", "Cron": "0 */15 * * * *", @@ -32,6 +36,7 @@ "IsSystem": true }, { + "Id": "03475c86-4314-4d7b-90f2-5a0639e3899b", "Command": "Start-AuditLogSearchCreation", "Description": "Timer to create audit log searches", "Cron": "0 */30 * * * *", @@ -41,6 +46,7 @@ "IsSystem": true }, { + "Id": "5ff6c500-e420-4a3b-8532-ace2e4da4f7d", "Command": "Start-ApplicationOrchestrator", "Description": "Orchestrator to process application uploads", "Cron": "0 0 */12 * * *", @@ -48,6 +54,7 @@ "RunOnProcessor": true }, { + "Id": "5b3bb926-d107-471e-8787-3b22b0d4dbbe", "Command": "Start-WebhookOrchestrator", "Description": "Orchestrator to process webhooks", "Cron": "0 */15 * * * *", @@ -55,6 +62,7 @@ "RunOnProcessor": true }, { + "Id": "9b0c8e50-f798-49db-9a8b-dbcc0fcadeea", "Command": "Start-StandardsOrchestrator", "Description": "Orchestrator to process standards", "Cron": "0 0 */4 * * *", @@ -63,6 +71,7 @@ "PreferredProcessor": "standards" }, { + "Id": "5113c66d-c040-42df-9565-39dff90ddd55", "Command": "Start-CIPPGraphSubscriptionCleanupTimer", "Description": "Orchestrator to cleanup old Graph subscriptions", "Cron": "0 0 0 * * *", @@ -70,6 +79,7 @@ "RunOnProcessor": true }, { + "Id": "97145a1d-28f0-4bb2-b929-5a43517d23cc", "Command": "Start-SchedulerOrchestrator", "Description": "Orchestrator to process system scheduled tasks", "Cron": "0 0 * * * *", @@ -77,6 +87,7 @@ "RunOnProcessor": true }, { + "Id": "ed7b5241-1cb9-499b-8f5b-1013ba5764b4", "Command": "Set-CIPPGDAPInviteGroups", "Description": "Orchestrator to map the groups for GDAP invites", "Cron": "0 0 */3 * * *", @@ -84,6 +95,7 @@ "RunOnProcessor": true }, { + "Id": "4ca242d0-8dc8-4256-b0ed-186599f4233f", "Command": "Start-UpdateTokensTimer", "Description": "Orchestrator to update tokens", "Cron": "0 0 0 * * 0", @@ -92,6 +104,7 @@ "IsSystem": true }, { + "Id": "ebe981b6-4417-406e-a1a5-7b8279058841", "Command": "Start-CIPPGraphSubscriptionRenewalTimer", "Description": "Orchestrator to renew Graph subscriptions", "Cron": "0 15 * * * *", @@ -100,6 +113,7 @@ "IsSystem": true }, { + "Id": "c2ebde3f-fa35-45aa-8a6b-91c835050b79", "Command": "Start-DomainOrchestrator", "Description": "Orchestrator to process domains", "Cron": "0 0 0 * * *", @@ -107,6 +121,19 @@ "RunOnProcessor": true }, { + "Id": "f82345da-e370-4b15-8167-be148cfd04af", + "Command": "Get-Tenants", + "Parameters": { + "TriggerRefresh": true + }, + "Description": "Update tenants", + "Cron": "0 0 23 * * *", + "Priority": 10, + "RunOnProcessor": true, + "IsSystem": true + }, + { + "Id": "d9ff3af4-bd34-40d6-b12a-8fa24463f331", "Command": "Start-UpdatePermissionsOrchestrator", "Description": "Orchestrator to update CPV permissions", "Cron": "0 0 0 * * *", @@ -115,6 +142,7 @@ "IsSystem": true }, { + "Id": "467787cf-01c5-4d20-8097-c2eef691a20e", "Command": "Start-BillingTimer", "Description": "Timer to process billing", "Cron": "0 0 0 * * *", @@ -122,6 +150,7 @@ "RunOnProcessor": true }, { + "Id": "80070b4f-95ed-4e5f-be4c-9e339306d4aa", "Command": "Start-BPAOrchestrator", "Description": "Orchestrator to process BPA reports", "Cron": "0 0 3 * * *", @@ -129,6 +158,7 @@ "RunOnProcessor": true }, { + "Id": "54c39540-fe91-4795-8613-ac4295751a51", "Command": "Start-ExtensionOrchestrator", "Description": "Orchestrator to process extensions", "Cron": "0 0 */2 * * *", @@ -136,6 +166,7 @@ "RunOnProcessor": true }, { + "Id": "3fb9745b-08c9-411b-bfac-dc48087489d5", "Command": "Start-CIPPStatsTimer", "Description": "Timer to process CIPP stats", "Cron": "0 0 0 * * *", @@ -144,11 +175,24 @@ "IsSystem": true }, { + "Id": "f74a4540-c811-4037-997c-0d32d7d5742f", "Command": "Start-TableCleanup", "Description": "Timer to cleanup tables", "Cron": "0 0 23 * * *", "Priority": 20, "RunOnProcessor": true, "IsSystem": true + }, + { + "Id": "e87db59d-3386-4a51-8274-da9aeb6793e3", + "Command": "Get-Tenants", + "Parameters": { + "CleanOld": true + }, + "Description": "Timer to cleanup old tenants", + "Cron": "0 0 0 * * *", + "Priority": 20, + "RunOnProcessor": true, + "IsSystem": true } ] diff --git a/Config/59bd753c-4204-4b3a-b84b-850d4b69f494.IntuneTemplate.json b/Config/59bd753c-4204-4b3a-b84b-850d4b69f494.IntuneTemplate.json index 91b9bd8c34f4..84d2fa964133 100644 --- a/Config/59bd753c-4204-4b3a-b84b-850d4b69f494.IntuneTemplate.json +++ b/Config/59bd753c-4204-4b3a-b84b-850d4b69f494.IntuneTemplate.json @@ -3,5 +3,5 @@ "Description": "", "RAWJson": "{\r\n \"name\": \"LAPS\",\r\n \"description\": \"\",\r\n \"settings\": [\r\n {\r\n \"id\": \"0\",\r\n \"settingInstance\": {\r\n \"@odata.type\": \"#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance\",\r\n \"settingDefinitionId\": \"device_vendor_msft_laps_policies_backupdirectory\",\r\n \"settingInstanceTemplateReference\": {\r\n \"settingInstanceTemplateId\": \"a3270f64-e493-499d-8900-90290f61ed8a\"\r\n },\r\n \"choiceSettingValue\": {\r\n \"value\": \"device_vendor_msft_laps_policies_backupdirectory_1\",\r\n \"settingValueTemplateReference\": {\r\n \"settingValueTemplateId\": \"4d90f03d-e14c-43c4-86da-681da96a2f92\",\r\n \"useTemplateDefault\": false\r\n },\r\n \"children\": [\r\n {\r\n \"@odata.type\": \"#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance\",\r\n \"settingDefinitionId\": \"device_vendor_msft_laps_policies_passwordagedays_aad\",\r\n \"settingInstanceTemplateReference\": null,\r\n \"simpleSettingValue\": {\r\n \"@odata.type\": \"#microsoft.graph.deviceManagementConfigurationIntegerSettingValue\",\r\n \"settingValueTemplateReference\": null,\r\n \"value\": 30\r\n }\r\n }\r\n ]\r\n }\r\n }\r\n },\r\n {\r\n \"id\": \"1\",\r\n \"settingInstance\": {\r\n \"@odata.type\": \"#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance\",\r\n \"settingDefinitionId\": \"device_vendor_msft_laps_policies_passwordcomplexity\",\r\n \"settingInstanceTemplateReference\": {\r\n \"settingInstanceTemplateId\": \"8a7459e8-1d1c-458a-8906-7b27d216de52\"\r\n },\r\n \"choiceSettingValue\": {\r\n \"value\": \"device_vendor_msft_laps_policies_passwordcomplexity_4\",\r\n \"settingValueTemplateReference\": {\r\n \"settingValueTemplateId\": \"aa883ab5-625e-4e3b-b830-a37a4bb8ce01\",\r\n \"useTemplateDefault\": false\r\n },\r\n \"children\": []\r\n }\r\n }\r\n }\r\n ],\r\n \"platforms\": \"windows10\",\r\n \"technologies\": \"mdm\",\r\n \"templateReference\": {\r\n \"templateId\": \"adc46e5a-f4aa-4ff6-aeff-4f27bc525796_1\",\r\n \"templateFamily\": \"endpointSecurityAccountProtection\",\r\n \"templateDisplayName\": \"Local admin password solution (Windows LAPS)\",\r\n \"templateDisplayVersion\": \"Version 1\"\r\n }\r\n}", "Type": "Catalog", - "GUID": "59bd753c-4204-4b3a-b84b-850d4b69f494" + "GUID": "59bd753c-4204-4b3a-b84b-850d4b69f494.IntuneTemplate.json" } diff --git a/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json b/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json index 91cf7015ff8d..2b36b4a3ed3d 100644 --- a/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json +++ b/Config/b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json @@ -3,5 +3,5 @@ "Description": "Configures the first profile on a device to always use the e-mail address of the currently logged on user.", "RAWJson": "{\"name\":\"Automatic configuration of Outlook\",\"description\":\"\",\"platforms\":\"windows10\",\"technologies\":\"mdm\",\"roleScopeTagIds\":[\"0\"],\"settings\":[{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationSetting\",\"settingInstance\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance\",\"settingDefinitionId\":\"user_vendor_msft_policy_config_outlk16v2~policy~l_microsoftofficeoutlook~l_toolsaccounts~l_exchangesettings_l_automaticallyconfigureprofilebasedonactiveonce\",\"choiceSettingValue\":{\"@odata.type\":\"#microsoft.graph.deviceManagementConfigurationChoiceSettingValue\",\"value\":\"user_vendor_msft_policy_config_outlk16v2~policy~l_microsoftofficeoutlook~l_toolsaccounts~l_exchangesettings_l_automaticallyconfigureprofilebasedonactiveonce_1\",\"children\":[]}}}]}", "Type": "Catalog", - "GUID": "b79d0123-3105-4c5d-9f15-62cc7a7eb7e1" + "GUID": "b79d0123-3105-4c5d-9f15-62cc7a7eb7e1.IntuneTemplate.json" } diff --git a/ConversionTable.csv b/ConversionTable.csv index 55ebdfd465b9..4463224224a6 100644 --- a/ConversionTable.csv +++ b/ConversionTable.csv @@ -1428,6 +1428,17 @@ Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99 Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_BUSINESS_CHAT,3f30311c-6b1e-48a4-ab79-725b469da960,Microsoft Copilot with Graph-grounded chat Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_CONNECTORS,89f1c4c8-0878-40f7-804d-869c9128ab5d,Power Platform Connectors in Microsoft 365 Copilot Microsoft 365 Domestic Calling Plan (120 minutes) - US,MCOPSTN5_US,d13e9d1b-316a-4946-98c6-362c97a4fdfe,PSTN5_US,1346d5e6-15a6-4b88-9693-806ff7296a7a,Microsoft 365 Domestic Calling Plan - US (120 minutes) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings @@ -1445,6 +1456,7 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_O365,882e1d0 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway @@ -1466,6 +1478,56 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_A,c1ec4a95-1 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MDE_LITE,292cc034-7b7c-4950-aaf5-943befd3f1d4,Microsoft Defender for Endpoint Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_LOOP,c4b8c31a-fb44-4c65-9837-a21f55fcabda,Microsoft Loop +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,UNIVERSAL_PRINT_01,795f6fe0-cc4d-4773-b050-5dde4dc704c9,Universal Print +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WIN10_PRO_ENT_SUB,21b439ba-a0ca-424f-a6cc-52f954a5b111,Windows 10/11 Enterprise (Original) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Windows_Autopatch,9a6eeb79-0b4b-4bf0-9808-39d99a2cd5a3,Windows Autopatch +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WINDOWSUPDATEFORBUSINESS_DEPLOYMENTSERVICE,7bf960f6-2cd9-443a-8046-5dbff9558365,Windows Update for Business Deployment Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_PREMIUM,6c57d4b6-3b23-47a5-9bc9-69f17b4947b3,Azure Information Protection Premium P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MFA_PREMIUM,8a256a2b-b617-496d-b51b-e76466e88db0,Microsoft Azure Multi-Factor Authentication +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ADALLOM_S_DISCOVERY,932ad362-64a8-4783-9106-97849a1a30b9,Microsoft Defender for Cloud Apps Discovery +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,AAD_PREMIUM,41781fb2-bc02-4b7c-bd55-b576c07bb09d,Microsoft Entra ID P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_A,c1ec4a95-1f05-45b3-a911-aa3fa01094f5,Microsoft Intune Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,Commercial data protection for Microsoft Copilot @@ -3186,6 +3248,8 @@ Microsoft Defender for Identity,ATA,98defdf7-f6c1-44f5-a1f6-943b6764e7a5,ADALLOM Microsoft Defender for Office 365 (Plan 1) Faculty,ATP_ENTERPRISE_FACULTY,26ad4b5c-b686-462e-84b9-d7c22b46837f,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 1) GCC,ATP_ENTERPRISE_GOV,d0d1ca43-b81a-4f51-81e5-a5b1ad7bb005,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH,ATP_ENTERPRISE_USGOV_GCCHIGH ,550f19ba-f323-4a7d-a8d2-8971b0d9ea85,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student,ATP_ENTERPRISE_STUDENT,917fb2b4-f71c-43a1-8edc-75532b554bb5,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student use benefit,ATP_ENTERPRISE_STUDENTS_USE_BENEFIT,a237b6d8-572e-4839-bffd-7786d32a5d0e,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,MTP,bf28f719-7844-4079-9c78-c1307898e192,Microsoft 365 Defender Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,THREAT_INTELLIGENCE_GOV,900018f1-0cdb-4ecb-94d4-90281760fdc6,Microsoft Defender for Office 365 (Plan 2) for Government @@ -3468,9 +3532,9 @@ Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,MIN Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,MINECRAFT_EDUCATION_EDITION,4c246bbc-f513-4311-beff-eba54c353256,Minecraft Education Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,NONPROFIT_PORTAL,7dbc2d88-20e2-4eb6-b065-4510b38d6eb2,Nonprofit Portal Office 365 A1 for faculty,STANDARDWOFFPACK_FACULTY,94763226-9b3c-4e75-a931-5c89701abe66,AAD_BASIC_EDU,1d0f309f-fdf9-4b2a-9ae7-9c48b91f1426,Microsoft Entra ID Basic for Education @@ -3858,6 +3922,23 @@ Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWERAPPS_O365_P1,92f7a6f3-b89b-4bbd-8c30-809e6da5ad1c,Power Apps for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,FLOW_O365_P1,0f9b09cb-62d1-4ff4-9129-43f4996f83f4,Power Automate for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWER_VIRTUAL_AGENTS_O365_P1,0683001c-0492-4d59-9515-d9a6426b5813,Power Virtual Agents for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,CDS_O365_P1,bed136c6-b799-4462-824d-fc045d3a9d25,Common Data Service for Teams +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,Exchange Online (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FORMS_PLAN_E1_AR_GCCHIGH,9c37c053-dfe3-4421-b6d4-bac8b86d42bd,Microsoft Forms (Plan E1) for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFT_SEARCH_GCCH,fc9f7921-4ca5-42c6-8533-1b84c4ee496b,Microsoft Search for Arlington +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,TEAMS_AR_GCCHIGH,9953b155-8aef-4c56-92f3-72b0487fce41,Microsoft Teams for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,OFFICEMOBILE_SUBSCRIPTION,c63d4d19-e8cb-460e-b37c-4d6c34603745,Office Mobile Apps for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SharePoint (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,DYN365_CDS_O365_P1,40b010bb-0b69-4654-ac5e-ba161433f4b4,Common Data Service +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,STREAM_O365_E1,743dd19e-1ce3-4c62-a3ad-49ba8f63a2f6,Microsoft Stream for Office 365 E1 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,POWERAPPS_O365_P1_GCCHIGH,3913e44e-824e-490c-a182-82785d769b45,Power Apps for Office 365 for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FLOW_O365_P1_GCCHIGH,e923bad8-588e-44d5-acd0-b226daa7b4de,Power Automate for Office 365 for GCCHigh Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,BPOS_S_TODO_1,5e62787c-c316-451f-b873-1d05acd4d12c,BPOS_S_TODO_1 Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,MICROSOFT STAFFHUB Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,EXCHANGE ONLINE (PLAN 1) @@ -3908,6 +3989,44 @@ Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,DYN365_CDS_O36 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard @@ -4563,16 +4682,16 @@ Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-5 Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,CDS_ POWERAPPS_PER_USER_CUSTOM,2e8dde43-6986-479d-b179-7dbe31c31f60,CDS Power Apps Per User Custom Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,DYN365_CDS_P1_GOV,ce361df2-f2a5-4713-953f-4050ba09aad8,Common Data Service for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,FLOW_P1_GOV,774da41c-a8b3-47c1-8322-b9c1ab68be9f,Power Automate (Plan 1) for Government @@ -4810,26 +4929,26 @@ Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4c Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,SWAY -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,Common Data Service for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,Power Automate for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT STANDARD -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project @@ -4948,13 +5067,13 @@ Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,OneDrive for Business (Basic) Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,Visio Desktop App Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,Visio Web App -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,EXCHANGE FOUNDATION FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,ONEDRIVE_BASIC_GOV,98709c2e-96b5-4244-95f5-a0ebe139fb8a,ONEDRIVE FOR BUSINESS BASIC FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,VISIO_CLIENT_SUBSCRIPTION_GOV,f85945f4-7a55-4009-bc39-6a5f14a8eac1,VISIO DESKTOP APP FOR Government diff --git a/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 b/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 index 760e4fe66791..3bd121c0c1c6 100644 --- a/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 @@ -19,12 +19,14 @@ function Add-CIPPAzDataTableEntity { } catch [System.Exception] { if ($_.Exception.ErrorCode -eq 'PropertyValueTooLarge' -or $_.Exception.ErrorCode -eq 'EntityTooLarge' -or $_.Exception.ErrorCode -eq 'RequestBodyTooLarge') { try { + Write-Host 'Entity is too large. Splitting entity into multiple parts.' + Write-Information ($SingleEnt | ConvertTo-Json) $largePropertyNames = [System.Collections.Generic.List[string]]::new() $entitySize = 0 # Convert $SingleEnt to hashtable if it is a PSObject if ($SingleEnt -is [System.Management.Automation.PSCustomObject]) { - $SingleEnt = $SingleEnt | ConvertTo-Json -Depth 100 | ConvertFrom-Json -AsHashtable + $SingleEnt = $SingleEnt | ConvertTo-Json -Depth 100 -Compress | ConvertFrom-Json -AsHashtable } foreach ($key in $SingleEnt.Keys) { @@ -35,7 +37,7 @@ function Add-CIPPAzDataTableEntity { } } - if ($largePropertyNames.Count -gt 0) { + if (($largePropertyNames | Measure-Object).Count -gt 0) { $splitInfoList = [System.Collections.Generic.List[object]]::new() foreach ($largePropertyName in $largePropertyNames) { $dataString = $SingleEnt[$largePropertyName] @@ -45,20 +47,20 @@ function Add-CIPPAzDataTableEntity { $start = $i * $MaxSize $splitData.Add($dataString.Substring($start, [Math]::Min($MaxSize, $dataString.Length - $start))) > $null } - + $splitDataCount = ($splitData | Measure-Object).Count $splitPropertyNames = [System.Collections.Generic.List[object]]::new() - for ($i = 0; $i -lt $splitData.Count; $i++) { - $splitPropertyNames.Add("${largePropertyName}_Part$i") > $null + for ($i = 0; $i -lt $splitDataCount; $i++) { + $splitPropertyNames.Add("${largePropertyName}_Part$i") } $splitInfo = @{ OriginalHeader = $largePropertyName SplitHeaders = $splitPropertyNames } - $splitInfoList.Add($splitInfo) > $null + $splitInfoList.Add($splitInfo) $SingleEnt.Remove($largePropertyName) - for ($i = 0; $i -lt $splitData.Count; $i++) { + for ($i = 0; $i -lt $splitDataCount; $i++) { $SingleEnt[$splitPropertyNames[$i]] = $splitData[$i] } } @@ -67,7 +69,7 @@ function Add-CIPPAzDataTableEntity { } # Check if the entity is still too large - $entitySize = [System.Text.Encoding]::UTF8.GetByteCount($($SingleEnt | ConvertTo-Json)) + $entitySize = [System.Text.Encoding]::UTF8.GetByteCount($($SingleEnt | ConvertTo-Json -Compress)) if ($entitySize -gt $MaxRowSize) { $rows = [System.Collections.Generic.List[object]]::new() $originalPartitionKey = $SingleEnt.PartitionKey @@ -89,7 +91,7 @@ function Add-CIPPAzDataTableEntity { $propertiesToRemove = [System.Collections.Generic.List[object]]::new() foreach ($key in $SingleEnt.Keys) { - $newEntitySize = [System.Text.Encoding]::UTF8.GetByteCount($($newEntity | ConvertTo-Json)) + $newEntitySize = [System.Text.Encoding]::UTF8.GetByteCount($($newEntity | ConvertTo-Json -Compress)) if ($newEntitySize -lt $MaxRowSize) { $propertySize = [System.Text.Encoding]::UTF8.GetByteCount($SingleEnt[$key].ToString()) if ($propertySize -gt $MaxRowSize) { @@ -103,7 +105,7 @@ function Add-CIPPAzDataTableEntity { $splitPropertyNames = [System.Collections.Generic.List[object]]::new() for ($i = 0; $i -lt $splitData.Count; $i++) { - $splitPropertyNames.Add("${key}_Part$i") > $null + $splitPropertyNames.Add("${key}_Part$i") } for ($i = 0; $i -lt $splitData.Count; $i++) { @@ -112,7 +114,7 @@ function Add-CIPPAzDataTableEntity { } else { $newEntity[$key] = $SingleEnt[$key] } - $propertiesToRemove.Add($key) > $null + $propertiesToRemove.Add($key) } } @@ -120,21 +122,21 @@ function Add-CIPPAzDataTableEntity { $SingleEnt.Remove($prop) } - $rows.Add($newEntity) > $null - $entitySize = [System.Text.Encoding]::UTF8.GetByteCount($($SingleEnt | ConvertTo-Json)) + $rows.Add($newEntity) + $entitySize = [System.Text.Encoding]::UTF8.GetByteCount($($SingleEnt | ConvertTo-Json -Compress)) } - if ($SingleEnt.Count -gt 0) { + if (($SingleEnt | Measure-Object).Count -gt 0) { $SingleEnt['RowKey'] = "$($originalRowKey)-part$entityIndex" $SingleEnt['OriginalEntityId'] = $originalRowKey $SingleEnt['PartIndex'] = $entityIndex $SingleEnt['PartitionKey'] = $originalPartitionKey - $rows.Add($SingleEnt) > $null + $rows.Add($SingleEnt) } foreach ($row in $rows) { - Write-Information "current entity is $($row.RowKey) with $($row.PartitionKey). Our size is $([System.Text.Encoding]::UTF8.GetByteCount($($row | ConvertTo-Json)))" + Write-Information "current entity is $($row.RowKey) with $($row.PartitionKey). Our size is $([System.Text.Encoding]::UTF8.GetByteCount($($row | ConvertTo-Json -Compress)))" Add-AzDataTableEntity -Context $Context -Force:$Force -CreateTableIfNotExists:$CreateTableIfNotExists -Entity $row } } else { diff --git a/Modules/CIPPCore/Public/Add-CIPPGDAPRoleTemplate.ps1 b/Modules/CIPPCore/Public/Add-CIPPGDAPRoleTemplate.ps1 new file mode 100644 index 000000000000..4c01b85cb78c --- /dev/null +++ b/Modules/CIPPCore/Public/Add-CIPPGDAPRoleTemplate.ps1 @@ -0,0 +1,47 @@ +function Add-CIPPGDAPRoleTemplate { + <# + .SYNOPSIS + This function is used to add a new role template + + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + param( + $TemplateId, + $RoleMappings, + [switch]$Overwrite + ) + + $Table = Get-CIPPTable -TableName 'GDAPRoleTemplates' + $Templates = Get-CIPPAzDataTableEntity @Table + if ($Templates.RowKey -contains $TemplateId -and !$Overwrite.IsPresent) { + $ExistingTemplate = $Templates | Where-Object -Property RowKey -EQ $RowKey + try { + $ExistingRoleMappings = $ExistingTemplate.RoleMappings | ConvertFrom-Json + } catch { + $ExistingRoleMappings = @() + } + $NewRoleMappings = [System.Collections.Generic.List[object]]@() + + $ExistingRoleMappings | ForEach-Object { + $NewRoleMappings.Add($_) + } + # Merge the new role mappings with the existing role mappings, exclude ones that have a duplicate roleDefinitionId + $RoleMappings | ForEach-Object { + if ($_.roleDefinitionId -notin $ExistingRoleMappings.roleDefinitionId) { + $NewRoleMappings.Add($_) + } + } + $NewRoleMappings = @($NewRoleMappings | Sort-Object -Property GroupName) | ConvertTo-Json -Compress + $ExistingTemplate.RoleMappings = [string]$NewRoleMappings + $Template = $ExistingTemplate + } else { + $Template = [PSCustomObject]@{ + PartitionKey = 'RoleTemplate' + RowKey = $TemplateId + RoleMappings = [string](@($RoleMappings | Sort-Object -Property GroupName) | ConvertTo-Json -Compress) + } + } + Add-CIPPAzDataTableEntity @Table -Entity $Template -Force +} diff --git a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 index b29972bcce3a..c81175d2c9ef 100644 --- a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 @@ -12,18 +12,16 @@ function Add-CIPPGroupMember( $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $GroupId; Member = $member; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $TenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)" -tenantid $TenantFilter -type patch -body $addmemberbody -Verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)" -tenantid $TenantFilter -type patch -body $addmemberbody -Verbose } $Message = "Successfully added user $($Member) to $($GroupId)." Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' return $message - return } catch { - $message = "Failed to add user $($Member) to $($GroupId)" + $message = "Failed to add user $($Member) to $($GroupId) - $($_.Exception.Message)" Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $message -Sev 'error' -LogData (Get-CippException -Exception $_) return $message } - } diff --git a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 index 30aa79cffaa2..6154119e56a4 100644 --- a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 @@ -17,11 +17,12 @@ function Add-CIPPScheduledTask { } $propertiesToCheck = @('Webhook', 'Email', 'PSA') - $PostExecution = ($propertiesToCheck | Where-Object { $task.PostExecution.$_ -eq $true }) -join ',' + $PostExecutionObject = ($propertiesToCheck | Where-Object { $task.PostExecution.$_ -eq $true }) + $PostExecution = $PostExecutionObject ? ($PostExecutionObject -join ',') : ($Task.PostExecution.value -join ',') $Parameters = [System.Collections.Hashtable]@{} foreach ($Key in $task.Parameters.PSObject.Properties.Name) { $Param = $task.Parameters.$Key - if ($Param -is [System.Collections.IDictionary]) { + if ($Param -is [System.Collections.IDictionary] -or $Param.Key) { $ht = @{} foreach ($p in $Param.GetEnumerator()) { $ht[$p.Key] = $p.Value @@ -59,7 +60,7 @@ function Add-CIPPScheduledTask { PartitionKey = [string]'ScheduledTask' TaskState = [string]'Planned' RowKey = [string]$RowKey - Tenant = [string]$task.TenantFilter + Tenant = $task.TenantFilter.value ? "$($task.TenantFilter.value)" : "$($task.TenantFilter)" Name = [string]$task.Name Command = [string]$task.Command.value Parameters = [string]$Parameters diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppCertificateExpiry.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppCertificateExpiry.ps1 new file mode 100644 index 000000000000..6e9b3bbf387f --- /dev/null +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppCertificateExpiry.ps1 @@ -0,0 +1,33 @@ +function Get-CIPPAlertAppCertificateExpiry { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $false)] + [Alias('input')] + $InputValue, + $TenantFilter + ) + + try { + Write-Host "Checking app expire for $($TenantFilter)" + $appList = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$select=appId,displayName,keyCredentials" -tenantid $TenantFilter + } catch { + return + } + + $AlertData = foreach ($App in $applist) { + Write-Host "checking $($App.displayName)" + if ($App.keyCredentials) { + foreach ($Credential in $App.keyCredentials) { + if ($Credential.endDateTime -lt (Get-Date).AddDays(30) -and $Credential.endDateTime -gt (Get-Date).AddDays(-7)) { + Write-Host ("Application '{0}' has certificates expiring on {1}" -f $App.displayName, $Credential.endDateTime) + @{ DisplayName = $App.displayName; Expires = $Credential.endDateTime } + } + } + } + } + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData +} diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppleTerms.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppleTerms.ps1 new file mode 100644 index 000000000000..3a1d0d6160c4 --- /dev/null +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertAppleTerms.ps1 @@ -0,0 +1,30 @@ +function Get-CIPPAlertAppleTerms { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + Param ( + [Parameter(Mandatory = $false)] + [Alias('input')] + $InputValue, + $TenantFilter + ) + + # 0 = Expired + # 1 = expired? + # 2 = unknown + # 3 = Terms & Conditions + # 4 = Warning + + try { + $appleterms = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/depOnboardingSettings" -tenantid $TenantFilter + } catch { + return + } + + if ($appleterms.lastSyncErrorCode -eq 3) { + $AlertData = "New Apple Business Manager terms are ready to accept." + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + } +} diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDeviceCompliance.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDeviceCompliance.ps1 index a8c3ff745fd5..ebdf7ee55be8 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDeviceCompliance.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertDeviceCompliance.ps1 @@ -12,9 +12,7 @@ function Get-CIPPAlertDeviceCompliance { $TenantFilter ) try { - $AlertData = New-GraphGETRequest -uri "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$top=999" -tenantid $TenantFilter | Where-Object -Property complianceState -NE 'compliant' | ForEach-Object { - $_ | Select-Object -Property id, deviceName, deviceType, complianceState, lastReportedDateTime - } + $AlertData = New-GraphGETRequest -uri "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$filter=complianceState eq 'noncompliant'&`$select=id,deviceName,managedDeviceOwnerType,complianceState,lastSyncDateTime&`$top=999" -tenantid $TenantFilter Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData } catch { Write-AlertMessage -tenant $($TenantFilter) -message "Could not get compliance state for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)" diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertInactiveLicensedUsers.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertInactiveLicensedUsers.ps1 index d114a7426cc0..c8907e481339 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertInactiveLicensedUsers.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertInactiveLicensedUsers.ps1 @@ -15,10 +15,14 @@ function Get-CIPPAlertInactiveLicensedUsers { try { $Lookup = (Get-Date).AddDays(-90).ToUniversalTime().ToString('o') - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=(signInActivity/lastNonInteractiveSignInDateTime le $Lookup)&`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled,assignedLicenses" -scope 'https://graph.microsoft.com/.default' -tenantid $TenantFilter | Where-Object { $_.assignedLicenses.skuId -ne $null } + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=(signInActivity/lastNonInteractiveSignInDateTime le $Lookup)&`$select=id,UserPrincipalName,signInActivity,mail,userType,accountEnabled,assignedLicenses" -scope 'https://graph.microsoft.com/.default' -tenantid $TenantFilter | + Where-Object { $null -ne $_.assignedLicenses.skuId } + + # true = only active users + if ($InputValue -eq $true) { $GraphRequest = $GraphRequest | Where-Object { $_.accountEnabled -eq $true } } $AlertData = foreach ($user in $GraphRequest) { $Message = 'User {0} has been inactive for 90 days, but still has a license assigned.' -f $user.UserPrincipalName - $user | Select-Object -Property userPrincipalname, signInActivity, @{Name = 'Message'; Expression = { $Message } } + $user | Select-Object -Property UserPrincipalName, signInActivity, @{Name = 'Message'; Expression = { $Message } } } Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 index 411e3c96a806..5b38bba86a29 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAdmins.ps1 @@ -18,7 +18,7 @@ function Get-CIPPAlertMFAAdmins { } } if (!$DuoActive) { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$top=999&$filter=IsAdmin eq true' -tenantid $($TenantFilter) | Where-Object -Property 'isMfaRegistered' -EQ $false + $users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq true and isMfaRegistered eq false and userType eq 'member'&`$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) | Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } if ($users.UserPrincipalName) { $AlertData = "The following admins do not have MFA registered: $($users.UserPrincipalName -join ', ')" Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData @@ -30,5 +30,4 @@ function Get-CIPPAlertMFAAdmins { } catch { Write-LogMessage -message "Failed to check MFA status for Admins: $($_.exception.message)" -API 'MFA Alerts - Informational' -tenant $TenantFilter -sev Error } - -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 index 0b59055ed560..92cdfe91f823 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertMFAAlertUsers.ps1 @@ -12,7 +12,7 @@ function Get-CIPPAlertMFAAlertUsers { ) try { - $users = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$top=999&filter=isMfaRegistered eq false and userType eq ''member''&$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered' -tenantid $($TenantFilter) + $users = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?`$top=999&filter=IsAdmin eq false and isMfaRegistered eq false and userType eq 'member'&`$select=userPrincipalName,lastUpdatedDateTime,isMfaRegistered,IsAdmin" -tenantid $($TenantFilter) | Where-Object { $_.userDisplayName -ne 'On-Premises Directory Synchronization Service Account' } if ($users.UserPrincipalName) { $AlertData = "The following $($users.Count) users do not have MFA registered: $($users.UserPrincipalName -join ', ')" Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 index 3708942b4759..e7e9ba47816e 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertNewAppApproval.ps1 @@ -12,8 +12,8 @@ function Get-CIPPAlertNewAppApproval { $TenantFilter ) try { - $Approvals = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/identityGovernance/appConsent/appConsentRequests' -tenantid $TenantFilter | Where-Object -Property requestStatus -EQ 'inProgress' - if ($Approvals.count -gt 1) { + $Approvals = New-GraphGetRequest -Uri "https://graph.microsoft.com/v1.0/identityGovernance/appConsent/appConsentRequests?`$filter=userConsentRequests/any (u:u/status eq 'InProgress')" -tenantid $TenantFilter + if ($Approvals.count -gt 0) { $AlertData = "There are $($Approvals.count) App Approval(s) pending." Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData } diff --git a/Modules/CIPPCore/Public/Alerts/Get-CippAlertBreachAlert.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CippAlertBreachAlert.ps1 new file mode 100644 index 000000000000..cd599c6b51d0 --- /dev/null +++ b/Modules/CIPPCore/Public/Alerts/Get-CippAlertBreachAlert.ps1 @@ -0,0 +1,19 @@ + +function Get-CippAlertBreachAlert { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [Alias('input')] + $TenantFilter + ) + try { + $Search = New-BreachTenantSearch -TenantFilter $TenantFilter + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $Search + } catch { + Write-AlertMessage -tenant $($TenantFilter) -message "Could not get New Breaches for $($TenantFilter): $(Get-NormalizedError -message $_.Exception.message)" + } +} diff --git a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 index 621c1f6d4cac..ac61237dcb60 100644 --- a/Modules/CIPPCore/Public/Assert-CippVersion.ps1 +++ b/Modules/CIPPCore/Public/Assert-CippVersion.ps1 @@ -14,14 +14,14 @@ function Assert-CippVersion { $APIVersion = (Get-Content 'version_latest.txt' -Raw).trim() $RemoteAPIVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP-API/master/version_latest.txt').trim() - $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/master/public/version_latest.txt').trim() + $RemoteCIPPVersion = (Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/KelvinTegelaar/CIPP/main/public/version.json').version [PSCustomObject]@{ LocalCIPPVersion = $CIPPVersion RemoteCIPPVersion = $RemoteCIPPVersion LocalCIPPAPIVersion = $APIVersion RemoteCIPPAPIVersion = $RemoteAPIVersion - OutOfDateCIPP = ([version]$RemoteCIPPVersion -gt [version]$CIPPVersion) - OutOfDateCIPPAPI = ([version]$RemoteAPIVersion -gt [version]$APIVersion) + OutOfDateCIPP = ([semver]$RemoteCIPPVersion -gt [semver]$CIPPVersion) + OutOfDateCIPPAPI = ([semver]$RemoteAPIVersion -gt [semver]$APIVersion) } } diff --git a/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearchResults.ps1 b/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearchResults.ps1 index d2e9ab074bb9..2ced11b10908 100644 --- a/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearchResults.ps1 +++ b/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearchResults.ps1 @@ -14,10 +14,20 @@ function Get-CippAuditLogSearchResults { [string]$TenantFilter, [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [Alias('id')] - [string]$QueryId + [string]$QueryId, + [switch]$CountOnly ) process { - New-GraphGetRequest -uri ('https://graph.microsoft.com/beta/security/auditLog/queries/{0}/records?$top=999' -f $QueryId) -AsApp $true -tenantid $TenantFilter -ErrorAction Stop + $GraphRequest = @{ + Uri = ('https://graph.microsoft.com/beta/security/auditLog/queries/{0}/records?$top=999&$count=true' -f $QueryId) + AsApp = $true + tenantid = $TenantFilter + } + if ($CountOnly.IsPresent) { + $GraphRequest.CountOnly = $true + } + + New-GraphGetRequest @GraphRequest -ErrorAction Stop } } diff --git a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 index f3e1f525ac57..8bac3674e677 100644 --- a/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CIPPRolePermissions.ps1 @@ -18,13 +18,15 @@ function Get-CIPPRolePermissions { $Role = Get-CIPPAzDataTableEntity @Table -Filter $Filter if ($Role) { $Permissions = $Role.Permissions | ConvertFrom-Json + $AllowedTenants = if ($Role.AllowedTenants) { $Role.AllowedTenants | ConvertFrom-Json } else { @() } + $BlockedTenants = if ($Role.BlockedTenants) { $Role.BlockedTenants | ConvertFrom-Json } else { @() } [PSCustomObject]@{ Role = $Role.RowKey Permissions = $Permissions.PSObject.Properties.Value - AllowedTenants = if ($Role.AllowedTenants) { $Role.AllowedTenants | ConvertFrom-Json } else { @() } - BlockedTenants = if ($Role.BlockedTenants) { $Role.BlockedTenants | ConvertFrom-Json } else { @() } + AllowedTenants = @($AllowedTenants) + BlockedTenants = @($BlockedTenants) } } else { throw "Role $RoleName not found." } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index acdaba4e0cee..aa12f2741414 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -4,12 +4,43 @@ function Test-CIPPAccess { [switch]$TenantList ) if ($Request.Params.CIPPEndpoint -eq 'ExecSAMSetup') { return $true } - if (!$Request.Headers.'x-ms-client-principal') { + + # Get function help + $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint + $Help = Get-Help $FunctionName + + # Check help for role + $APIRole = $Help.Role + + if (!$Request.Headers.'x-ms-client-principal' -or ($Request.Headers.'x-ms-client-principal-id' -and $Request.Headers.'x-ms-client-principal-idp' -eq 'aad')) { # Direct API Access - $CustomRoles = @('CIPP-API') + $IPRegex = '^(?(?:\d{1,3}(?:\.\d{1,3}){3}|\[[0-9a-fA-F:]+\]|[0-9a-fA-F:]+))(?::\d+)?$' + $IPAddress = $Request.Headers.'x-forwarded-for' -replace $IPRegex, '$1' -replace '[\[\]]', '' + Write-Information "API Access: AppId=$($Request.Headers.'x-ms-client-principal-id') IP=$IPAddress" + + # TODO: Implement API Client support, create Get-CippApiClient function + <#$Client = Get-CippApiClient -AppId $Request.Headers.'x-ms-client-principal-id' + if ($Client) { + if ($Client.AllowedIPs -contains $IPAddress -or $Client.AllowedIPs -contains 'All')) { + if ($Client.CustomRoles) { + $CustomRoles = @($Client.CustomRoles) + } else { + $CustomRoles = @('CIPP-API') + } + } else { + throw 'Access to this CIPP API endpoint is not allowed, the API Client does not have the required permission' + } + } else { #> + $CustomRoles = @('cipp-api') + # } } else { $DefaultRoles = @('admin', 'editor', 'readonly', 'anonymous', 'authenticated') $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json + + if (!$TenantList.IsPresent -and $APIRole -match 'SuperAdmin' -and $User.userRoles -notcontains 'superadmin') { + throw 'Access to this CIPP API endpoint is not allowed, the user does not have the required permission' + } + if ($User.userRoles -contains 'admin' -or $User.userRoles -contains 'superadmin') { if ($TenantList.IsPresent) { return @('AllTenants') @@ -38,8 +69,8 @@ function Test-CIPPAccess { if ($PermissionsFound) { if ($TenantList.IsPresent) { $LimitedTenantList = foreach ($Permission in $PermissionSet) { - if (($Permission.AllowedTenants | Measure-Object).Count -eq 0 -and ($Permission.BlockedTenants | Measure-Object).Count -eq 0) { - return @('AllTenants') + if ((($Permission.AllowedTenants | Measure-Object).Count -eq 0 -or $Permission.AllowedTenants -contains 'AllTenants') -and (($Permission.BlockedTenants | Measure-Object).Count -eq 0)) { + @('AllTenants') } else { if ($Permission.AllowedTenants -contains 'AllTenants') { $Permission.AllowedTenants = $Tenants.customerId @@ -49,57 +80,51 @@ function Test-CIPPAccess { } return $LimitedTenantList } + foreach ($Role in $PermissionSet) { + # Loop through each custom role permission and check API / Tenant access + $TenantAllowed = $false + $APIAllowed = $false - if (($PermissionSet | Measure-Object).Count -eq 0) { - return $true - } else { - $FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint - $Help = Get-Help $FunctionName - # Check API for required role - $APIRole = $Help.Role - foreach ($Role in $PermissionSet) { - # Loop through each custom role permission and check API / Tenant access - $TenantAllowed = $false - $APIAllowed = $false - foreach ($Perm in $Role.Permissions) { - if ($Perm -match $APIRole) { - $APIAllowed = $true - break - } + foreach ($Perm in $Role.Permissions) { + if ($Perm -match $APIRole) { + $APIAllowed = $true + break } - if ($APIAllowed) { - # Check tenant level access - if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') { - $TenantAllowed = $true - } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { - $TenantAllowed = $false + } + + if ($APIAllowed) { + # Check tenant level access + if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') { + $TenantAllowed = $true + } elseif ($Request.Query.TenantFilter -eq 'AllTenants' -or $Request.Body.TenantFilter -eq 'AllTenants') { + $TenantAllowed = $false + } else { + $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId + if ($Role.AllowedTenants -contains 'AllTenants') { + $AllowedTenants = $Tenants.customerId + } else { + $AllowedTenants = $Role.AllowedTenants + } + if ($Tenant) { + $TenantAllowed = $AllowedTenants -contains $Tenant -and $Role.BlockedTenants -notcontains $Tenant + if (!$TenantAllowed) { continue } + break } else { - $Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId - if ($Role.AllowedTenants -contains 'AllTenants') { - $AllowedTenants = $Tenants.customerId - } else { - $AllowedTenants = $Role.AllowedTenants - } - if ($Tenant) { - $TenantAllowed = $AllowedTenants -contains $Tenant -and $Role.BlockedTenants -notcontains $Tenant - if (!$TenantAllowed) { continue } - break - } else { - $TenantAllowed = $true - break - } + $TenantAllowed = $true + break } } } - if (!$APIAllowed) { - throw "Access to this CIPP API endpoint is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" - } - if (!$TenantAllowed) { - throw 'Access to this tenant is not allowed' - } else { - return $true - } } + if (!$APIAllowed) { + throw "Access to this CIPP API endpoint is not allowed, the '$($Role.Role)' custom role does not have the required permission: $APIRole" + } + if (!$TenantAllowed) { + throw 'Access to this tenant is not allowed' + } else { + return $true + } + } else { # No permissions found for any roles if ($TenantList.IsPresent) { @@ -110,4 +135,4 @@ function Test-CIPPAccess { } else { return $true } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 index 209432df45dd..7914041f8cf4 100644 --- a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 +++ b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 @@ -17,10 +17,11 @@ function Invoke-ListCippQueue { $CippQueue = Get-CippTable -TableName 'CippQueue' $CippQueueTasks = Get-CippTable -TableName 'CippQueueTasks' - $CippQueueData = Get-CIPPAzDataTableEntity @CippQueue | Where-Object { ($_.Timestamp.DateTime) -ge (Get-Date).ToUniversalTime().AddHours(-3) } | Sort-Object -Property Timestamp -Descending + $3HoursAgo = (Get-Date).ToUniversalTime().AddHours(-3).ToString('yyyy-MM-ddTHH:mm:ssZ') + $CippQueueData = Get-CIPPAzDataTableEntity @CippQueue -Filter "Timestamp ge datetime'$3HoursAgo'" | Sort-Object -Property Timestamp -Descending $QueueData = foreach ($Queue in $CippQueueData) { - $Tasks = Get-CIPPAzDataTableEntity @CippQueueTasks -Filter "QueueId eq '$($Queue.RowKey)'" | Where-Object { $_.Name } | Select-Object Timestamp, Name, Status + $Tasks = Get-CIPPAzDataTableEntity @CippQueueTasks -Filter "QueueId eq '$($Queue.RowKey)'" | Where-Object { $_.Name } | Select-Object @{n = 'Timestamp'; exp = { $_.Timestamp.DateTime.ToUniversalTime() } }, Name, Status $TaskStatus = @{} $Tasks | Group-Object -Property Status | ForEach-Object { $TaskStatus.$($_.Name) = $_.Count @@ -58,7 +59,7 @@ function Invoke-ListCippQueue { PercentRunning = [math]::Round((($TotalRunning / $Queue.TotalTasks) * 100), 1) Tasks = @($Tasks) Status = $Queue.Status - Timestamp = $Queue.Timestamp + Timestamp = $Queue.Timestamp.DateTime.ToUniversalTime() } } diff --git a/Modules/CIPPCore/Public/Clear-CippDurables.ps1 b/Modules/CIPPCore/Public/Clear-CippDurables.ps1 index b63d399647d6..ac439e7b8983 100644 --- a/Modules/CIPPCore/Public/Clear-CippDurables.ps1 +++ b/Modules/CIPPCore/Public/Clear-CippDurables.ps1 @@ -29,7 +29,7 @@ function Clear-CippDurables { } if (($QueueEntities | Measure-Object).Count -gt 0) { if ($PSCmdlet.ShouldProcess('Queues', 'Mark Failed')) { - Update-AzDataTableEntity @QueueTable -Entity $QueueEntities + Update-AzDataTableEntity -Force @QueueTable -Entity $QueueEntities } } @@ -41,7 +41,7 @@ function Clear-CippDurables { $Task.Status = 'Failed' $Task } - Update-AzDataTableEntity @CippQueueTasks -Entity $UpdatedTasks + Update-AzDataTableEntity -Force @CippQueueTasks -Entity $UpdatedTasks } } diff --git a/Modules/CIPPCore/Public/ConversionTable.csv b/Modules/CIPPCore/Public/ConversionTable.csv index 55ebdfd465b9..4463224224a6 100644 --- a/Modules/CIPPCore/Public/ConversionTable.csv +++ b/Modules/CIPPCore/Public/ConversionTable.csv @@ -1428,6 +1428,17 @@ Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99 Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_BUSINESS_CHAT,3f30311c-6b1e-48a4-ab79-725b469da960,Microsoft Copilot with Graph-grounded chat Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_CONNECTORS,89f1c4c8-0878-40f7-804d-869c9128ab5d,Power Platform Connectors in Microsoft 365 Copilot Microsoft 365 Domestic Calling Plan (120 minutes) - US,MCOPSTN5_US,d13e9d1b-316a-4946-98c6-362c97a4fdfe,PSTN5_US,1346d5e6-15a6-4b88-9693-806ff7296a7a,Microsoft 365 Domestic Calling Plan - US (120 minutes) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings @@ -1445,6 +1456,7 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_O365,882e1d0 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway @@ -1466,6 +1478,56 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_A,c1ec4a95-1 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MDE_LITE,292cc034-7b7c-4950-aaf5-943befd3f1d4,Microsoft Defender for Endpoint Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_LOOP,c4b8c31a-fb44-4c65-9837-a21f55fcabda,Microsoft Loop +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,UNIVERSAL_PRINT_01,795f6fe0-cc4d-4773-b050-5dde4dc704c9,Universal Print +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WIN10_PRO_ENT_SUB,21b439ba-a0ca-424f-a6cc-52f954a5b111,Windows 10/11 Enterprise (Original) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Windows_Autopatch,9a6eeb79-0b4b-4bf0-9808-39d99a2cd5a3,Windows Autopatch +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WINDOWSUPDATEFORBUSINESS_DEPLOYMENTSERVICE,7bf960f6-2cd9-443a-8046-5dbff9558365,Windows Update for Business Deployment Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_PREMIUM,6c57d4b6-3b23-47a5-9bc9-69f17b4947b3,Azure Information Protection Premium P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MFA_PREMIUM,8a256a2b-b617-496d-b51b-e76466e88db0,Microsoft Azure Multi-Factor Authentication +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ADALLOM_S_DISCOVERY,932ad362-64a8-4783-9106-97849a1a30b9,Microsoft Defender for Cloud Apps Discovery +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,AAD_PREMIUM,41781fb2-bc02-4b7c-bd55-b576c07bb09d,Microsoft Entra ID P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_A,c1ec4a95-1f05-45b3-a911-aa3fa01094f5,Microsoft Intune Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,Commercial data protection for Microsoft Copilot @@ -3186,6 +3248,8 @@ Microsoft Defender for Identity,ATA,98defdf7-f6c1-44f5-a1f6-943b6764e7a5,ADALLOM Microsoft Defender for Office 365 (Plan 1) Faculty,ATP_ENTERPRISE_FACULTY,26ad4b5c-b686-462e-84b9-d7c22b46837f,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 1) GCC,ATP_ENTERPRISE_GOV,d0d1ca43-b81a-4f51-81e5-a5b1ad7bb005,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH,ATP_ENTERPRISE_USGOV_GCCHIGH ,550f19ba-f323-4a7d-a8d2-8971b0d9ea85,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student,ATP_ENTERPRISE_STUDENT,917fb2b4-f71c-43a1-8edc-75532b554bb5,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student use benefit,ATP_ENTERPRISE_STUDENTS_USE_BENEFIT,a237b6d8-572e-4839-bffd-7786d32a5d0e,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,MTP,bf28f719-7844-4079-9c78-c1307898e192,Microsoft 365 Defender Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,THREAT_INTELLIGENCE_GOV,900018f1-0cdb-4ecb-94d4-90281760fdc6,Microsoft Defender for Office 365 (Plan 2) for Government @@ -3468,9 +3532,9 @@ Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,MIN Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,MINECRAFT_EDUCATION_EDITION,4c246bbc-f513-4311-beff-eba54c353256,Minecraft Education Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,NONPROFIT_PORTAL,7dbc2d88-20e2-4eb6-b065-4510b38d6eb2,Nonprofit Portal Office 365 A1 for faculty,STANDARDWOFFPACK_FACULTY,94763226-9b3c-4e75-a931-5c89701abe66,AAD_BASIC_EDU,1d0f309f-fdf9-4b2a-9ae7-9c48b91f1426,Microsoft Entra ID Basic for Education @@ -3858,6 +3922,23 @@ Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWERAPPS_O365_P1,92f7a6f3-b89b-4bbd-8c30-809e6da5ad1c,Power Apps for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,FLOW_O365_P1,0f9b09cb-62d1-4ff4-9129-43f4996f83f4,Power Automate for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWER_VIRTUAL_AGENTS_O365_P1,0683001c-0492-4d59-9515-d9a6426b5813,Power Virtual Agents for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,CDS_O365_P1,bed136c6-b799-4462-824d-fc045d3a9d25,Common Data Service for Teams +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,Exchange Online (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FORMS_PLAN_E1_AR_GCCHIGH,9c37c053-dfe3-4421-b6d4-bac8b86d42bd,Microsoft Forms (Plan E1) for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFT_SEARCH_GCCH,fc9f7921-4ca5-42c6-8533-1b84c4ee496b,Microsoft Search for Arlington +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,TEAMS_AR_GCCHIGH,9953b155-8aef-4c56-92f3-72b0487fce41,Microsoft Teams for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,OFFICEMOBILE_SUBSCRIPTION,c63d4d19-e8cb-460e-b37c-4d6c34603745,Office Mobile Apps for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SharePoint (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,DYN365_CDS_O365_P1,40b010bb-0b69-4654-ac5e-ba161433f4b4,Common Data Service +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,STREAM_O365_E1,743dd19e-1ce3-4c62-a3ad-49ba8f63a2f6,Microsoft Stream for Office 365 E1 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,POWERAPPS_O365_P1_GCCHIGH,3913e44e-824e-490c-a182-82785d769b45,Power Apps for Office 365 for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FLOW_O365_P1_GCCHIGH,e923bad8-588e-44d5-acd0-b226daa7b4de,Power Automate for Office 365 for GCCHigh Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,BPOS_S_TODO_1,5e62787c-c316-451f-b873-1d05acd4d12c,BPOS_S_TODO_1 Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,MICROSOFT STAFFHUB Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,EXCHANGE ONLINE (PLAN 1) @@ -3908,6 +3989,44 @@ Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,DYN365_CDS_O36 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard @@ -4563,16 +4682,16 @@ Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-5 Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,CDS_ POWERAPPS_PER_USER_CUSTOM,2e8dde43-6986-479d-b179-7dbe31c31f60,CDS Power Apps Per User Custom Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,DYN365_CDS_P1_GOV,ce361df2-f2a5-4713-953f-4050ba09aad8,Common Data Service for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,FLOW_P1_GOV,774da41c-a8b3-47c1-8322-b9c1ab68be9f,Power Automate (Plan 1) for Government @@ -4810,26 +4929,26 @@ Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4c Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,SWAY -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,Common Data Service for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,Power Automate for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT STANDARD -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project @@ -4948,13 +5067,13 @@ Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,OneDrive for Business (Basic) Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,Visio Desktop App Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,Visio Web App -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,EXCHANGE FOUNDATION FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,ONEDRIVE_BASIC_GOV,98709c2e-96b5-4244-95f5-a0ebe139fb8a,ONEDRIVE FOR BUSINESS BASIC FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,VISIO_CLIENT_SUBSCRIPTION_GOV,f85945f4-7a55-4009-bc39-6a5f14a8eac1,VISIO DESKTOP APP FOR Government diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BEC/Push-BECRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BEC/Push-BECRun.ps1 index 46800bad1f59..bcfd1dd7262b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BEC/Push-BECRun.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BEC/Push-BECRun.ps1 @@ -26,9 +26,6 @@ function Push-BECRun { } else { $sessionid = Get-Random -Minimum 10000 -Maximum 99999 $operations = @( - 'New-InboxRule', - 'Set-InboxRule', - 'UpdateInboxRules', 'Remove-MailboxPermission', 'Add-MailboxPermission', 'UpdateCalendarDelegation', @@ -96,18 +93,12 @@ function Push-BECRun { $PermissionsLog = @() } + Write-Information 'Getting rules' + try { - $RulesLog = @(($7dayslog | Where-Object -Property Operations -In 'New-InboxRule', 'Set-InboxRule', 'UpdateInboxRules').AuditData | ConvertFrom-Json -ErrorAction Stop) | ForEach-Object { - Write-Information ($_ | ConvertTo-Json) - [pscustomobject]@{ - ClientIP = $_.ClientIP - CreationTime = $_.CreationTime - UserId = $_.UserId - RuleName = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleName') { $_.Value } }) - RuleCondition = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleCondition') { $_.Value } }) - } - } + $RulesLog = New-ExoRequest -cmdlet 'Get-InboxRule' -tenantid $TenantFilter -cmdParams @{ Mailbox = $Username; IncludeHidden = $true } -Anchor $Username } catch { + Write-Host 'Failed to get rules: ' + $_.Exception.Message $RulesLog = @() } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 index 840145d08dee..4229e704b46f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/BPA/Push-BPACollectData.ps1 @@ -21,7 +21,7 @@ function Push-BPACollectData { $Table = Get-CippTable -tablename 'cachebpav2' $Rerun = Test-CIPPRerun -Type 'BPA' -Tenant $TenantName.defaultDomainName -API $Item.Template if ($Rerun) { - Write-Host 'Detected rerun. Exiting cleanly' + Write-Host 'Detected rerun for BPA. Exiting cleanly' exit 0 } Write-Host "Working on BPA for $($TenantName.defaultDomainName) with GUID $($TenantName.customerId) - Report ID $($Item.Template)" diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPAccessTenantTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPAccessTenantTest.ps1 new file mode 100644 index 000000000000..447661a71d88 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPAccessTenantTest.ps1 @@ -0,0 +1,9 @@ +function Push-CIPPAccessTenantTest { + <# + .FUNCTIONALITY + Entrypoint + #> + Param($Item) + + Test-CIPPAccessTenant -Tenant $Item.customerId -ExecutingUser 'CIPP' +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 index 5c18cbe54d21..7f9e54f72637 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 @@ -6,15 +6,13 @@ Function Push-ExecOnboardTenantQueue { [CmdletBinding()] param($Item) try { - $DateFormat = '%Y-%m-%d %H:%M:%S' $Id = $Item.id - #Write-Host ($Item.Roles | ConvertTo-Json) $Start = Get-Date $Logs = [System.Collections.Generic.List[object]]::new() $OnboardTable = Get-CIPPTable -TableName 'TenantOnboarding' $TenantOnboarding = Get-CIPPAzDataTableEntity @OnboardTable -Filter "RowKey eq '$Id'" - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Starting onboarding for relationship $Id" }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = "Starting onboarding for relationship $Id" }) $OnboardingSteps = $TenantOnboarding.OnboardingSteps | ConvertFrom-Json $OnboardingSteps.Step1.Status = 'running' $OnboardingSteps.Step1.Message = 'Checking GDAP invite status' @@ -53,7 +51,7 @@ Function Push-ExecOnboardTenantQueue { ) if ($OnboardingSteps.Step1.Status -ne 'succeeded') { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking relationship status' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Checking relationship status' }) $x = 0 do { $Relationship = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$Id" @@ -62,12 +60,12 @@ Function Push-ExecOnboardTenantQueue { } while ($Relationship.status -ne 'active' -and $x -lt 6) if ($Relationship.status -eq 'active') { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'GDAP Invite Accepted' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'GDAP Invite Accepted' }) $OnboardingSteps.Step1.Status = 'succeeded' $OnboardingSteps.Step1.Message = "GDAP Invite accepted for $($Relationship.customer.displayName)" $TenantOnboarding.CustomerId = $Relationship.customer.tenantId } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'GDAP Invite Failed' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'GDAP Invite Failed' }) $OnboardingSteps.Step1.Status = 'failed' $OnboardingSteps.Step1.Message = 'GDAP Invite timeout, retry onboarding after accepting the invite with a GA account in the customer tenant.' $TenantOnboarding.Status = 'failed' @@ -79,7 +77,7 @@ Function Push-ExecOnboardTenantQueue { } if ($OnboardingSteps.Step1.Status -eq 'succeeded') { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Starting role check' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Starting role check' }) $OnboardingSteps.Step2.Status = 'running' $OnboardingSteps.Step2.Message = 'Checking role mapping' $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) @@ -100,12 +98,18 @@ Function Push-ExecOnboardTenantQueue { } } if (($MissingRoles | Measure-Object).Count -gt 0) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Missing roles for relationship' }) - $TenantOnboarding.Status = 'failed' - $OnboardingSteps.Step2.Status = 'failed' - $OnboardingSteps.Step2.Message = "Your GDAP relationship is missing the following roles: $($MissingRoles -join ', ')" + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Missing roles for relationship' }) + if ($Item.IgnoreMissingRoles -ne $true) { + $TenantOnboarding.Status = 'failed' + $OnboardingSteps.Step2.Status = 'failed' + $OnboardingSteps.Step2.Message = "Your GDAP relationship is missing the following roles: $($MissingRoles -join ', ')" + } else { + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Ignoring missing roles' }) + $OnboardingSteps.Step2.Status = 'succeeded' + $OnboardingSteps.Step2.Message = 'Your GDAP relationship is missing some roles, but the onboarding will continue' + } } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Required roles found' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Required roles found' }) $OnboardingSteps.Step2.Status = 'succeeded' $OnboardingSteps.Step2.Message = 'Your GDAP relationship has the required roles' } @@ -115,10 +119,10 @@ Function Push-ExecOnboardTenantQueue { } if ($OnboardingSteps.Step2.Status -eq 'succeeded') { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking group mapping' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Checking group mapping' }) $AccessAssignments = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$Id/accessAssignments" if ($AccessAssignments.id -and $Item.AutoMapRoles -ne $true) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Groups mapped' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Groups mapped' }) $OnboardingSteps.Step3.Status = 'succeeded' $OnboardingSteps.Step3.Message = 'Your GDAP relationship already has mapped security groups' } else { @@ -134,12 +138,12 @@ Function Push-ExecOnboardTenantQueue { if ($AccessAssignments.id -and !$Invite) { $MissingRoles = [System.Collections.Generic.List[object]]::new() - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Relationship has existing access assignments, checking for missing mappings' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Relationship has existing access assignments, checking for missing mappings' }) if ($Item.Roles -and $Item.AutoMapRoles -eq $true) { foreach ($Role in $Item.Roles) { if ($AccessAssignments.accessContainer.accessContainerid -notcontains $Role.GroupId -and $Relationship.accessDetails.unifiedRoles.roleDefinitionId -contains $Role.roleDefinitionId) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Adding missing group to relationship: $($Role.GroupName)" }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = "Adding missing group to relationship: $($Role.GroupName)" }) $MissingRoles.Add([PSCustomObject]$Role) } } @@ -153,7 +157,7 @@ Function Push-ExecOnboardTenantQueue { } Add-CIPPAzDataTableEntity @InviteTable -Entity $Invite } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'All roles have been mapped to the M365 GDAP security groups' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'All roles have been mapped to the M365 GDAP security groups' }) $OnboardingSteps.Step3.Status = 'succeeded' $OnboardingSteps.Step3.Message = 'Groups mapped successfully' $GroupSuccess = $true @@ -162,7 +166,7 @@ Function Push-ExecOnboardTenantQueue { } if (!$AccessAssignments.id -and $Item.Roles) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'No access assignments found, using defined role mapping.' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'No access assignments found, using defined role mapping.' }) $MatchingRoles = [System.Collections.Generic.List[object]]::new() foreach ($Role in $Item.Roles) { if ($Relationship.accessDetails.unifiedRoles.roleDefinitionId -contains $Role.roleDefinitionId) { @@ -191,17 +195,17 @@ Function Push-ExecOnboardTenantQueue { } if ($Invite) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'GDAP invite found, starting group/role mapping' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'GDAP invite found, starting group/role mapping' }) $GroupMapStatus = Set-CIPPGDAPInviteGroups -Relationship $Relationship if ($GroupMapStatus) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Groups mapped successfully' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Groups mapped successfully' }) $OnboardingSteps.Step3.Message = 'Groups mapped successfully, checking access assignment status' $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) $TenantOnboarding.Logs = [string](ConvertTo-Json -InputObject @($Logs) -Compress) Add-CIPPAzDataTableEntity @OnboardTable -Entity $TenantOnboarding -Force -ErrorAction Stop } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Group mapping failed' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Group mapping failed' }) $TenantOnboarding.Status = 'failed' $OnboardingSteps.Step3.Status = 'failed' $OnboardingSteps.Step3.Message = 'Group mapping failed, check the log book for details.' @@ -226,7 +230,7 @@ Function Push-ExecOnboardTenantQueue { $OnboardingSteps.Step3.Message = 'Group check: Access assignments are mapped and active' $OnboardingSteps.Step3.Status = 'succeeded' if ($Item.AddMissingGroups -eq $true) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Checking for missing groups for SAM user' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Checking for missing groups for SAM user' }) $SamUserId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me?`$select=id").id $CurrentMemberships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/me/transitiveMemberOf?`$select=id,displayName" foreach ($Role in $Item.Roles) { @@ -236,13 +240,13 @@ Function Push-ExecOnboardTenantQueue { } | ConvertTo-Json -Compress try { New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($Role.GroupId)/members/`$ref" -body $PostBody -AsApp $true -NoAuthCheck $true - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Added SAM user to $($Role.GroupName)" }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = "Added SAM user to $($Role.GroupName)" }) } catch { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Failed to add SAM user to $($Role.GroupName) - $($_.Exception.Message)" }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = "Failed to add SAM user to $($Role.GroupName) - $($_.Exception.Message)" }) } } } - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'SAM user group check completed' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'SAM user group check completed' }) } } else { $OnboardingSteps.Step3.Message = 'Group check: Access assignments are still pending, try again later' @@ -257,7 +261,7 @@ Function Push-ExecOnboardTenantQueue { } if ($OnboardingSteps.Step3.Status -eq 'succeeded') { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Setting up CPV consent' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Setting up CPV consent' }) $OnboardingSteps.Step4.Status = 'running' $OnboardingSteps.Step4.Message = 'Setting up CPV consent' $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) @@ -267,12 +271,12 @@ Function Push-ExecOnboardTenantQueue { $ExcludedTenant = Get-Tenants -SkipList | Where-Object { $_.customerId -eq $Relationship.customer.tenantId } $IsExcluded = ($ExcludedTenant | Measure-Object).Count -gt 0 if ($IsExcluded) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = ('Tenant is excluded from CIPP, onboarding cannot continue. Remove the exclusion from "{0}" ({1})' -f $ExcludedTenant.displayName, $ExcludedTenant.customerId) }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = ('Tenant is excluded from CIPP, onboarding cannot continue. Remove the exclusion from "{0}" ({1})' -f $ExcludedTenant.displayName, $ExcludedTenant.customerId) }) $TenantOnboarding.Status = 'failed' $OnboardingSteps.Step4.Status = 'failed' $OnboardingSteps.Step4.Message = 'Tenant excluded from CIPP, remove the exclusion and retry onboarding.' } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Clearing tenant cache' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Clearing tenant cache' }) $y = 0 do { $Tenant = Get-Tenants -TriggerRefresh -TenantFilter $Relationship.customer.tenantId | Select-Object -First 1 @@ -281,7 +285,7 @@ Function Push-ExecOnboardTenantQueue { } while (!$Tenant -and $y -le 10) if ($Tenant) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Tenant found in customer list' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Tenant found in customer list' }) try { $CPVConsentParams = @{ TenantFilter = $Relationship.customer.tenantId @@ -290,9 +294,9 @@ Function Push-ExecOnboardTenantQueue { if ($Consent -match 'Could not add our Service Principal to the client tenant') { throw } - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Added initial CPV consent permissions' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Added initial CPV consent permissions' }) } catch { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = ('CPV Consent Failed, error: {0}' -f $Consent) }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = ('CPV Consent Failed, error: {0}' -f $Consent) }) $TenantOnboarding.Status = 'failed' $OnboardingSteps.Step4.Status = 'failed' $OnboardingSteps.Step4.Message = 'CPV Consent failed, check the logs for more details.' @@ -304,7 +308,7 @@ Function Push-ExecOnboardTenantQueue { } $Refreshing = $true $CPVSuccess = $false - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Refreshing CPV permissions' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Refreshing CPV permissions' }) $OnboardingSteps.Step4.Message = 'Refreshing CPV permissions' $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) $TenantOnboarding.Logs = [string](ConvertTo-Json -InputObject @($Logs) -Compress) @@ -323,20 +327,20 @@ Function Push-ExecOnboardTenantQueue { } while ($Refreshing -and (Get-Date) -lt $Start.AddMinutes(8)) if ($CPVSuccess) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'CPV permissions refreshed' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'CPV permissions refreshed' }) $OnboardingSteps.Step4.Status = 'succeeded' $OnboardingSteps.Step4.Message = 'CPV permissions refreshed' if ($Tenant.defaultDomainName -match 'Domain Error') { $Tenant = Get-Tenants -TriggerRefresh -IncludeAll | Where-Object { $_.customerId -eq $Relationship.customer.tenantId } | Select-Object -First 1 } } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'CPV permissions failed to refresh. {0}' -f $LastCPVError }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'CPV permissions failed to refresh. {0}' -f $LastCPVError }) $TenantOnboarding.Status = 'failed' $OnboardingSteps.Step4.Status = 'failed' $OnboardingSteps.Step4.Message = 'CPV permissions failed to refresh, check the logs for more details.' } } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Tenant not found' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Tenant not found' }) $TenantOnboarding.Status = 'failed' $OnboardingSteps.Step4.Status = 'failed' $OnboardingSteps.Step4.Message = 'Tenant not found in customer list, try again later' @@ -349,29 +353,30 @@ Function Push-ExecOnboardTenantQueue { if ($OnboardingSteps.Step4.Status -eq 'succeeded') { if ($Item.StandardsExcludeAllTenants -eq $true) { - $Settings = @{ - 'OverrideAllTenants' = @{ - 'remediate' = $true + $AddExclusionObj = [PSCustomObject]@{ + label = $Tenant.defaultDomainName + value = $Tenant.defaultDomainName + addedFields = @{} + } + $Table = Get-CippTable -tablename 'templates' + $ExistingTemplates = Get-CippazDataTableEntity @Table -Filter "PartitionKey eq 'StandardsTemplateV2'" | Where-Object { $_.JSON -match 'AllTenants' } + foreach ($AllTenantesTemplate in $ExistingTemplates) { + $object = $AllTenantesTemplate.JSON | ConvertFrom-Json + $NewExcludedTenants = $object.excludedTenants + $AddExclusionObj + $object.excludedTenants = $NewExcludedTenants + $JSON = ConvertTo-Json -InputObject $object -Compress -Depth 10 + $Table.Force = $true + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = "$JSON" + RowKey = $AllTenantesTemplate.RowKey + GUID = $AllTenantesTemplate.GUID + PartitionKey = 'StandardsTemplateV2' } } - $object = [PSCustomObject]@{ - Tenant = $Tenant.defaultDomainName - AddedBy = 'Onboarding' - AppliedAt = (Get-Date).ToString('s') - Standards = $Settings - v2 = $true - } | ConvertTo-Json -Depth 10 - $Table = Get-CippTable -tablename 'standards' - $Table.Force = $true - Add-CIPPAzDataTableEntity @Table -Entity @{ - JSON = "$object" - RowKey = [string]$Tenant.defaultDomainName - PartitionKey = 'standards' - } - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Set All Tenant Standards Exclusion' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Set All Tenant Standards Exclusion' }) } - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = "Testing API access for $($Tenant.defaultDomainName)" }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = "Testing API access for $($Tenant.defaultDomainName)" }) $OnboardingSteps.Step5.Status = 'running' $OnboardingSteps.Step5.Message = 'Testing API access' $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) @@ -388,8 +393,8 @@ Function Push-ExecOnboardTenantQueue { } if ($UserCount -gt 0) { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'API test successful' }) - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Onboarding complete' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'API test successful' }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Onboarding complete' }) $OnboardingSteps.Step5.Status = 'succeeded' $OnboardingSteps.Step5.Message = 'API Test Successful: {0} users found' -f $UserCount $TenantOnboarding.Status = 'succeeded' @@ -398,7 +403,7 @@ Function Push-ExecOnboardTenantQueue { Add-CIPPAzDataTableEntity @OnboardTable -Entity $TenantOnboarding -Force -ErrorAction Stop Write-LogMessage -API 'Onboarding' -message "Tenant onboarding succeeded for $($Relationship.customer.displayName)" -Sev 'Info' } else { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'API Test failed: {0}' -f $ApiError }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'API Test failed: {0}' -f $ApiError }) $OnboardingSteps.Step5.Status = 'failed' $OnboardingSteps.Step5.Message = 'API Test failed: {0}' -f $ApiError $TenantOnboarding.Status = 'succeeded' @@ -409,7 +414,7 @@ Function Push-ExecOnboardTenantQueue { } } } catch { - $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Onboarding failed. Exception: {0}' -f $_.Exception.Message }) + $Logs.Add([PSCustomObject]@{ Date = (Get-Date).ToUniversalTime(); Log = 'Onboarding failed. Exception: {0}' -f $_.Exception.Message }) $TenantOnboarding.Status = 'failed' $TenantOnboarding.Exception = [string]('{0} - Line {1} - {2}' -f $_.Exception.Message, $_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.ScriptName) $TenantOnboarding.OnboardingSteps = [string](ConvertTo-Json -InputObject $OnboardingSteps -Compress) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index 00f8f93e20c1..d7fdf61608be 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -49,7 +49,7 @@ function Push-ExecScheduledCommand { } catch { $errorMessage = $_.Exception.Message if ($task.Recurrence -ne 0) { $State = 'Failed - Planned' } else { $State = 'Failed' } - Update-AzDataTableEntity @Table -Entity @{ + Update-AzDataTableEntity -Force @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey Results = "$errorMessage" @@ -83,7 +83,7 @@ function Push-ExecScheduledCommand { if ($task.Recurrence -eq '0' -or [string]::IsNullOrEmpty($task.Recurrence)) { Write-Host 'Recurrence empty or 0. Task is not recurring. Setting task state to completed.' - Update-AzDataTableEntity @Table -Entity @{ + Update-AzDataTableEntity -Force @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey Results = "$StoredResults" @@ -110,7 +110,7 @@ function Push-ExecScheduledCommand { $nextRunUnixTime = [int64]$task.ScheduledTime + [int64]$secondsToAdd Write-Host "The job is recurring. It was scheduled for $($task.ScheduledTime). The next runtime should be $nextRunUnixTime" - Update-AzDataTableEntity @Table -Entity @{ + Update-AzDataTableEntity -Force @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey Results = "$StoredResults" diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 index 2d8a0c7cd512..c64592b7aab2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ListMailboxRulesQueue.ps1 @@ -21,8 +21,8 @@ function Push-ListMailboxRulesQueue { } } if (($Rules | Measure-Object).Count -gt 0) { - foreach ($Rule in $Rules) { - $GraphRequest = [PSCustomObject]@{ + $GraphRequest = foreach ($Rule in $Rules) { + [PSCustomObject]@{ Rules = [string]($Rule | ConvertTo-Json) RowKey = [string](New-Guid).guid Tenant = [string]$domainName @@ -31,9 +31,9 @@ function Push-ListMailboxRulesQueue { } } else { - $Rules = @{ - Name = 'No rules found' - } | ConvertTo-Json + $Rules = @(@{ + Name = 'No rules found' + }) | ConvertTo-Json $GraphRequest = [PSCustomObject]@{ Rules = [string]$Rules RowKey = [string]$domainName diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 index 811d54b229be..d3ef1e2711c8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-UpdateTenants.ps1 @@ -6,10 +6,7 @@ function Push-UpdateTenants { Param($Item) $QueueReference = 'UpdateTenants' $RunningQueue = Invoke-ListCippQueue | Where-Object { $_.Reference -eq $QueueReference -and $_.Status -ne 'Completed' -and $_.Status -ne 'Failed' } - if ($RunningQueue) { - Write-Host 'Update Tenants already running' - return - } + $Queue = New-CippQueueEntry -Name 'Update Tenants' -Reference $QueueReference -TotalTasks 1 try { $QueueTask = @{ @@ -30,4 +27,4 @@ function Push-UpdateTenants { $QueueTask.Status = 'Failed' Set-CippQueueTask @QueueTask } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 index 276c90519a39..27b206bbc513 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 @@ -12,7 +12,7 @@ function Push-CIPPStandard { $Standard = $Item.Standard $FunctionName = 'Invoke-CIPPStandard{0}' -f $Standard Write-Information "We'll be running $FunctionName" - $Rerun = Test-CIPPRerun -Type Standard -Tenant $Tenant -API $Standard + $Rerun = Test-CIPPRerun -Type Standard -Tenant $Tenant -API "$($Standard)_$($Item.templateId)" if ($Rerun) { Write-Information 'Detected rerun. Exiting cleanly' exit 0 diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-GetStandards.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-GetStandards.ps1 index fa1b43313add..df57ab77f885 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-GetStandards.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-GetStandards.ps1 @@ -6,14 +6,17 @@ function Push-GetStandards { Param($Item) $Params = $Item.StandardParams | ConvertTo-Json | ConvertFrom-Json -AsHashtable + Write-Host "My params are $($Params | ConvertTo-Json -Depth 5 -Compress)" try { $AllTasks = Get-CIPPStandards @Params + Write-Host "AllTasks: $($AllTasks | ConvertTo-Json -Depth 5 -Compress)" foreach ($task in $AllTasks) { [PSCustomObject]@{ Tenant = $task.Tenant Standard = $task.Standard Settings = $task.Settings QueueId = $Item.QueueId + templateId = $task.templateId QueueName = '{0} - {1}' -f $task.Standard, $Task.Tenant FunctionName = 'CIPPStandard' } @@ -22,4 +25,4 @@ function Push-GetStandards { Write-Host "GetStandards Exception $($_.Exception.Message)" } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 index eee642d90665..4276b516c810 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 @@ -26,14 +26,21 @@ function Push-AuditLogTenant { } $CIPPURL = $LegacyUrl } else { - $CIPPURL = 'https://{0}' -f $CippConfig.Value + if (!$CippConfig) { + $CippConfig = @{ + PartitionKey = 'InstanceProperties' + RowKey = 'CIPPURL' + Value = [string]([System.Uri]$Request.Headers.'x-ms-original-url').Host + } + Add-AzDataTableEntity @ConfigTable -Entity $CippConfig -Force + $CIPPURL = 'https://{0}' -f $CippConfig.Value + } else { $CIPPURL = 'https://{0}' -f $CippConfig.Value } } # Get webhook rules $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable $LogSearchesTable = Get-CippTable -TableName 'AuditLogSearches' - Write-Information ("Audit: Memory usage before processing $([System.GC]::GetTotalMemory($false))") - $SearchCount = 0 + $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } if ($Configuration) { try { @@ -89,8 +96,6 @@ function Push-AuditLogTenant { } } } - $SearchCount++ - Write-Information "Audit: Memory usage after processing $SearchCount searches: $([System.GC]::GetTotalMemory($false))" } } catch { Write-Information ( 'Audit Log search: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) @@ -98,8 +103,5 @@ function Push-AuditLogTenant { } } catch { Write-Information ( 'Push-AuditLogTenant: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) - } finally { - Write-Information "Audit Logs: Completed processing $($TenantFilter)" - Write-Information "Audit Logs: Memory usage after processing $([System.GC]::GetTotalMemory($false))" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 index 81a079c2401d..837b439f0a9a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAddAlert.ps1 @@ -10,12 +10,21 @@ Function Invoke-ExecAddAlert { [CmdletBinding()] param($Request, $TriggerMetadata) - - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Alerts' -message $request.body.text -Sev $request.body.Severity - # Associate values to output bindings by calling 'Push-OutputBinding'. + if ($Request.Body.sendEmailNow) { + $CIPPAlert = @{ + Type = 'email' + Title = 'Test Email Alert' + HTMLContent = 'This is a test from CIPP' + TenantFilter = 'PartnerTenant' + } + $Result = Send-CIPPAlert @CIPPAlert + } else { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Alerts' -message $request.body.text -Sev $request.body.Severity + $Result = 'Successfully generated alert.' + # Associate values to output bindings by calling 'Push-OutputBinding'. + } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = 'Successfully generated alert.' + Body = $Result }) - } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAzBobbyTables.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAzBobbyTables.ps1 new file mode 100644 index 000000000000..88080bdcf5b4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAzBobbyTables.ps1 @@ -0,0 +1,58 @@ + +function Invoke-ExecAzBobbyTables { + <# + .SYNOPSIS + Execute a AzBobbyTables function + .DESCRIPTION + This function is used to interact with Azure Tables. This is advanced functionality used for external integrations or SuperAdmin functionality. + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $AllowList = @( + 'Add-AzDataTableEntity' + 'Update-AzDataTableEntity' + 'Get-AzDataTableEntity' + 'Get-AzDataTable' + 'New-AzDataTable' + 'Remove-AzDataTableEntity' + 'Remove-AzDataTable' + ) + + $Function = $Request.Body.FunctionName + $Params = if ($Request.Body.Parameters) { + $Request.Body.Parameters | ConvertTo-Json -Compress -ErrorAction Stop | ConvertFrom-Json -AsHashtable + } else { + @{} + } + + if ($Function -in $AllowList) { + if ($Function -eq 'Get-AzDataTable') { + $Context = New-AzDataTableContext -ConnectionString $env:AzureWebJobsStorage + } else { + $Context = New-AzDataTableContext -ConnectionString $env:AzureWebJobsStorage -TableName $Request.Body.TableName + } + try { + $Results = & $Function -Context $Context @Params + if (!$Results) { + $Results = "Function $Function executed successfully" + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $Results = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError + } + } else { + $Results = "Function $Function not found or not allowed" + $StatusCode = [HttpStatusCode]::NotFound + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($Results) + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCPVRefresh.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCPVRefresh.ps1 new file mode 100644 index 000000000000..dbf1d9de62de --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCPVRefresh.ps1 @@ -0,0 +1,27 @@ +function Invoke-ExecCPVRefresh { + <# + .SYNOPSIS + This endpoint is used to trigger a refresh of CPV for all tenants + + .FUNCTIONALITY + Entrypoint + + .ROLE + CIPP.Core.ReadWrite + #> + [CmdletBinding()] + param( + $Request, + $TriggerMetadata + ) + + $InstanceId = Start-UpdatePermissionsOrchestrator + + Push-OutputBinding -Name Response -Value @{ + StatusCode = [System.Net.HttpStatusCode]::OK + Body = @{ + Results = 'CPV Refresh has been triggered' + InstanceId = $InstanceId + } + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCippFunction.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCippFunction.ps1 new file mode 100644 index 000000000000..a7f4e599579b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCippFunction.ps1 @@ -0,0 +1,48 @@ +function Invoke-ExecCippFunction { + <# + .SYNOPSIS + Execute a CIPPCore function + .DESCRIPTION + This function is used to execute a CIPPCore function from an HTTP request. This is advanced functionality used for external integrations or SuperAdmin functionality. + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $BlockList = @( + 'Get-GraphToken' + 'Get-GraphTokenFromCert' + 'Get-ClassicAPIToken' + ) + + $Function = $Request.Body.FunctionName + $Params = if ($Request.Body.Parameters) { + $Request.Body.Parameters | ConvertTo-Json -Compress -ErrorAction Stop | ConvertFrom-Json -AsHashtable + } else { + @{} + } + + if (Get-Command -Module CIPPCore -Name $Function -and $BlockList -notcontains $Function) { + try { + $Results = & $Function @Params + if (!$Results) { + $Results = "Function $Function executed successfully" + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $Results = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError + } + } else { + $Results = "Function $Function not found or not allowed" + $StatusCode = [HttpStatusCode]::NotFound + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Results + }) +} \ No newline at end of file diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 index e852991c7c9a..e056a656c402 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecDurableFunctions.ps1 @@ -95,7 +95,7 @@ function Invoke-ExecDurableFunctions { if ($PSCmdlet.ShouldProcess('Orchestrators', 'Mark Failed')) { foreach ($Instance in $RunningInstances) { $Instance.RuntimeStatus = 'Failed' - Update-AzDataTableEntity @InstancesTable -Entity $Instance + Update-AzDataTableEntity -Force @InstancesTable -Entity $Instance } } } @@ -110,7 +110,7 @@ function Invoke-ExecDurableFunctions { } if (($QueueEntities | Measure-Object).Count -gt 0) { if ($PSCmdlet.ShouldProcess('Queues', 'Mark Failed')) { - Update-AzDataTableEntity @QueueTable -Entity $QueueEntities + Update-AzDataTableEntity -Force @QueueTable -Entity $QueueEntities } } @@ -122,7 +122,7 @@ function Invoke-ExecDurableFunctions { $Task.Status = 'Failed' $Task } - Update-AzDataTableEntity @CippQueueTasks -Entity $UpdatedTasks + Update-AzDataTableEntity -Force @CippQueueTasks -Entity $UpdatedTasks } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 index 053395d7d293..0d765e27a478 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 @@ -15,17 +15,19 @@ Function Invoke-ExecEditTemplate { try { $Table = Get-CippTable -tablename 'templates' - $Table.Force = $true $guid = $request.body.guid $JSON = ConvertTo-Json -Compress -Depth 100 -InputObject ($request.body | Select-Object * -ExcludeProperty GUID) - $Type = $request.Query.Type + $Type = $request.Body.Type if ($Type -eq 'IntuneTemplate') { Write-Host 'Intune Template' - Write-Host '' - $RawJSON = $request.body | Select-Object * -ExcludeProperty displayName, description, type, GUID | ConvertTo-Json -Depth 10 -Compress - Set-CIPPIntuneTemplate -RawJSON $RawJSON -GUID $GUID -DisplayName $Request.body.displayName -Description $Request.body.description -templateType $Request.body.type + $OriginalTemplate = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'IntuneTemplate' and RowKey eq '$GUID'" + $OriginalTemplate = ($OriginalTemplate.JSON | ConvertFrom-Json -Depth 100) + $RawJSON = $OriginalTemplate.RAWJson + Set-CIPPIntuneTemplate -RawJSON $RawJSON -GUID $GUID -DisplayName $Request.body.displayName -Description $Request.body.description -templateType $OriginalTemplate.Type } else { + $Table.Force = $true + Add-CIPPAzDataTableEntity @Table -Entity @{ JSON = "$JSON" RowKey = "$GUID" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 index 6c252b12c28c..cd3dbc1a42b6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGeoIPLookup.ps1 @@ -12,9 +12,14 @@ Function Invoke-ExecGeoIPLookup { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - Write-Host $Request.Query.IP - $locationInfo = Get-CIPPGeoIPLocation -IP $Request.query.IP + $IP = $Request.Query.IP ?? $Request.Body.IP + if (-not $IP) { + $ErrorMessage = Get-NormalizedError -Message 'IP address is required' + $LocationInfo = $ErrorMessage + } else { + $locationInfo = Get-CIPPGeoIPLocation -IP $IP + } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 index f04ea258bba7..268f91caac18 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 @@ -10,9 +10,24 @@ Function Invoke-ExecListBackup { [CmdletBinding()] param($Request, $TriggerMetadata) - $Result = Get-CIPPBackup -type $Request.query.Type -TenantFilter $Request.query.TenantFilter - if ($request.query.NameOnly) { - $Result = $Result | Select-Object RowKey, timestamp + $CippBackupParams = @{} + if ($Request.Query.Type) { + $CippBackupParams.Type = $Request.Query.Type + } + if ($Request.Query.TenantFilter) { + $CippBackupParams.TenantFilter = $Request.Query.TenantFilter + } + if ($Request.Query.NameOnly) { + $CippBackupParams.NameOnly = $true + } + if ($Request.Query.BackupName) { + $CippBackupParams.Name = $Request.Query.BackupName + } + + $Result = Get-CIPPBackup @CippBackupParams + Write-Host ($Result | ConvertTo-Json) + if ($request.Query.NameOnly) { + $Result = $Result | Select-Object @{Name = 'BackupName'; exp = { $_.RowKey } }, Timestamp | Sort-Object Timestamp -Descending } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'Alerts' -message $request.body.text -Sev $request.body.Severity # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 index 841895a7b16c..ea26ed3aca03 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecPartnerWebhook.ps1 @@ -32,6 +32,10 @@ function Invoke-ExecPartnerWebhook { } } 'CreateSubscription' { + if ($Request.Body.EventType.value) { + $Request.Body.EventType = $Request.Body.EventType.value + } + $BaseURL = ([System.Uri]$Request.Headers.'x-ms-original-url').Host $Webhook = @{ TenantFilter = $env:TenantID @@ -40,6 +44,7 @@ function Invoke-ExecPartnerWebhook { EventType = $Request.Body.EventType ExecutingUser = $Request.Headers.'x-ms-client-principal' } + $Results = New-CIPPGraphSubscription @Webhook $ConfigTable = Get-CIPPTable -TableName Config 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 index 71bdb7a36d59..a2f10c527808 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecServicePrincipals.ps1 @@ -22,7 +22,8 @@ function Invoke-ExecServicePrincipals { 'appId' = $Request.Query.AppId } | ConvertTo-Json -Compress try { - $Results = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body + $ServicePrincipal = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body -NoAuthCheck $true + $Results = "Created service principal for $($ServicePrincipal.displayName) ($($ServicePrincipal.appId))" } catch { $Results = "Unable to create service principal: $($_.Exception.Message)" $Success = $false @@ -39,8 +40,7 @@ function Invoke-ExecServicePrincipals { } elseif ($Request.Query.Id) { $Action = 'Get' $Results = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/servicePrincipals/$($Request.Query.Id)" -tenantid $TenantFilter -NoAuthCheck $true - } - else { + } else { $Action = 'List' $Results = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$orderby=displayName&$count=true' -ComplexFilter -tenantid $TenantFilter -NoAuthCheck $true } @@ -56,6 +56,10 @@ function Invoke-ExecServicePrincipals { 'Success' = $Success } + if ($ServicePrincipal) { + $Metadata.ServicePrincipal = $ServicePrincipal + } + if ($Request.Query.AppId) { $Metadata.AppId = $Request.Query.AppId } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 index 798975625766..84721b1e06c1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSetCIPPAutoBackup.ps1 @@ -10,7 +10,7 @@ Function Invoke-ExecSetCIPPAutoBackup { [CmdletBinding()] param($Request, $TriggerMetadata) $unixtime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds - if ($Request.query.Enabled -eq 'True') { + if ($Request.Body.Enabled -eq 'True') { $Table = Get-CIPPTable -TableName 'ScheduledTasks' $AutomatedCIPPBackupTask = Get-AzDataTableEntity @table -Filter "Name eq 'Automated CIPP Backup'" $task = @{ @@ -20,7 +20,7 @@ Function Invoke-ExecSetCIPPAutoBackup { Remove-AzDataTableEntity -Force @Table -Entity $task | Out-Null $TaskBody = [pscustomobject]@{ - TenantFilter = 'AllTenants' + TenantFilter = 'PartnerTenant' Name = 'Automated CIPP Backup' Command = @{ value = 'New-CIPPBackup' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 index a49abf454b11..49618c428105 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 @@ -20,22 +20,49 @@ Function Invoke-GetCippAlerts { $CIPPVersion = $Request.Query.localversion $Version = Assert-CippVersion -CIPPVersion $CIPPVersion if ($Version.OutOfDateCIPP) { - $Alerts.Add(@{Alert = 'Your CIPP Frontend is out of date. Please update to the latest version. Find more on the following '; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) + $Alerts.Add(@{ + title = 'CIPP Frontend Out of Date' + Alert = 'Your CIPP Frontend is out of date. Please update to the latest version. Find more on the following ' + link = 'https://docs.cipp.app/setup/installation/updating' + type = 'warning' + }) Write-LogMessage -message 'Your CIPP Frontend is out of date. Please update to the latest version' -API 'Updates' -tenant 'All Tenants' -sev Alert } if ($Version.OutOfDateCIPPAPI) { - $Alerts.Add(@{Alert = 'Your CIPP API is out of date. Please update to the latest version. Find more on the following'; link = 'https://docs.cipp.app/setup/installation/updating'; type = 'warning' }) + $Alerts.Add(@{ + title = 'CIPP API Out of Date' + Alert = 'Your CIPP API is out of date. Please update to the latest version. Find more on the following' + link = 'https://docs.cipp.app/setup/installation/updating' + type = 'warning' + }) Write-LogMessage -message 'Your CIPP API is out of date. Please update to the latest version' -API 'Updates' -tenant 'All Tenants' -sev Alert } - if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { $Alerts.Add(@{Alert = 'You have not yet completed your SAM Setup. Please go to the SAM Setup Wizard in settings to connect CIPP to your tenant.'; link = '/cipp/setup'; type = 'warning'; setupCompleted = $false }) } - if ($role -like '*superadmin*') { $Alerts.Add(@{Alert = 'You are logged in under a superadmin account. This account should not be used for normal usage.'; link = 'https://docs.cipp.app/setup/installation/owntenant'; type = 'danger' }) } + if ($env:ApplicationID -eq 'LongApplicationID' -or $null -eq $ENV:ApplicationID) { + $Alerts.Add(@{ + title = 'SAM Setup Incomplete' + Alert = 'You have not yet completed your setup. Please go to the Setup Wizard in Application Settings to connect CIPP to your tenants.' + link = '/cipp/setup' + type = 'warning' + setupCompleted = $false + }) + } + if ($role -like '*superadmin*') { + $Alerts.Add(@{ + title = 'Superadmin Account Warning' + Alert = 'You are logged in under a superadmin account. This account should not be used for normal usage.' + link = 'https://docs.cipp.app/setup/installation/owntenant' + type = 'error' + }) + } if ($env:WEBSITE_RUN_FROM_PACKAGE -ne '1' -and $env:AzureWebJobsStorage -ne 'UseDevelopmentStorage=true') { $Alerts.Add( - @{Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this ' - link = 'https://docs.cipp.app/setup/installation/runfrompackage' - type = 'warning' + @{ + title = 'Function App in Write Mode' + Alert = 'Your Function App is running in write mode. This will cause performance issues and increase cost. Please check this ' + link = 'https://docs.cipp.app/setup/installation/runfrompackage' + type = 'warning' }) } if ($Rows) { $Rows | ForEach-Object { $Alerts.Add($_) } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 new file mode 100644 index 000000000000..017d0b60a2ce --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 @@ -0,0 +1,52 @@ +function Invoke-ListGraphBulkRequest { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Core.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $GraphRequestParams = @{ + tenantid = $Request.Body.tenantFilter + Requests = @() + } + + if ($Request.Body.asapp) { + $GraphRequestParams.asapp = $Request.Body.asApp + } + + $BulkRequests = foreach ($GraphRequest in $Request.Body.requests) { + if ($GraphRequest.method -eq 'GET') { + @{ + id = $GraphRequest.id + url = $GraphRequest.url + method = $GraphRequest.method + } + } + } + + if ($BulkRequests) { + $GraphRequestParams.Requests = @($BulkRequests) + try { + $Body = New-GraphBulkRequest @GraphRequestParams + $Results = @{ + StatusCode = [System.Net.HttpStatusCode]::OK + Body = $Body + } + } catch { + $Results = @{ + StatusCode = [System.Net.HttpStatusCode]::BadRequest + Body = $_.Exception.Message + } + } + } else { + $Results = @{ + StatusCode = [System.Net.HttpStatusCode]::BadRequest + Body = 'No requests found in the body' + } + } + + Push-OutputBinding -Name Response -Value $Results +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 similarity index 91% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 index f656bd541400..45bede27c0b2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 @@ -18,11 +18,11 @@ function Invoke-ListGraphRequest { $Parameters = @{} if ($Request.Query.'$filter') { - $Parameters.'$filter' = $Request.Query.'$filter' -replace '%tenantid%', $env:TenantId + $Parameters.'$filter' = $Request.Query.'$filter' -replace '%tenantid%', $env:TenantID } if (!$Request.Query.'$filter' -and $Request.Query.graphFilter) { - $Parameters.'$filter' = $Request.Query.graphFilter -replace '%tenantid%', $env:TenantId + $Parameters.'$filter' = $Request.Query.graphFilter -replace '%tenantid%', $env:TenantID } if ($Request.Query.'$select') { @@ -120,8 +120,11 @@ function Invoke-ListGraphRequest { try { $Results = Get-GraphRequestList @GraphRequestParams - if ($Results.nextLink -and $Request.Query.NoPagination) { - $Metadata['nextLink'] = $Results.nextLink | Select-Object -Last 1 + if ($Results.nextLink) { + Write-Host "NextLink: $($Results.nextLink | Select-Object -Last 1)" + if ($Request.Query.TenantFilter -ne 'AllTenants') { + $Metadata['nextLink'] = $Results.nextLink | Select-Object -Last 1 + } #Results is an array of objects, so we need to remove the last object before returning $Results = $Results | Select-Object -First ($Results.Count - 1) } @@ -142,7 +145,7 @@ function Invoke-ListGraphRequest { } $StatusCode = [HttpStatusCode]::OK } catch { - $GraphRequestData = "Graph Error: $($_.Exception.Message) - Endpoint: $($Request.Query.Endpoint)" + $GraphRequestData = "Graph Error: $(Get-NormalizedError $_.Exception.Message) - Endpoint: $($Request.Query.Endpoint)" if ($Request.Query.IgnoreErrors) { $StatusCode = [HttpStatusCode]::OK } else { $StatusCode = [HttpStatusCode]::BadRequest } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/invoke-ListEmptyResults.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/invoke-ListEmptyResults.ps1 new file mode 100644 index 000000000000..c0497528c42a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/invoke-ListEmptyResults.ps1 @@ -0,0 +1,19 @@ +using namespace System.Net + +Function invoke-ListEmptyResults { + <# + .FUNCTIONALITY + Entrypoint - Purposely lists an empty result + .ROLE + CIPP.Core + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @() + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionMapping.ps1 index 32a21c2119f4..01558e4c2c9f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionMapping.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionMapping.ps1 @@ -35,12 +35,18 @@ Function Invoke-ExecExtensionMapping { 'HuduFields' { $Body = Get-HuduFieldMapping -CIPPMapping $Table } + 'Sherweb' { + $Body = Get-SherwebMapping -CIPPMapping $Table + } } } try { if ($Request.Query.AddMapping) { switch ($Request.Query.AddMapping) { + 'Sherweb' { + $Body = Set-SherwebMapping -CIPPMapping $Table -APIName $APIName -Request $Request + } 'HaloPSA' { $body = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request } @@ -68,7 +74,7 @@ Function Invoke-ExecExtensionMapping { try { if ($Request.Query.AutoMapping) { switch ($Request.Query.AutoMapping) { - 'NinjaOrgs' { + 'NinjaOne' { $Batch = [PSCustomObject]@{ 'NinjaAction' = 'StartAutoMapping' 'FunctionName' = 'NinjaOneQueue' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionTest.ps1 index 1262ab6260a9..3a61241b5753 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionTest.ps1 @@ -55,9 +55,17 @@ Function Invoke-ExecExtensionTest { $Results = [pscustomobject]@{'Results' = 'Failed to connect to Hudu' } } } + 'Sherweb' { + $token = Get-SherwebAuthentication + $Results = [pscustomobject]@{'Results' = 'Successfully Connected to Sherweb' } + } + 'HIBP' { + $ConnectionTest = Get-HIBPConnectionTest + $Results = [pscustomobject]@{'Results' = 'Successfully Connected to HIBP' } + } } } catch { - $Results = [pscustomobject]@{'Results' = "Failed to connect: $($_.Exception.Message) $($_.InvocationInfo.ScriptLineNumber)" } + $Results = [pscustomobject]@{'Results' = "Failed to connect: $($_.Exception.Message). Line $($_.InvocationInfo.ScriptLineNumber)" } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ListExtensionSync.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ListExtensionSync.ps1 index 8ccf26abd1cc..dd1564a91e73 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ListExtensionSync.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ListExtensionSync.ps1 @@ -50,10 +50,9 @@ Function Invoke-ListExtensionSync { $AllTasksArrayList.Add($TaskEntry) } } - Write-Host ($AllTasksArrayList | ConvertTo-Json -Depth 5 -Compress) - # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = ConvertTo-Json -Depth 5 -InputObject $($AllTasksArrayList) + Body = ConvertTo-Json -Depth 5 -InputObject @($AllTasksArrayList) }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 index 4a3869b56176..e8a5c5575739 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1 @@ -12,18 +12,35 @@ Function Invoke-ListScheduledItems { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' + + $ScheduledItemFilter = [System.Collections.Generic.List[string]]::new() + $ScheduledItemFilter.Add("PartitionKey eq 'ScheduledTask'") + + if ($Request.Query.ShowHidden) { + $ScheduledItemFilter.Add('Hidden eq true') + } else { + $ScheduledItemFilter.Add('Hidden eq false') + } + + if ($Request.Query.Name) { + $ScheduledItemFilter.Add("Name eq '$($Request.Query.Name)'") + } + + $Filter = $ScheduledItemFilter -join ' and ' + + Write-Host "Filter: $Filter" $Table = Get-CIPPTable -TableName 'ScheduledTasks' if ($Request.Query.Showhidden -eq $true) { $HiddenTasks = $false } else { $HiddenTasks = $true } - $Tasks = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'ScheduledTask'" | Where-Object { $_.Hidden -ne $HiddenTasks } + $Tasks = Get-CIPPAzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Hidden -ne $HiddenTasks } if ($Request.Query.Type) { $tasks.Command $Tasks = $Tasks | Where-Object { $_.command -eq $Request.Query.Type } } - + $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList if ($AllowedTenants -notcontains 'AllTenants') { $Tasks = $Tasks | Where-Object -Property TenantId -In $AllowedTenants diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 index 26b0d4153cc3..3fcce60e2d53 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-RemoveScheduledItem.ps1 @@ -14,7 +14,7 @@ Function Invoke-RemoveScheduledItem { $User = $request.headers.'x-ms-client-principal' $task = @{ - RowKey = $Request.Query.ID + RowKey = $Request.Query.id ? $Request.Query.id : $Request.Body.id PartitionKey = 'ScheduledTask' } $Table = Get-CIPPTable -TableName 'ScheduledTasks' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 index 08d9b59cc620..5e3726e5d73f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecAccessChecks.ps1 @@ -14,31 +14,117 @@ Function Invoke-ExecAccessChecks { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Table = Get-CIPPTable -tablename 'AccessChecks' + $LastRun = (Get-Date).ToUniversalTime() + switch ($Request.Query.Type) { + 'Permissions' { + if ($Request.Query.SkipCache -ne 'true' -or $Request.Query.SkipCache -ne $true) { + try { + $Cache = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'AccessPermissions'" + $Results = $Cache.Data | ConvertFrom-Json + } catch { + $Results = $null + } + if (!$Results) { + $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:TenantID -APIName $APINAME -ExecutingUser $Request.Headers.'x-ms-client-principal' + } else { + try { + $LastRun = [DateTime]::SpecifyKind($Cache.Timestamp.DateTime, [DateTimeKind]::Utc) + } catch { + $LastRun = $null + } + } + } else { + $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:TenantID -APIName $APINAME -ExecutingUser $Request.Headers.'x-ms-client-principal' + } + } + 'Tenants' { + $AccessChecks = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'TenantAccessChecks'" + if (!$Request.Body.TenantId) { + try { + $Tenants = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -ne $ENV:TenantID } + $Results = foreach ($Tenant in $Tenants) { + $TenantCheck = $AccessChecks | Where-Object -Property RowKey -EQ $Tenant.customerId | Select-Object -Property Data + $TenantResult = [PSCustomObject]@{ + TenantId = $Tenant.customerId + TenantName = $Tenant.displayName + DefaultDomainName = $Tenant.defaultDomainName + GraphStatus = 'Not run yet' + ExchangeStatus = 'Not run yet' + GDAPRoles = '' + MissingRoles = '' + LastRun = '' + GraphTest = '' + ExchangeTest = '' + } + if ($TenantCheck) { + $Data = @($TenantCheck.Data | ConvertFrom-Json) + $TenantResult.GraphStatus = $Data.GraphStatus + $TenantResult.ExchangeStatus = $Data.ExchangeStatus + $TenantResult.GDAPRoles = $Data.GDAPRoles + $TenantResult.MissingRoles = $Data.MissingRoles + $TenantResult.LastRun = $Data.LastRun + $TenantResult.GraphTest = $Data.GraphTest + $TenantResult.ExchangeTest = $Data.ExchangeTest + } + $TenantResult + } + + $LastRunTime = $AccessChecks | Sort-Object Timestamp | Select-Object -Property Timestamp -Last 1 + try { + $LastRun = [DateTime]::SpecifyKind($LastRunTime.Timestamp.DateTime, [DateTimeKind]::Utc) + } catch { + $LastRun = $null + } + } catch { + Write-Host $_.Exception.Message + $Results = @() + } + } + + if ($Request.Query.SkipCache -eq 'true' -or $Request.Query.SkipCache -eq $true) { + $Message = Test-CIPPAccessTenant -ExecutingUser $Request.Headers.'x-ms-client-principal' + } + + if ($Request.Body.TenantId) { + $Tenant = Get-Tenants -TenantFilter $Request.Body.TenantId + $null = Test-CIPPAccessTenant -Tenant $Tenant.customerId -ExecutingUser $Request.Headers.'x-ms-client-principal' + $Results = "Refreshing tenant $($Tenant.displayName)" + } - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - if ($Request.Query.Permissions -eq 'true') { - if ($Request.Query.Cached -eq 'true') { - $Data = (Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'AccessPermissions'").Data | ConvertFrom-Json - $Results = $Data - } else { - $Results = Test-CIPPAccessPermissions -tenantfilter $ENV:TenantID -APIName $APINAME -ExecutingUser $Request.Headers.'x-ms-client-principal' + } + 'GDAP' { + if (!$Request.Query.SkipCache -eq 'true' -or !$Request.Query.SkipCache -eq $true) { + try { + $Cache = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'GDAPRelationships'" + $Results = $Cache.Data | ConvertFrom-Json + } catch { + $Results = $null + } + if (!$Results) { + $Results = Test-CIPPGDAPRelationships + } else { + try { + $LastRun = [DateTime]::SpecifyKind($Cache.Timestamp.DateTime, [DateTimeKind]::Utc) + } catch { + $LastRun = $null + } + } + } else { + $Results = Test-CIPPGDAPRelationships + } } } - - if ($Request.Query.Tenants -eq 'true') { - $Results = Test-CIPPAccessTenant -TenantCSV $Request.Body.tenantid -ExecutingUser $Request.Headers.'x-ms-client-principal' + $Metadata = @{ + LastRun = $LastRun } - if ($Request.Query.GDAP -eq 'true') { - if ($Request.Query.Cached -eq 'true') { - $Data = (Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'GDAPRelationships'").Data | ConvertFrom-Json - $Results = $Data - } else { - $Results = Test-CIPPGDAPRelationships - } + if ($Message) { + $Metadata.AlertMessage = $Message } - $body = [pscustomobject]@{'Results' = $Results } + $body = [pscustomobject]@{ + 'Results' = $Results + 'Metadata' = $Metadata + } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 index 8fbf7872e3c9..11fbdb4022bd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCPVPermissions.ps1 @@ -15,41 +15,46 @@ Function Invoke-ExecCPVPermissions { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $Tenant = Get-Tenants -IncludeAll | Where-Object -Property customerId -EQ $Request.Query.TenantFilter | Select-Object -First 1 + $Tenant = Get-Tenants -IncludeAll | Where-Object -Property customerId -EQ $Request.Body.TenantFilter | Select-Object -First 1 - Write-Host "Our tenant is $($Tenant.displayName) - $($Tenant.defaultDomainName)" + if ($Tenant) { + Write-Host "Our tenant is $($Tenant.displayName) - $($Tenant.defaultDomainName)" - $TenantFilter = $Request.Query.TenantFilter - $CPVConsentParams = @{ - TenantFilter = $Request.Query.TenantFilter - } - if ($Request.Query.ResetSP -eq 'true') { - $CPVConsentParams.ResetSP = $true - } + $TenantFilter = $Request.Body.TenantFilter + $CPVConsentParams = @{ + TenantFilter = $Request.Body.TenantFilter + } + if ($Request.Query.ResetSP -eq 'true') { + $CPVConsentParams.ResetSP = $true + } - $GraphRequest = try { - if ($TenantFilter -notin @('PartnerTenant', $env:TenantId)) { - Set-CIPPCPVConsent @CPVConsentParams - } else { - $TenantFilter = $env:TenantID - $Tenant = [PSCustomObject]@{ - displayName = '*Partner Tenant' - defaultDomainName = $env:TenantID + $GraphRequest = try { + if ($TenantFilter -notin @('PartnerTenant', $env:TenantID)) { + Set-CIPPCPVConsent @CPVConsentParams + } else { + $TenantFilter = $env:TenantID + $Tenant = [PSCustomObject]@{ + displayName = '*Partner Tenant' + defaultDomainName = $env:TenantID + } } + Add-CIPPApplicationPermission -RequiredResourceAccess 'CIPPDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter + Add-CIPPDelegatedPermission -RequiredResourceAccess 'CIPPDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter + if ($TenantFilter -notin @('PartnerTenant', $env:TenantID)) { + Set-CIPPSAMAdminRoles -TenantFilter $TenantFilter + } + $Success = $true + } catch { + "Failed to update permissions for $($Tenant.displayName): $($_.Exception.Message)" + $Success = $false } - Add-CIPPApplicationPermission -RequiredResourceAccess 'CIPPDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter - Add-CIPPDelegatedPermission -RequiredResourceAccess 'CIPPDefaults' -ApplicationId $ENV:ApplicationID -tenantfilter $TenantFilter - if ($TenantFilter -notin @('PartnerTenant', $env:TenantId)) { - Set-CIPPSAMAdminRoles -TenantFilter $TenantFilter - } - $Success = $true - } catch { - "Failed to update permissions for $($Tenant.displayName): $($_.Exception.Message)" - $Success = $false - } - $Tenant = Get-Tenants -IncludeAll | Where-Object -Property customerId -EQ $TenantFilter | Select-Object -First 1 + $Tenant = Get-Tenants -IncludeAll | Where-Object -Property customerId -EQ $TenantFilter | Select-Object -First 1 + } else { + $GraphRequest = 'Tenant not found' + $Success = $false + } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 index d575cdab9956..aaf16a8c8b10 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecDnsConfig.ps1 @@ -44,8 +44,8 @@ Function Invoke-ExecDnsConfig { switch ($Request.Query.Action) { 'SetConfig' { - if ($Request.Query.Resolver) { - $Resolver = $Request.Query.Resolver + if ($Request.Body.Resolver) { + $Resolver = $Request.Body.Resolver if ($ValidResolvers -contains $Resolver) { try { $Config.Resolver = $Resolver diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 index 063e26bb0d4b..1d554d031aef 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeLicenses.ps1 @@ -53,7 +53,7 @@ Function Invoke-ExecExcludeLicenses { } if ($Request.Query.RemoveExclusion) { - $Filter = "RowKey eq '{0}' and PartitionKey eq 'License'" -f $Request.Query.Guid + $Filter = "RowKey eq '{0}' and PartitionKey eq 'License'" -f $Request.Body.GUID $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity -Force @Table -Entity $Entity Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Removed exclusion $($Request.Query.GUID)" -Sev 'Info' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 index 76c414414905..ccb04d2bceb6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecExcludeTenant.ps1 @@ -11,8 +11,7 @@ Function Invoke-ExecExcludeTenant { param($Request, $TriggerMetadata) 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.' + $user = $request.headers.'x-ms-client-principal' $username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($user)) | ConvertFrom-Json).userDetails $date = (Get-Date).tostring('yyyy-MM-dd') @@ -24,7 +23,7 @@ Function Invoke-ExecExcludeTenant { Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded tenants list' -Sev 'Debug' $body = @($ExcludedTenants) } elseif ($Request.query.ListAll) { - $ExcludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -filter "PartitionKey eq 'Tenants'" + $ExcludedTenants = Get-CIPPAzDataTableEntity @TenantsTable -filter "PartitionKey eq 'Tenants'" | Sort-Object -Property displayName Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message 'got excluded tenants list' -Sev 'Debug' $body = @($ExcludedTenants) } @@ -40,21 +39,19 @@ Function Invoke-ExecExcludeTenant { $Tenant.ExcludeDate = $date $Tenant } - Write-Host ($Excluded | ConvertTo-Json) - Update-AzDataTableEntity @TenantsTable -Entity ([pscustomobject]$Excluded) - #Remove-CIPPCache + Update-AzDataTableEntity -Force @TenantsTable -Entity ([pscustomobject]$Excluded) Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Added exclusion for customer(s): $($Excluded.defaultDomainName -join ',')" -Sev 'Info' $body = [pscustomobject]@{'Results' = "Success. Added exclusions for customer(s): $($Excluded.defaultDomainName -join ',')" } } if ($Request.Query.RemoveExclusion) { - $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $name - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - $Tenant.Excluded = $false - $Tenant.ExcludeUser = '' - $Tenant.ExcludeDate = '' - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - #Remove-CIPPCache + $Tenants = Get-Tenants -IncludeAll | Where-Object { $Request.body.value -contains $_.customerId } + foreach ($Tenant in $Tenants) { + $Tenant.Excluded = $false + $Tenant.ExcludeUser = '' + $Tenant.ExcludeDate = '' + Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant + } Write-LogMessage -API $APINAME -tenant $($name) -user $request.headers.'x-ms-client-principal' -message "Removed exclusion for customer $($name)" -Sev 'Info' $body = [pscustomobject]@{'Results' = "Success. We've removed $name from the excluded tenants." } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 index a7d2ba3511bb..75605662298d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPartnerMode.ps1 @@ -25,9 +25,40 @@ Function Invoke-ExecPartnerMode { RowKey = 'PartnerModeSetting' state = $request.body.TenantMode } -Force + + if ($Request.Body.TenantMode -eq 'default') { + $Table = Get-CippTable -tablename 'Tenants' + $Tenant = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Tenants' and RowKey eq '$($env:TenantID)'" -Property RowKey, PartitionKey, customerId, displayName + if ($Tenant) { + try { + Remove-AzDataTableEntity -Force @Table -Entity $Tenant + } catch { + } + } + } elseif ($Request.Body.TenantMode -eq 'PartnerTenantAvailable') { + $InputObject = [PSCustomObject]@{ + Batch = @( + @{ + FunctionName = 'UpdateTenants' + } + ) + OrchestratorName = 'UpdateTenants' + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @{ results = "Set Tenant mode to $($Request.body.TenantMode)" } + Body = @{ + results = @( + @{ + result = "Set Tenant mode to $($Request.body.TenantMode)" + copyInfo = $null + state = 'info' + } + ) + } }) } @@ -43,10 +74,11 @@ Function Invoke-ExecPartnerMode { TenantMode = $CurrentState.state } } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $CurrentState + }) } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $CurrentState - }) } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 index 9f4815e3f25d..25e72a914e82 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPasswordConfig.ps1 @@ -22,14 +22,14 @@ Function Invoke-ExecPasswordConfig { if ($Request.Query.List) { @{ passwordType = $PasswordType.passwordType } } else { - $SchedulerConfig = @{ + $PasswordConfig = @{ 'passwordType' = "$($Request.Body.passwordType)" 'passwordCount' = '12' 'PartitionKey' = 'settings' 'RowKey' = 'settings' } - Add-CIPPAzDataTableEntity @Table -Entity $SchedulerConfig -Force | Out-Null + Add-CIPPAzDataTableEntity @Table -Entity $PasswordConfig -Force | Out-Null 'Successfully set the configuration' } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPermissionRepair.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPermissionRepair.ps1 new file mode 100644 index 000000000000..8f629db28e81 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecPermissionRepair.ps1 @@ -0,0 +1,89 @@ +function Invoke-ExecPermissionRepair { + <# + .SYNOPSIS + This endpoint will update the CIPP-SAM app permissions. + .DESCRIPTION + Merges new permissions from the SAM manifest into the AppPermissions entry for CIPP-SAM. + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.AppSettings.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + try { + $Table = Get-CippTable -tablename 'AppPermissions' + $User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json + + $CurrentPermissions = Get-CippSamPermissions + if (($CurrentPermissions.MissingPermissions | Measure-Object).Count -gt 0) { + Write-Information 'Missing permissions found' + $MissingPermissions = $CurrentPermissions.MissingPermissions + $Permissions = $CurrentPermissions.Permissions + + $AppIds = @($Permissions.PSObject.Properties.Name + $MissingPermissions.PSObject.Properties.Name) + + $NewPermissions = @{} + foreach ($AppId in $AppIds) { + $ApplicationPermissions = [system.collections.generic.list[object]]::new() + $DelegatedPermissions = [system.collections.generic.list[object]]::new() + + # App permissions + foreach ($Permission in $Permissions.$AppId.applicationPermissions) { + $ApplicationPermissions.Add($Permission) + } + if (($MissingPermissions.$AppId.applicationPermissions | Measure-Object).Count -gt 0) { + foreach ($MissingPermission in $MissingPermissions.$AppId.applicationPermissions) { + Write-Host "Adding missing permission: $MissingPermission" + $ApplicationPermissions.Add($MissingPermission) + } + } + + # Delegated permissions + foreach ($Permission in $Permissions.$AppId.delegatedPermissions) { + $DelegatedPermissions.Add($Permission) + } + if (($MissingPermissions.$AppId.delegatedPermissions | Measure-Object).Count -gt 0) { + foreach ($MissingPermission in $MissingPermissions.$AppId.delegatedPermissions) { + Write-Host "Adding missing permission: $MissingPermission" + $DelegatedPermissions.Add($MissingPermission) + } + } + # New permission object + $NewPermissions.$AppId = @{ + applicationPermissions = @($ApplicationPermissions | Sort-Object -Property label) + delegatedPermissions = @($DelegatedPermissions | Sort-Object -Property label) + } + } + + + $Entity = @{ + 'PartitionKey' = 'CIPP-SAM' + 'RowKey' = 'CIPP-SAM' + 'Permissions' = [string]([PSCustomObject]$NewPermissions | ConvertTo-Json -Depth 10 -Compress) + 'UpdatedBy' = $User.UserDetails ?? 'CIPP-API' + } + $Table = Get-CIPPTable -TableName 'AppPermissions' + $null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + + $Body = @{ + 'Results' = 'Permissions Updated' + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'ExecPermissionRepair' -message 'CIPP-SAM Permissions Updated' -Sev 'Info' -LogData $Permissions + } else { + $Body = @{ + 'Results' = 'No permissions to update' + } + } + } catch { + $Body = @{ + 'Results' = "$($_.Exception.Message) - at line $($_.InvocationInfo.ScriptLineNumber)" + } + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 index 00cb9bd38a36..e07e8e139dca 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecRestoreBackup.ps1 @@ -13,23 +13,45 @@ Function Invoke-ExecRestoreBackup { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' try { - foreach ($line in ($Request.body | ConvertFrom-Json | Select-Object * -ExcludeProperty ETag)) { - Write-Host ($line) - $Table = Get-CippTable -tablename $line.table - $ht2 = @{} - $line.psobject.properties | Where-Object { $_.Name -ne 'table' } | ForEach-Object { $ht2[$_.Name] = [string]$_.Value } - $Table.Entity = $ht2 - Add-CIPPAzDataTableEntity @Table -Force - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' + if ($Request.Body.BackupName -like 'CippBackup_*') { + $Table = Get-CippTable -tablename 'CIPPBackup' + $Backup = Get-CippAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Body.BackupName)'" + if ($Backup) { + $BackupData = $Backup.Backup | ConvertFrom-Json -ErrorAction SilentlyContinue | Select-Object * -ExcludeProperty ETag, Timestamp + $BackupData | ForEach-Object { + $Table = Get-CippTable -tablename $_.table + $ht2 = @{ } + $_.psobject.properties | ForEach-Object { $ht2[$_.Name] = [string]$_.Value } + $Table.Entity = $ht2 + Add-CIPPAzDataTableEntity @Table -Force + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' + $body = [pscustomobject]@{ + 'Results' = 'Successfully restored backup.' + } + } else { + $body = [pscustomobject]@{ + 'Results' = 'Backup not found.' + } + } + } else { + foreach ($line in ($Request.body | Select-Object * -ExcludeProperty ETag, Timestamp)) { + $Table = Get-CippTable -tablename $line.table + $ht2 = @{} + $line.psobject.properties | ForEach-Object { $ht2[$_.Name] = [string]$_.Value } + $Table.Entity = $ht2 + Add-AzDataTableEntity @Table -Force + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Created backup' -Sev 'Debug' - $body = [pscustomobject]@{ - 'Results' = 'Successfully restored backup.' + $body = [pscustomobject]@{ + 'Results' = 'Successfully restored backup.' + } } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create backup: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Backup Creation failed: $($_.Exception.Message)" } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to restore backup: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "Backup restore failed: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecWebhookSubscriptions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecWebhookSubscriptions.ps1 index 35d6278e4649..c5cf687c5fc9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecWebhookSubscriptions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecWebhookSubscriptions.ps1 @@ -3,7 +3,7 @@ function Invoke-ExecWebhookSubscriptions { .FUNCTIONALITY Entrypoint .ROLE - Tenant.Alerts.ReadWrite + Tenant.Alert.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) @@ -60,6 +60,26 @@ function Invoke-ExecWebhookSubscriptions { }) } } + 'UnsubscribeAll' { + $TenantList = Get-Tenants -IncludeErrors + $Results = foreach ($tenant in $TenantList) { + $TenantFilter = $tenant.defaultDomainName + $Subscriptions = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscriptions' -tenantid $TenantFilter | Where-Object { $_.notificationUrl -like '*PublicWebhooks*' } + "Unsubscribing from all CIPP subscriptions for $TenantFilter - $($Subscriptions.Count) subscriptions found" + $Subscriptions | ForEach-Object { + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/subscriptions/$($_.id)" -tenantid $TenantFilter -type DELETE -body {} -Verbose + # get row from table if exists and remove + $Webhook = Get-AzDataTableEntity @Table -Filter "WebhookNotificationUrl eq 'https://graph.microsoft.com/beta/subscriptions/$($_.id)'" -Property PartitionKey, RowKey, ETag + if ($Webhook) { + $null = Remove-AzDataTableEntity -Force @Table -Entity $Webhook + } + } + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = $Results } + }) + } 'Resubscribe' { Write-Host "Resubscribing to $($Request.Query.WebhookID)" $Row = Get-AzDataTableEntity @Table -Filter "RowKey eq '$($Request.Query.WebhookID)'" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 index b480e9222627..e5f8029c7df8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSAMSetup.ps1 @@ -119,30 +119,33 @@ Function Invoke-ExecSAMSetup { PartitionKey = 'setup' validated = $false SamSetup = 'NotStarted' - partnersetup = $false + partnersetup = $true appid = 'NotStarted' tenantid = 'NotStarted' } Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-10) - - if ($Request.Query.partnersetup) { - $SetupPhase = $Rows.partnersetup = $true - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - } $step = 1 $DeviceLogon = New-DeviceLogin -clientid '1b730954-1685-4b74-9bfd-dac224a7b894' -Scope 'https://graph.microsoft.com/.default' -FirstLogon $SetupPhase = $rows.SamSetup = [string]($DeviceLogon | ConvertTo-Json) Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null - $Results = @{ message = "Your code is $($DeviceLogon.user_code). Enter the code" ; step = $step; url = $DeviceLogon.verification_uri } + $Results = @{ code = $($DeviceLogon.user_code); message = "Your code is $($DeviceLogon.user_code). Enter the code" ; step = $step; url = $DeviceLogon.verification_uri } } if ($Request.Query.CheckSetupProcess -and $Request.Query.step -eq 1) { $SAMSetup = $Rows.SamSetup | ConvertFrom-Json -ErrorAction SilentlyContinue + if ($SamSetup.token_type -eq 'Bearer') { + #sleeping for 10 seconds to allow the token to be created. + Start-Sleep 10 + #nulling the token to force a recheck. + $step = 2 + } $Token = (New-DeviceLogin -clientid '1b730954-1685-4b74-9bfd-dac224a7b894' -Scope 'https://graph.microsoft.com/.default' -device_code $SAMSetup.device_code) + Write-Host "Token is $($token | ConvertTo-Json)" if ($Token.access_token) { $step = 2 + $rows.SamSetup = [string]($Token | ConvertTo-Json) $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 - $PartnerSetup = $Rows.partnersetup + $PartnerSetup = $true $TenantId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/organization' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method GET -ContentType 'application/json').value.id $SetupPhase = $rows.tenantid = [string]($TenantId) Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null @@ -178,24 +181,13 @@ Function Invoke-ExecSAMSetup { } $SPN = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/servicePrincipals' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"appId`": `"$($AppId.appId)`" }" -ContentType 'application/json') Start-Sleep 3 - $GroupID = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(displayName,'AdminAgents')" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method Get -ContentType 'application/json').value.id - Write-Host "Id is $GroupID" - $AddingToAdminAgent = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/groups/$($GroupID)/members/`$ref" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body "{ `"@odata.id`": `"https://graph.microsoft.com/v1.0/directoryObjects/$($SPN.id)`"}" -ContentType 'application/json') - Write-Host 'Added to adminagents' $attempt ++ } catch { $attempt ++ } } until ($attempt -gt 5) - } else { - $app = Get-Content '.\Cache_SAMSetup\SAMManifestNoPartner.json' - $AppId = (Invoke-RestMethod 'https://graph.microsoft.com/v1.0/applications' -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body $app -ContentType 'application/json') - $Rows.appid = [string]($AppId.appId) - Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null } $AppPassword = (Invoke-RestMethod "https://graph.microsoft.com/v1.0/applications/$($AppId.id)/addPassword" -Headers @{ authorization = "Bearer $($Token.access_token)" } -Method POST -Body '{"passwordCredential":{"displayName":"CIPPInstall"}}' -ContentType 'application/json').secretText - - if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $Secret.TenantId = $TenantId $Secret.ApplicationId = $AppId.appId @@ -210,7 +202,7 @@ Function Invoke-ExecSAMSetup { $Results = @{'message' = 'Created application. Waiting 30 seconds for Azure propagation'; step = $step } } else { $step = 1 - $Results = @{ message = "Your code is $($SAMSetup.user_code). Enter the code " ; step = $step; url = $SAMSetup.verification_uri } + $Results = @{ code = $($SAMSetup.user_code); message = "Your code is $($SAMSetup.user_code). Enter the code " ; step = $step; url = $SAMSetup.verification_uri } } } @@ -219,24 +211,20 @@ Function Invoke-ExecSAMSetup { $step = 2 $TenantId = $Rows.tenantid $AppID = $rows.appid - $PartnerSetup = $Rows.partnersetup + $PartnerSetup = $true $SetupPhase = $rows.SamSetup = [string]($FirstLogonRefreshtoken | ConvertTo-Json) Add-CIPPAzDataTableEntity @Table -Entity $Rows -Force | Out-Null $URL = ($Request.headers.'x-ms-original-url').split('?') | Select-Object -First 1 $Validated = $Rows.validated if ($Validated) { $step = 3 } - $Results = @{ message = 'Give the next approval by clicking ' ; step = $step; url = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/authorize?scope=https://graph.microsoft.com/.default+offline_access+openid+profile&response_type=code&client_id=$($appid)&redirect_uri=$($url)" } + $Results = @{ appId = $AppID; message = 'Give the next approval by clicking ' ; step = $step; url = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/authorize?scope=https://graph.microsoft.com/.default+offline_access+openid+profile&response_type=code&client_id=$($appid)&redirect_uri=$($url)" } } 3 { - $step = 4 $Results = @{'message' = 'Received token.'; step = $step } - - } 4 { Remove-AzDataTableEntity -Force @Table -Entity $Rows - $step = 5 $Results = @{'message' = 'setup completed.'; step = $step } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilter.ps1 new file mode 100644 index 000000000000..e36aaea55402 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilter.ps1 @@ -0,0 +1,39 @@ +using namespace System.Net + +Function Invoke-AddConnectionFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.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' + + $RequestParams = $Request.Body.PowerShellCommand | + ConvertFrom-Json | + Select-Object -Property *, @{Name='identity'; Expression={$_.name}} -ExcludeProperty GUID, comments, name + + $Tenants = ($Request.body.selectedTenants).value + $Result = foreach ($Tenantfilter in $tenants) { + try { + $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Set-HostedConnectionFilterPolicy' -cmdParams $RequestParams + "Successfully created Connectionfilter for $tenantfilter." + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Updated Connection filter rule for $($tenantfilter)" -sev Info + } catch { + "Could not create create Connection Filter rule for $($tenantfilter): $($_.Exception.message)" + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Could not create create connection filter rule for $($tenantfilter): $($_.Exception.message)" -sev Error + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{Results = @($Result) } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilterTemplate.ps1 new file mode 100644 index 000000000000..17b1fd994f4b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilterTemplate.ps1 @@ -0,0 +1,54 @@ +using namespace System.Net + +Function Invoke-AddConnectionFilterTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.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' + Write-Host ($request | ConvertTo-Json -Compress) + + try { + $GUID = (New-Guid).GUID + $JSON = if ($request.body.PowerShellCommand) { + Write-Host 'PowerShellCommand' + $request.body.PowerShellCommand | ConvertFrom-Json + } + else { + $GUID = (New-Guid).GUID + ([pscustomobject]$Request.body | Select-Object Name, EnableSafeList, IPAllowList , IPBlockList ) | ForEach-Object { + $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name + $_ | Select-Object -Property $NonEmptyProperties + } + } + $JSON = ($JSON | Select-Object @{n = 'name'; e = { $_.name } }, @{n = 'comments'; e = { $_.comments } }, * | ConvertTo-Json -Depth 10) + $Table = Get-CippTable -tablename 'templates' + $Table.Force = $true + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = "$json" + RowKey = "$GUID" + PartitionKey = 'ConnectionfilterTemplate' + } + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created Connection Filter Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' + $body = [pscustomobject]@{'Results' = 'Successfully added template' } + + } + catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create Connection Filter Template: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = "ConnectionFilter Template Deployment failed: $($_.Exception.Message)" } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 index d1a29a85a67d..6f54028ddeb6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 @@ -16,14 +16,13 @@ Function Invoke-AddExConnector { $ConnectorType = ($Request.body.PowerShellCommand | ConvertFrom-Json).cippConnectorType $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, cippConnectorType, comments - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = ($Request.body.selectedTenants).value $Result = foreach ($Tenantfilter in $tenants) { try { $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams "Successfully created Connector for $Tenantfilter." Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Created Connector for $($Tenantfilter)" -sev 'Info' - } - catch { + } catch { "Could not create created Connector for $($Tenantfilter): $($_.Exception.message)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Tenantfilter -message "Could not create created Connector for $($Tenantfilter): $($_.Exception.message)" -sev 'Error' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 index a27660da63c5..7d267b3c8ac1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 @@ -17,7 +17,7 @@ Function Invoke-AddSpamFilter { $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, comments $RequestPriority = $Request.Body.Priority - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = ($Request.body.selectedTenants).value $Result = foreach ($Tenantfilter in $tenants) { try { $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-HostedContentFilterPolicy' -cmdParams $RequestParams @@ -32,8 +32,7 @@ Function Invoke-AddSpamFilter { $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-HostedContentFilterRule' -cmdParams $ruleparams "Successfully created spamfilter for $tenantfilter." Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Created spamfilter rule for $($tenantfilter)" -sev Info - } - catch { + } catch { "Could not create create spamfilter rule for $($tenantfilter): $($_.Exception.message)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Could not create create spamfilter rule for $($tenantfilter): $($_.Exception.message)" -sev Error } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 index acd265572aa5..fae7f8b60e5f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 @@ -11,31 +11,31 @@ Function Invoke-AddTransportRule { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $ExetutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExetutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, Comments, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications + $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value - $Result = foreach ($Tenantfilter in $tenants) { - $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $Tenantfilter -cmdlet 'Get-TransportRule' -useSystemMailbox $true | Where-Object -Property Identity -EQ $RequestParams.name + $Tenants = ($Request.body.selectedTenants).value + $Result = foreach ($tenantFilter in $tenants) { + $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $tenantFilter -cmdlet 'Get-TransportRule' -useSystemMailbox $true | Where-Object -Property Identity -EQ $RequestParams.name try { if ($Existing) { Write-Host 'Found existing' $RequestParams | Add-Member -NotePropertyValue $RequestParams.name -NotePropertyName Identity - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Set-TransportRule' -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty UseLegacyRegex) -useSystemMailbox $true - "Successfully set transport rule for $tenantfilter." - } - else { + $null = New-ExoRequest -tenantid $tenantFilter -cmdlet 'Set-TransportRule' -cmdParams ($RequestParams | Select-Object -Property * -ExcludeProperty UseLegacyRegex) -useSystemMailbox $true + "Successfully set transport rule for $tenantFilter." + } else { Write-Host 'Creating new' - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-TransportRule' -cmdParams $RequestParams -useSystemMailbox $true - "Successfully created transport rule for $tenantfilter." + $null = New-ExoRequest -tenantid $tenantFilter -cmdlet 'New-TransportRule' -cmdParams $RequestParams -useSystemMailbox $true + "Successfully created transport rule for $tenantFilter." } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Created transport rule for $($tenantfilter)" -sev Info - } - catch { - "Could not create transport rule for $($tenantfilter): $($_.Exception.message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Could not create transport rule for $($tenantfilter). Error:$($_.Exception.message)" -sev Error + Write-LogMessage -user $ExetutingUser -API $APINAME -tenant $tenantFilter -message "Created transport rule for $($tenantFilter)" -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + "Could not create transport rule for $($tenantFilter): $($ErrorMessage.NormalizedError)" + Write-LogMessage -user $ExetutingUser -API $APINAME -tenant $tenantFilter -message "Could not create transport rule for $($tenantFilter). Error:$($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 index 0f7fb738e6ff..9c176d7c8939 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 @@ -11,42 +11,44 @@ Function Invoke-AddTransportTemplate { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - Write-Host ($request | ConvertTo-Json -Compress) + $ExecutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev Debug + Write-Host ($request | ConvertTo-Json -Depth 10 -Compress) try { $GUID = (New-Guid).GUID $JSON = if ($request.body.PowerShellCommand) { Write-Host 'PowerShellCommand' $request.body.PowerShellCommand | ConvertFrom-Json - } - else { - ([pscustomobject]$Request.body | Select-Object Name, ActivationDate, ADComparisonAttribute, ADComparisonOperator, AddManagerAsRecipientType, AddToRecipients, AnyOfCcHeader, AnyOfCcHeaderMemberOf, AnyOfRecipientAddressContainsWords, AnyOfRecipientAddressMatchesPatterns, AnyOfToCcHeader, AnyOfToCcHeaderMemberOf, AnyOfToHeader, AnyOfToHeaderMemberOf, ApplyClassification, ApplyHtmlDisclaimerFallbackAction, ApplyHtmlDisclaimerLocation, ApplyHtmlDisclaimerText, ApplyOME, ApplyRightsProtectionCustomizationTemplate, ApplyRightsProtectionTemplate, AttachmentContainsWords, AttachmentExtensionMatchesWords, AttachmentHasExecutableContent, AttachmentIsPasswordProtected, AttachmentIsUnsupported, AttachmentMatchesPatterns, AttachmentNameMatchesPatterns, AttachmentProcessingLimitExceeded, AttachmentPropertyContainsWords, AttachmentSizeOver, BetweenMemberOf1, BetweenMemberOf2, BlindCopyTo, Comments, Confirm, ContentCharacterSetContainsWords, CopyTo, DeleteMessage, DlpPolicy, DomainController, Enabled, ExceptIfADComparisonAttribute, ExceptIfADComparisonOperator, ExceptIfAnyOfCcHeader, ExceptIfAnyOfCcHeaderMemberOf, ExceptIfAnyOfRecipientAddressContainsWords, ExceptIfAnyOfRecipientAddressMatchesPatterns, ExceptIfAnyOfToCcHeader, ExceptIfAnyOfToCcHeaderMemberOf, ExceptIfAnyOfToHeader, ExceptIfAnyOfToHeaderMemberOf, ExceptIfAttachmentContainsWords, ExceptIfAttachmentExtensionMatchesWords, ExceptIfAttachmentHasExecutableContent, ExceptIfAttachmentIsPasswordProtected, ExceptIfAttachmentIsUnsupported, ExceptIfAttachmentMatchesPatterns, ExceptIfAttachmentNameMatchesPatterns, ExceptIfAttachmentProcessingLimitExceeded, ExceptIfAttachmentPropertyContainsWords, ExceptIfAttachmentSizeOver, ExceptIfBetweenMemberOf1, ExceptIfBetweenMemberOf2, ExceptIfContentCharacterSetContainsWords, ExceptIfFrom, ExceptIfFromAddressContainsWords, ExceptIfFromAddressMatchesPatterns, ExceptIfFromMemberOf, ExceptIfFromScope, ExceptIfHasClassification, ExceptIfHasNoClassification, ExceptIfHasSenderOverride, ExceptIfHeaderContainsMessageHeader, ExceptIfHeaderContainsWords, ExceptIfHeaderMatchesMessageHeader, ExceptIfHeaderMatchesPatterns, ExceptIfManagerAddresses, ExceptIfManagerForEvaluatedUser, ExceptIfMessageContainsDataClassifications, ExceptIfMessageSizeOver, ExceptIfMessageTypeMatches, ExceptIfRecipientADAttributeContainsWords, ExceptIfRecipientADAttributeMatchesPatterns, ExceptIfRecipientAddressContainsWords, ExceptIfRecipientAddressMatchesPatterns, ExceptIfRecipientDomainIs, ExceptIfRecipientInSenderList, ExceptIfSCLOver, ExceptIfSenderADAttributeContainsWords, ExceptIfSenderADAttributeMatchesPatterns, ExceptIfSenderDomainIs, ExceptIfSenderInRecipientList, ExceptIfSenderIpRanges, ExceptIfSenderManagementRelationship, ExceptIfSentTo, ExceptIfSentToMemberOf, ExceptIfSentToScope, ExceptIfSubjectContainsWords, ExceptIfSubjectMatchesPatterns, ExceptIfSubjectOrBodyContainsWords, ExceptIfSubjectOrBodyMatchesPatterns, ExceptIfWithImportance, ExpiryDate, From, FromAddressContainsWords, FromAddressMatchesPatterns, FromMemberOf, FromScope, GenerateIncidentReport, GenerateNotification, HasClassification, HasNoClassification, HasSenderOverride, HeaderContainsMessageHeader, HeaderContainsWords, HeaderMatchesMessageHeader, HeaderMatchesPatterns, IncidentReportContent, IncidentReportOriginalMail, LogEventText, ManagerAddresses, ManagerForEvaluatedUser, MessageContainsDataClassifications, MessageSizeOver, MessageTypeMatches, Mode, ModerateMessageByManager, ModerateMessageByUser, NotifySender, PrependSubject, Quarantine, RecipientADAttributeContainsWords, RecipientADAttributeMatchesPatterns, RecipientAddressContainsWords, RecipientAddressMatchesPatterns, RecipientAddressType, RecipientDomainIs, RecipientInSenderList, RedirectMessageTo, RejectMessageEnhancedStatusCode, RejectMessageReasonText, RemoveHeader, RemoveOME, RemoveOMEv2, RemoveRMSAttachmentEncryption, RouteMessageOutboundConnector, RouteMessageOutboundRequireTls, RuleErrorAction, RuleSubType, SCLOver, SenderADAttributeContainsWords, SenderADAttributeMatchesPatterns, SenderAddressLocation, SenderDomainIs, SenderInRecipientList, SenderIpRanges, SenderManagementRelationship, SentTo, SentToMemberOf, SentToScope, SetAuditSeverity, SetHeaderName, SetHeaderValue, SetSCL, SmtpRejectMessageRejectStatusCode, SmtpRejectMessageRejectText, StopRuleProcessing, SubjectContainsWords, SubjectMatchesPatterns, SubjectOrBodyContainsWords, SubjectOrBodyMatchesPatterns, UseLegacyRegex, WithImportance ) | ForEach-Object { - $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties - } + } else { + ([pscustomobject]$Request.body | Select-Object Name, ActivationDate, ADComparisonAttribute, ADComparisonOperator, AddManagerAsRecipientType, AddToRecipients, AnyOfCcHeader, AnyOfCcHeaderMemberOf, AnyOfRecipientAddressContainsWords, AnyOfRecipientAddressMatchesPatterns, AnyOfToCcHeader, AnyOfToCcHeaderMemberOf, AnyOfToHeader, AnyOfToHeaderMemberOf, ApplyClassification, ApplyHtmlDisclaimerFallbackAction, ApplyHtmlDisclaimerLocation, ApplyHtmlDisclaimerText, ApplyOME, ApplyRightsProtectionCustomizationTemplate, ApplyRightsProtectionTemplate, AttachmentContainsWords, AttachmentExtensionMatchesWords, AttachmentHasExecutableContent, AttachmentIsPasswordProtected, AttachmentIsUnsupported, AttachmentMatchesPatterns, AttachmentNameMatchesPatterns, AttachmentProcessingLimitExceeded, AttachmentPropertyContainsWords, AttachmentSizeOver, BetweenMemberOf1, BetweenMemberOf2, BlindCopyTo, Comments, Confirm, ContentCharacterSetContainsWords, CopyTo, DeleteMessage, DlpPolicy, DomainController, Enabled, ExceptIfADComparisonAttribute, ExceptIfADComparisonOperator, ExceptIfAnyOfCcHeader, ExceptIfAnyOfCcHeaderMemberOf, ExceptIfAnyOfRecipientAddressContainsWords, ExceptIfAnyOfRecipientAddressMatchesPatterns, ExceptIfAnyOfToCcHeader, ExceptIfAnyOfToCcHeaderMemberOf, ExceptIfAnyOfToHeader, ExceptIfAnyOfToHeaderMemberOf, ExceptIfAttachmentContainsWords, ExceptIfAttachmentExtensionMatchesWords, ExceptIfAttachmentHasExecutableContent, ExceptIfAttachmentIsPasswordProtected, ExceptIfAttachmentIsUnsupported, ExceptIfAttachmentMatchesPatterns, ExceptIfAttachmentNameMatchesPatterns, ExceptIfAttachmentProcessingLimitExceeded, ExceptIfAttachmentPropertyContainsWords, ExceptIfAttachmentSizeOver, ExceptIfBetweenMemberOf1, ExceptIfBetweenMemberOf2, ExceptIfContentCharacterSetContainsWords, ExceptIfFrom, ExceptIfFromAddressContainsWords, ExceptIfFromAddressMatchesPatterns, ExceptIfFromMemberOf, ExceptIfFromScope, ExceptIfHasClassification, ExceptIfHasNoClassification, ExceptIfHasSenderOverride, ExceptIfHeaderContainsMessageHeader, ExceptIfHeaderContainsWords, ExceptIfHeaderMatchesMessageHeader, ExceptIfHeaderMatchesPatterns, ExceptIfManagerAddresses, ExceptIfManagerForEvaluatedUser, ExceptIfMessageContainsDataClassifications, ExceptIfMessageSizeOver, ExceptIfMessageTypeMatches, ExceptIfRecipientADAttributeContainsWords, ExceptIfRecipientADAttributeMatchesPatterns, ExceptIfRecipientAddressContainsWords, ExceptIfRecipientAddressMatchesPatterns, ExceptIfRecipientDomainIs, ExceptIfRecipientInSenderList, ExceptIfSCLOver, ExceptIfSenderADAttributeContainsWords, ExceptIfSenderADAttributeMatchesPatterns, ExceptIfSenderDomainIs, ExceptIfSenderInRecipientList, ExceptIfSenderIpRanges, ExceptIfSenderManagementRelationship, ExceptIfSentTo, ExceptIfSentToMemberOf, ExceptIfSentToScope, ExceptIfSubjectContainsWords, ExceptIfSubjectMatchesPatterns, ExceptIfSubjectOrBodyContainsWords, ExceptIfSubjectOrBodyMatchesPatterns, ExceptIfWithImportance, ExpiryDate, From, FromAddressContainsWords, FromAddressMatchesPatterns, FromMemberOf, FromScope, GenerateIncidentReport, GenerateNotification, HasClassification, HasNoClassification, HasSenderOverride, HeaderContainsMessageHeader, HeaderContainsWords, HeaderMatchesMessageHeader, HeaderMatchesPatterns, IncidentReportContent, IncidentReportOriginalMail, LogEventText, ManagerAddresses, ManagerForEvaluatedUser, MessageContainsDataClassifications, MessageSizeOver, MessageTypeMatches, Mode, ModerateMessageByManager, ModerateMessageByUser, NotifySender, PrependSubject, Quarantine, RecipientADAttributeContainsWords, RecipientADAttributeMatchesPatterns, RecipientAddressContainsWords, RecipientAddressMatchesPatterns, RecipientAddressType, RecipientDomainIs, RecipientInSenderList, RedirectMessageTo, RejectMessageEnhancedStatusCode, RejectMessageReasonText, RemoveHeader, RemoveOME, RemoveOMEv2, RemoveRMSAttachmentEncryption, RouteMessageOutboundConnector, RouteMessageOutboundRequireTls, RuleErrorAction, RuleSubType, SCLOver, SenderADAttributeContainsWords, SenderADAttributeMatchesPatterns, SenderAddressLocation, SenderDomainIs, SenderInRecipientList, SenderIpRanges, SenderManagementRelationship, SentTo, SentToMemberOf, SentToScope, SetAuditSeverity, SetHeaderName, SetHeaderValue, SetSCL, SmtpRejectMessageRejectStatusCode, SmtpRejectMessageRejectText, StopRuleProcessing, SubjectContainsWords, SubjectMatchesPatterns, SubjectOrBodyContainsWords, SubjectOrBodyMatchesPatterns, UseLegacyRegex, WithImportance ) | + ForEach-Object { + $NonEmptyProperties = $_.PSObject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name + $_ | Select-Object -Property $NonEmptyProperties + } } $JSON = ($JSON | Select-Object @{n = 'name'; e = { $_.name } }, @{n = 'comments'; e = { $_.comments } }, * | ConvertTo-Json -Depth 10) $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ - JSON = "$json" + JSON = "$JSON" RowKey = "$GUID" PartitionKey = 'TransportTemplate' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created Transport Rule Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' - $body = [pscustomobject]@{'Results' = 'Successfully added template' } - - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create Transport Rule Template: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Intune Template Deployment failed: $($_.Exception.Message)" } + Write-LogMessage -user $ExecutingUser -API $APINAME -message "Created Transport Rule Template $($Request.body.name) with GUID $GUID" -Sev Debug + $body = [pscustomobject]@{'Results' = "Created Transport Rule Template $($Request.body.name) with GUID $GUID" } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $ExecutingUser -API $APINAME -message "Failed to create Transport Rule Template: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $body = [pscustomobject]@{'Results' = "Failed to create Transport Rule Template: $($ErrorMessage.NormalizedError)" } + $StatusCode = [HttpStatusCode]::Forbidden } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode Body = $body }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 index b1c622f621fd..35b181507cda 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 @@ -11,23 +11,22 @@ Function Invoke-EditExConnector { 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 - - - $Params = @{ - Identity = $request.query.guid - } - + Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Tenantfilter = $request.Query.tenantfilter ?? $Request.Body.tenantfilter try { - $state = if ($request.query.state -eq 'enable') { $true } else { $false } - $Params = @{ Identity = $request.query.GUID; Enabled = $state } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Set-$($Request.query.Type)Connector" -cmdParams $params -UseSystemMailbox $true - $Result = "Set Connector $($Request.query.guid) to $($request.query.State)" + $ConnectorState = $Request.Query.State ?? $Request.Body.State + $State = if ($ConnectorState -eq 'enable') { $true } else { $false } + $Guid = $Request.Query.GUID ?? $Request.Body.GUID + $type = $Request.Query.Type ?? $Request.Body.Type + $Params = @{ + Identity = $Guid + Enabled = $State + } + $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Set-$($Type)Connector" -cmdParams $params -UseSystemMailbox $true + $Result = "Set Connector $($Guid) to $($ConnectorState)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Set Connector $($Request.query.guid) to $($request.query.State)" -sev 'Info' - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Failed setting Connector $($Request.query.guid) to $($request.query.State). Error:$($_.Exception.Message)" -Sev 'Error' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantfilter -message "Failed setting Connector $($Guid) to $($ConnectorState). Error:$($_.Exception.Message)" -Sev 'Error' $ErrorMessage = Get-NormalizedError -Message $_.Exception $Result = $ErrorMessage } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 index 52837656b0e0..eb8f57c38f10 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 @@ -11,28 +11,33 @@ Function Invoke-EditTransportRule { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - $User = $request.headers.'x-ms-client-principal' - Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.Query.tenantfilter + $ExecutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.tenantFilter ?? $Request.body.tenantFilter + $Identity = $Request.Query.guid ?? $Request.body.guid + $State = $Request.Query.state ?? $Request.body.state $Params = @{ - Identity = $request.query.guid + Identity = $Identity } try { - $cmdlet = if ($request.query.state -eq 'enable') { 'Enable-TransportRule' } else { 'Disable-TransportRule' } - $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true - $Result = "Set transport rule $($Request.query.guid) to $($request.query.State)" - Write-LogMessage -user $User -API $APINAME -tenant $tenantfilter -message "Set transport rule $($Request.query.guid) to $($request.query.State)" -sev Info + $cmdlet = if ($State -eq 'enable') { 'Enable-TransportRule' } else { 'Disable-TransportRule' } + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true + $Result = "Set transport rule $($Identity) to $($State)" + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $TenantFilter -message $Result -sev Info + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -user $User -API $APINAME -tenant $tenantfilter -message "Failed setting transport rule $($Request.query.guid) to $($request.query.State). Error:$($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $TenantFilter -message "Failed setting transport rule $($Identity) to $($State). Error:$($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage $Result = $ErrorMessage.NormalizedError + $StatusCode = [HttpStatusCode]::Forbidden } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode Body = @{Results = $Result } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 index 56102f3e2f17..fbc9b085a552 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 @@ -11,30 +11,30 @@ Function Invoke-ExecEditCalendarPermissions { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - $User = $Request.headers.'x-ms-client-principal' - Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $UserID = ($Request.query.UserID) - $LoggingName = $Request.query.LoggingName - $UserToGetPermissions = $Request.query.UserToGetPermissions - $Tenantfilter = $Request.Query.tenantfilter - $Permissions = @($Request.query.permissions) - $folderName = $Request.query.folderName + # Extract parameters from query or body + $TenantFilter = if ($Request.query.TenantFilter) { $Request.query.TenantFilter } else { $Request.Body.TenantFilter } + $UserID = if ($Request.query.UserID) { $Request.query.UserID } else { $Request.Body.UserID } + $UserToGetPermissions = if ($Request.query.UserToGetPermissions) { $Request.query.UserToGetPermissions } else { $Request.Body.UserToGetPermissions.value } + $Permissions = if ($Request.query.Permissions) { @($Request.query.Permissions) } else { @($Request.Body.Permissions.value) } + $FolderName = if ($Request.query.FolderName) { $Request.query.FolderName } else { $Request.Body.FolderName } + $RemoveAccess = if ($Request.query.RemoveAccess) { $Request.query.RemoveAccess } else { $Request.Body.RemoveAccess.value } try { - if ($Request.query.removeaccess) { - $Result = Set-CIPPCalendarPermission -UserID $UserID -folderName $folderName -RemoveAccess $Request.query.removeaccess -TenantFilter $TenantFilter -LoggingName $LoggingName + if ($RemoveAccess) { + $result = Set-CIPPCalendarPermission -UserID $UserID -FolderName $FolderName -RemoveAccess $RemoveAccess -TenantFilter $TenantFilter } else { - $Result = Set-CIPPCalendarPermission -UserID $UserID -folderName $folderName -TenantFilter $Tenantfilter -UserToGetPermissions $UserToGetPermissions -LoggingName $LoggingName -Permissions $Permissions + $result = Set-CIPPCalendarPermission -UserID $UserID -FolderName $FolderName -TenantFilter $TenantFilter -UserToGetPermissions $UserToGetPermissions -Permissions $Permissions } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception $Result = $ErrorMessage } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @{Results = $Result } }) - } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 index e64c821acd68..1886cb55375b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 @@ -14,11 +14,11 @@ Function Invoke-ExecEmailForward { $username = $request.body.userid $ForwardingAddress = $request.body.ForwardInternal.value $ForwardingSMTPAddress = $request.body.ForwardExternal - $DisableForwarding = $request.body.disableForwarding + $ForwardOption = $request.body.forwardOption $APIName = $TriggerMetadata.FunctionName [bool]$KeepCopy = if ($request.body.keepCopy -eq 'true') { $true } else { $false } - if ($ForwardingAddress) { + if ($ForwardOption -eq 'internalAddress') { try { Set-CIPPForwarding -userid $username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -Forward $ForwardingAddress -keepCopy $KeepCopy if (-not $request.body.KeepCopy) { @@ -33,7 +33,7 @@ Function Invoke-ExecEmailForward { } } - if ($ForwardingSMTPAddress) { + if ($ForwardOption -eq 'ExternalAddress') { try { Set-CIPPForwarding -userid $username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -forwardingSMTPAddress $ForwardingSMTPAddress -keepCopy $KeepCopy if (-not $request.body.KeepCopy) { @@ -49,7 +49,7 @@ Function Invoke-ExecEmailForward { } - if ($DisableForwarding -eq 'True') { + if ($ForwardOption -eq 'disabled') { try { Set-CIPPForwarding -userid $username -username $username -tenantFilter $Tenantfilter -ExecutingUser $ExecutingUser -APIName $APIName -Disable $true $results = "Disabled Email Forwarding for $($username)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 index 7dac7da9c2fd..145a0ed7c46d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 @@ -11,22 +11,30 @@ Function Invoke-ExecHideFromGAL { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $ExecutingUser = $Request.headers.'x-ms-client-principal' + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + + # Support if the request is a POST or a GET. So to support legacy(GET) and new(POST) requests + $UserId = $Request.Query.ID ?? $Request.body.ID + $TenantFilter = $Request.Query.TenantFilter ?? $Request.body.tenantFilter + $Hidden = -not [string]::IsNullOrWhiteSpace($Request.Query.HideFromGAL) ? [System.Convert]::ToBoolean($Request.Query.HideFromGAL) : [System.Convert]::ToBoolean($Request.body.HideFromGAL) - $TenantFilter = $request.query.tenantfilter Try { - $Hidden = [System.Convert]::ToBoolean($Request.query.HideFromGal) - $HideResults = Set-CIPPHideFromGAL -tenantFilter $tenantFilter -userid $Request.query.ID -HideFromGAL $Hidden -ExecutingUser $request.headers.'x-ms-client-principal' -APIName 'ExecOffboardUser' + $HideResults = Set-CIPPHideFromGAL -tenantFilter $TenantFilter -UserID $UserId -hidefromgal $Hidden -ExecutingUser $ExecutingUser -APIName $APIName $Results = [pscustomobject]@{'Results' = $HideResults } + $StatusCode = [HttpStatusCode]::OK } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Hide/UnHide from GAL failed: $($_.Exception.Message)" -Sev 'Error' + $ErrorMessage = Get-CippException -Exception $_ + $Results = [pscustomobject]@{'Results' = "Failed. $($ErrorMessage.NormalizedError)" } + $StatusCode = [HttpStatusCode]::Forbidden } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode Body = $Results }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 index 7e787acacfc8..fe94e74424a1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 @@ -45,8 +45,8 @@ function Invoke-ExecMailboxRestore { default { $TenantFilter = $Request.Body.TenantFilter $RequestName = $Request.Body.RequestName - $SourceMailbox = $Request.Body.SourceMailbox - $TargetMailbox = if (!$Request.Body.input) {$Request.Body.TargetMailbox} else {$Request.Body.input} + $SourceMailbox = $Request.Body.SourceMailbox.value ?? $Request.Body.SourceMailbox + $TargetMailbox = $Request.Body.TargetMailbox.value ?? $Request.Body.TargetMailbox $ExoRequest = @{ tenantid = $TenantFilter @@ -58,8 +58,32 @@ function Invoke-ExecMailboxRestore { AllowLegacyDNMismatch = $true } } - if ([bool]$Request.Body.AcceptLargeDataLoss -eq $true) { - $ExoRequest.cmdParams.AcceptLargeDataLoss = $true + if ($Request.Body.AssociatedMessagesCopyOption) { + $ExoRequest.cmdParams.AssociatedMessagesCopyOption = $Request.Body.AssociatedMessagesCopyOption.value + } + if ($Request.Body.ExcludeFolders) { + $ExoRequest.cmdParams.ExcludeFolders = $Request.Body.ExcludeFolders.value + } + if ($Request.Body.IncludeFolders) { + $ExoRequest.cmdParams.IncludeFolders = $Request.Body.IncludeFolders.value + } + if ($Request.Body.BatchName) { + $ExoRequest.cmdParams.BatchName = $Request.Body.BatchName + } + if ($Request.Body.CompletedRequestAgeLimit) { + $ExoRequest.cmdParams.CompletedRequestAgeLimit = $Request.Body.CompletedRequestAgeLimit + } + if ($Request.Body.ConflictResolutionOption) { + $ExoRequest.cmdParams.ConflictResolutionOption = $Request.Body.ConflictResolutionOption.value + } + if ($Request.Body.SourceRootFolder) { + $ExoRequest.cmdParams.SourceRootFolder = $Request.Body.SourceRootFolder + } + if ($Request.Body.TargetRootFolder) { + $ExoRequest.cmdParams.TargetRootFolder = $Request.Body.TargetRootFolder + } + if ($Request.Body.TargetType) { + $ExoRequest.cmdParams.TargetType = $Request.Body.TargetType.value } if ([int]$Request.Body.BadItemLimit -gt 0) { $ExoRequest.cmdParams.BadItemLimit = $Request.Body.BadItemLimit @@ -67,7 +91,17 @@ function Invoke-ExecMailboxRestore { if ([int]$Request.Body.LargeItemLimit -gt 0) { $ExoRequest.cmdParams.LargeItemLimit = $Request.Body.LargeItemLimit } + if ($Request.Body.ExcludeDumpster) { + $ExoRequest.cmdParams.ExcludeDumpster = $Request.Body.ExcludeDumpster + } + if ($Request.Body.SourceIsArchive) { + $ExoRequest.cmdParams.SourceIsArchive = $Request.Body.SourceIsArchive + } + if ($Request.Body.TargetIsArchive) { + $ExoRequest.cmdParams.TargetIsArchive = $Request.Body.TargetIsArchive + } + Write-Information ($ExoRequest | ConvertTo-Json) $SuccessMessage = 'Mailbox restore request created successfully' } } @@ -93,4 +127,4 @@ function Invoke-ExecMailboxRestore { StatusCode = $StatusCode Body = $Body }) -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 index e22301a7629c..893302ffb327 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 @@ -11,7 +11,7 @@ Function Invoke-ExecQuarantineManagement { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Write to the Azure Functions log stream. @@ -20,19 +20,19 @@ Function Invoke-ExecQuarantineManagement { # Interact with query parameters or the body of the request. Try { - $tenantfilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Body.tenantFilter $params = @{ - Identity = $request.query.ID - AllowSender = [boolean]$Request.query.AllowSender - ReleasetoAll = [boolean]$Request.query.type - ActionType = $Request.query.type + Identity = $Request.Body.Identity + AllowSender = [boolean]$Request.Body.AllowSender + ReleaseToAll = [boolean]$Request.Body.Type + ActionType = $Request.Body.Type } - Write-Host $params + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Release-QuarantineMessage' -cmdParams $Params - $Results = [pscustomobject]@{'Results' = "Successfully processed $($request.query.ID)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "$($request.query.id)" -Sev 'Info' + $Results = [pscustomobject]@{'Results' = "Successfully processed $($Request.Body.Identity)" } + Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantFilter -message "Successfully processed Quarantine ID $($Request.Body.Identity)" -Sev 'Info' } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message "Quarantine Management failed: $($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantFilter -message "Quarantine Management failed: $($_.Exception.Message)" -Sev 'Error' -LogData $_ $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 index fab2212d888c..612be4253734 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 @@ -3,16 +3,14 @@ using namespace System.Net Function Invoke-ExecSetOoO { <# .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite + Entrypoint #> [CmdletBinding()] param($Request, $TriggerMetadata) try { $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Username = $request.body.user + Write-LogMessage -user $request.headers.'X-MS-CLIENT-PRINCIPAL' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Username = $request.body.userId $Tenantfilter = $request.body.tenantfilter if ($Request.body.input) { $InternalMessage = $Request.body.input @@ -21,24 +19,16 @@ Function Invoke-ExecSetOoO { $InternalMessage = $Request.body.InternalMessage $ExternalMessage = $Request.body.ExternalMessage } - $StartTime = $Request.body.StartTime - $EndTime = $Request.body.EndTime - - $OutOfOffice = @{ - userid = $Request.body.user - InternalMessage = $InternalMessage - ExternalMessage = $ExternalMessage - TenantFilter = $TenantFilter - State = $Request.Body.AutoReplyState - APIName = $APINAME - ExecutingUser = $request.headers.'x-ms-client-principal' - StartTime = $StartTime - EndTime = $EndTime - } - Write-Host ($OutOfOffice | ConvertTo-Json -Depth 10) + #if starttime and endtime are a number, they are unix timestamps and need to be converted to datetime, otherwise just use them. + $StartTime = if ($Request.body.StartTime -match '^\d+$') { [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.body.StartTime).DateTime } else { $Request.body.StartTime } + $EndTime = if ($Request.body.EndTime -match '^\d+$') { [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.body.EndTime).DateTime } else { $Request.body.EndTime } $Results = try { - Set-CIPPOutOfOffice @OutOfOffice + if ($Request.Body.AutoReplyState.value -ne 'Scheduled') { + Set-CIPPOutOfOffice -userid $Username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'X-MS-CLIENT-PRINCIPAL' -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -State $Request.Body.AutoReplyState.value + } else { + Set-CIPPOutOfOffice -userid $Username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'X-MS-CLIENT-PRINCIPAL' -InternalMessage $InternalMessage -ExternalMessage $ExternalMessage -StartTime $StartTime -EndTime $EndTime -State $Request.Body.AutoReplyState.value + } } catch { "Could not add out of office message for $($username). Error: $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilter.ps1 new file mode 100644 index 000000000000..61c62cef6d78 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilter.ps1 @@ -0,0 +1,32 @@ +using namespace System.Net + +Function Invoke-ListConnectionFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.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 { + $Policies = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-HostedConnectionFilterPolicy' | Select-Object * -ExcludeProperty *odata*, *data.type* + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $Policies = $ErrorMessage + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($Policies) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilterTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilterTemplates.ps1 new file mode 100644 index 000000000000..b11f7c512fa8 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilterTemplates.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ListConnectionFilterTemplates { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Table = Get-CippTable -tablename 'templates' + + #List new policies + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'ConnectionfilterTemplate'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { + $GUID = $_.RowKey + $data = $_.JSON | ConvertFrom-Json + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID + $data + } + + if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property RowKey -EQ $Request.query.id } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($Templates) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 index 4fced9c1680e..6e31de2403ce 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 @@ -16,49 +16,76 @@ function Invoke-ListExoRequest { $Tenants = Get-Tenants -IncludeErrors $Tenant = $Tenants | Where-Object { $_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter } if ($Tenant.customerId -in $AllowedTenants -or $AllowedTenants -eq 'AllTenants') { - if ($AllowedVerbs -notcontains $Verb) { - $Body = [pscustomobject]@{ - Results = "Invalid cmdlet: $Cmdlet" + if ($Request.Body.AvailableCmdlets) { + $ExoRequest = @{ + TenantID = $TenantFilter + AvailableCmdlets = $true + } + if ($Request.Body.AsApp -eq $true) { + $ExoRequest.AsApp = $true + } + if ($Request.Body.Compliance -eq $true) { + $ExoRequest.Compliance = $true + } + $Results = New-ExoRequest @ExoRequest + $Body = [PSCustomObject]@{ + Results = $Results | Select-Object @{ Name = 'Cmdlet'; Expression = { $_ } } + Metadata = @{ + Count = ($Results | Measure-Object).Count + } + } + } else { + if ($AllowedVerbs -notcontains $Verb) { + $Body = [pscustomobject]@{ + Results = "Invalid cmdlet: $Cmdlet" + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = $Body + }) + return + } + $ExoParams = @{ + Cmdlet = $Cmdlet + cmdParams = $cmdParams + tenantid = $TenantFilter } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::BadRequest - Body = $Body - }) - return - } - $ExoParams = @{ - Cmdlet = $Cmdlet - cmdParams = $cmdParams - tenantid = $TenantFilter - } - if ($Request.Body.Select) { - $ExoParams.Select = $Request.Body.Select - } + if ($Request.Body.Select) { + $ExoParams.Select = $Request.Body.Select + } - if ($Request.Body.UseSystemMailbox -eq $true) { - $ExoParams.useSystemMailbox = $true - } + if ($Request.Body.UseSystemMailbox -eq $true) { + $ExoParams.useSystemMailbox = $true + } - if ($Request.Body.Anchor) { - $ExoParams.Anchor = $Request.Body.Anchor - } + if ($Request.Body.Anchor) { + $ExoParams.Anchor = $Request.Body.Anchor + } - if ($Request.Body.Compliance -eq $true) { - $ExoParams.Compliance = $true - } + if ($Request.Body.Compliance -eq $true) { + $ExoParams.Compliance = $true + } - if ($Request.Body.AsApp -eq $true) { - $ExoParams.AsApp = $true - } + if ($Request.Body.AsApp -eq $true) { + $ExoParams.AsApp = $true + } - $Results = New-ExoRequest @ExoParams - $Body = [pscustomobject]@{ - Results = $Results - } - } else { - $Body = [pscustomobject]@{ - Results = "Invalid tenant: $TenantFilter" + try { + $Results = New-ExoRequest @ExoParams + $Body = [pscustomobject]@{ + Results = $Results + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Body = [pscustomobject]@{ + Results = @(@{ Error = $ErrorMessage }) + } + } + } else { + $Body = [pscustomobject]@{ + Results = "Invalid tenant: $TenantFilter" + } } } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListGlobalAddressList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListGlobalAddressList.ps1 new file mode 100644 index 000000000000..993f894fed02 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListGlobalAddressList.ps1 @@ -0,0 +1,34 @@ +using namespace System.Net + +Function Invoke-ListGlobalAddressList { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $ExecutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.tenantFilter + + try { + $GAL = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-Recipient' -cmdParams @{ResultSize = 'unlimited'; SortBy = 'DisplayName' } ` + -Select 'Identity, DisplayName, Alias, PrimarySmtpAddress, ExternalDirectoryObjectId, HiddenFromAddressListsEnabled, EmailAddresses, IsDirSynced, SKUAssigned, RecipientType, RecipientTypeDetails, AddressListMembership' | Select-Object -ExcludeProperty *odata*, *data.type* + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $StatusCode = [HttpStatusCode]::Forbidden + $GAL = $ErrorMessage.NormalizedError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GAL) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 index 25a5e57b1e59..9c7c3bc1482e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 @@ -10,26 +10,63 @@ Function Invoke-ListMessageTrace { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + try { + $TenantFilter = $Request.Body.tenantFilter + if ($Request.Body.MessageId) { + $SearchParams = @{ 'MessageId' = $Request.Body.messageId } + } else { + $SearchParams = @{} + if ($Request.Body.days) { + $Days = $Request.Body.days + $SearchParams.StartDate = (Get-Date).AddDays(-$Days).ToUniversalTime().ToString('s') + $SearchParams.EndDate = (Get-Date).ToUniversalTime().ToString('s') + } else { + if ($Request.Body.startDate) { + if ($Request.Body.startDate -match '^\d+$') { + $SearchParams.StartDate = [DateTimeOffset]::FromUnixTimeSeconds([int64]$Request.Body.startDate).UtcDateTime.ToString('s') + } else { + $SearchParams.StartDate = [DateTime]::ParseExact($Request.Body.startDate, 'yyyy-MM-ddTHH:mm:ssZ', $null).ToUniversalTime().ToString('s') + } + } + if ($Request.Body.endDate) { + if ($Request.Body.endDate -match '^\d+$') { + $SearchParams.EndDate = [DateTimeOffset]::FromUnixTimeSeconds([int64]$Request.Body.endDate).UtcDateTime.ToString('s') + } else { + $SearchParams.EndDate = [DateTime]::ParseExact($Request.Body.endDate, 'yyyy-MM-ddTHH:mm:ssZ', $null).ToUniversalTime().ToString('s') + } + } + } - try { - $TenantFilter = $request.query.TenantFilter - $SearchParams = @{ - StartDate = (Get-Date).AddDays( - $($request.query.days)).ToString('s') - EndDate = (Get-Date).ToString('s') + if ($Request.Body.status) { + $SearchParams.Add('Status', $Request.Body.status.value) + } + if (![string]::IsNullOrEmpty($Request.Body.fromIP)) { + $SearchParams.Add('FromIP', $Request.Body.fromIP) + } + if (![string]::IsNullOrEmpty($Request.Body.toIP)) { + $SearchParams.Add('ToIP', $Request.Body.toIP) + } } - if ($null -ne $request.query.recipient) { $Searchparams.Add('RecipientAddress', $($request.query.recipient)) } - if ($null -ne $request.query.sender) { $Searchparams.Add('SenderAddress', $($request.query.sender)) } - $type = $request.query.Tracedetail - $trace = if ($Request.Query.Tracedetail) { - New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MessageTraceDetail' -cmdParams $Searchparams - Get-MessageTraceDetail -MessageTraceId $Request.Query.ID -RecipientAddress $request.query.recipient -erroraction stop | Select-Object Event, Action, Detail, @{ Name = 'Date'; Expression = { $_.Date.Tostring('s') } } + if ($Request.Body.recipient) { + $Searchparams.Add('RecipientAddress', $($Request.Body.recipient.value ?? $Request.Body.recipient)) + } + if ($Request.Body.sender) { + $Searchparams.Add('SenderAddress', $($Request.Body.sender.value ?? $Request.Body.sender)) + } + + $trace = if ($Request.Body.traceDetail) { + $CmdParams = @{ + MessageTraceId = $Request.Body.ID + RecipientAddress = $Request.Body.recipient + } + New-ExoRequest -TenantId $TenantFilter -Cmdlet 'Get-MessageTraceDetail' -CmdParams $CmdParams | Select-Object @{ Name = 'Date'; Expression = { $_.Date.ToString('u') } }, Event, Action, Detail } else { - New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MessageTrace' -cmdParams $Searchparams | Select-Object MessageTraceId, Status, Subject, RecipientAddress, SenderAddress, @{ Name = 'Date'; Expression = { $_.Received.tostring('s') } } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantfilter) -message 'Executed message trace' -Sev 'Info' + Write-Information ($SearchParams | ConvertTo-Json) + + New-ExoRequest -TenantId $TenantFilter -Cmdlet 'Get-MessageTrace' -CmdParams $SearchParams | Select-Object MessageTraceId, Status, Subject, RecipientAddress, SenderAddress, @{ Name = 'Received'; Expression = { $_.Received.ToString('u') } }, FromIP, ToIP + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($TenantFilter) -message 'Executed message trace' -Sev 'Info' } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 index f554fd228f7b..a2320397fa3f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddChocoApp.ps1 @@ -29,7 +29,7 @@ Function Invoke-AddChocoApp { $intunebody.detectionRules[0].path = "$($ENV:SystemDrive)\programdata\chocolatey\lib" $intunebody.detectionRules[0].fileOrFolderName = "$($chocoapp.PackageName)" - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = $Request.body.selectedTenants.defaultDomainName $Results = foreach ($Tenant in $tenants) { try { $CompleteObject = [PSCustomObject]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 index d019dc129e6f..d0e3c340a7b5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddMSPApp.ps1 @@ -24,6 +24,7 @@ Function Invoke-AddMSPApp { $InstallParams = [pscustomobject]$RMMApp.params switch ($rmmapp.RMMName.value) { 'datto' { + Write-Host 'test' $installcommandline = "powershell.exe -executionpolicy bypass .\install.ps1 -URL $($InstallParams.DattoURL) -GUID $($InstallParams.DattoGUID."$($tenant.customerId)")" $UninstallCommandLine = 'powershell.exe -executionpolicy bypass .\uninstall.ps1' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 index e5a73e7dcb6c..907410fbe500 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddOfficeApp.ps1 @@ -14,11 +14,8 @@ Function Invoke-AddOfficeApp { 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.' - # Input bindings are passed in via param block. - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = $Request.body.selectedTenants.defaultDomainName if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants).defaultDomainName } $AssignTo = if ($request.body.Assignto -ne 'on') { $request.body.Assignto } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddStoreApp.ps1 similarity index 95% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddStoreApp.ps1 index f80645694331..ef098ff7b0d8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddWinGetApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-AddStoreApp.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-AddWinGetApp { +Function Invoke-AddStoreApp { <# .FUNCTIONALITY Entrypoint @@ -28,7 +28,7 @@ Function Invoke-AddWinGetApp { } } - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = $Request.body.selectedTenants.defaultDomainName $Results = foreach ($Tenant in $tenants) { try { $CompleteObject = [PSCustomObject]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 index de00263734fd..d57088b5a4e2 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 @@ -20,7 +20,7 @@ function Invoke-ExecAppUpload { } $ProcessorQueue = Get-CIPPTable -TableName 'ProcessorQueue' Add-AzDataTableEntity @ProcessorQueue -Entity $ProcessorFunction -Force - $Results = [pscustomobject]@{'Results' = 'Queueing application upload' } + $Results = [pscustomobject]@{'Results' = 'Application upload job has started. Please check back in 15 minutes or track the logbook for results.' } } } else { try { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 index d74d69cc0074..1e1c57118f14 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAPDevice.ps1 @@ -16,7 +16,7 @@ Function Invoke-AddAPDevice { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $TenantFilter = (Get-Tenants | Where-Object { $_.defaultDomainName -eq $Request.body.TenantFilter }).customerId + $TenantFilter = (Get-Tenants | Where-Object { $_.defaultDomainName -eq $Request.body.TenantFilter.value }).customerId $GroupName = if ($Request.body.Groupname) { $Request.body.Groupname } else { (New-Guid).GUID } Write-Host $GroupName $rawDevices = $request.body.autopilotData @@ -51,7 +51,7 @@ Function Invoke-AddAPDevice { $NewStatus = New-GraphgetRequest -uri "https://api.partnercenter.microsoft.com/v1/$($GraphRequest.Location)" -scope 'https://api.partnercenter.microsoft.com/user_impersonation' } until ($Newstatus.status -eq 'finished' -or $amount -eq 4) if ($NewStatus.status -ne 'finished') { throw 'Could not retrieve status of import - This job might still be running. Check the autopilot device list in 10 minutes for the latest status.' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($Request.body.TenantFilter) -message "Created Autopilot devices group. Group ID is $GroupName" -Sev 'Info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($Request.body.TenantFilter.value) -message "Created Autopilot devices group. Group ID is $GroupName" -Sev 'Info' [PSCustomObject]@{ Status = 'Import Job Completed' @@ -59,10 +59,10 @@ Function Invoke-AddAPDevice { } } catch { [PSCustomObject]@{ - Status = "$($Request.body.TenantFilter): Failed to create autopilot devices. $($_.Exception.Message)" + Status = "$($Request.body.TenantFilter.value): Failed to create autopilot devices. $($_.Exception.Message)" Devices = @() } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($Request.body.TenantFilter) -message "Failed to create autopilot devices. $($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $($Request.body.TenantFilter.value) -message "Failed to create autopilot devices. $($_.Exception.Message)" -Sev 'Error' } $body = [pscustomobject]@{'Results' = $Result } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 index a87a2bcb7824..1c737749e18a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddAutopilotConfig.ps1 @@ -18,7 +18,7 @@ Function Invoke-AddAutopilotConfig { Write-Host 'PowerShell HTTP trigger function processed a request.' # Input bindings are passed in via param block. - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = $Request.body.selectedTenants.value $AssignTo = if ($request.body.Assignto -ne 'on') { $request.body.Assignto } $Profbod = [pscustomobject]$Request.body $usertype = if ($Profbod.NotLocalAdmin -eq 'true') { 'standard' } else { 'administrator' } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 index eaed0e5aba15..22179704004a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-AddEnrollment.ps1 @@ -18,7 +18,7 @@ Function Invoke-AddEnrollment { Write-Host 'PowerShell HTTP trigger function processed a request.' # Input bindings are passed in via param block. - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = $Request.body.selectedTenants.value $Profbod = $Request.body $results = foreach ($Tenant in $tenants) { Set-CIPPDefaultAPEnrollment -TenantFilter $Tenant -ShowProgress $Profbod.ShowProgress -BlockDevice $Profbod.blockDevice -AllowReset $Profbod.AllowReset -EnableLog $Profbod.EnableLog -ErrorMessage $Profbod.ErrorMessage -TimeOutInMinutes $Profbod.TimeOutInMinutes -AllowFail $Profbod.AllowFail -OBEEOnly $Profbod.OBEEOnly diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 index 0ae4d1f13cb0..f4d0e10d2526 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecAssignAPDevice.ps1 @@ -10,24 +10,35 @@ Function Invoke-ExecAssignAPDevice { [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 + $User = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.body.tenantFilter + + try { + $UserObject = $Request.body.user.addedFields + $DeviceObject = $Request.body.device + $SerialNumber = $Request.body.serialNumber $body = @{ - UserPrincipalName = $Request.body.UserPrincipalName - addressableUserName = $Request.body.addressableUserName + userPrincipalName = $UserObject.userPrincipalName + addressableUserName = $UserObject.addressableUserName } | ConvertTo-Json - New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$($request.body.Device)/UpdateDeviceProperties" -tenantid $TenantFilter -body $body -method POST - $Results = "Successfully assigned device to $($Request.body.UserPrincipalName) for $($tenantfilter)" + New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$($DeviceObject)/UpdateDeviceProperties" -tenantid $TenantFilter -body $body -method POST | Out-Null + Write-LogMessage -user $User -API $APINAME -message "Successfully assigned device: $DeviceObject with Serial: $SerialNumber to $($UserObject.userPrincipalName) for $($TenantFilter)" -Sev Info + $Results = "Successfully assigned device: $DeviceObject with Serial: $SerialNumber to $($UserObject.userPrincipalName) for $($TenantFilter)" + $StatusCode = [HttpStatusCode]::OK } catch { - $Results = "Could not $($Request.body.UserPrincipalName) to $($Request.body.device) for $($tenantfilter) Error: $($_.Exception.Message)" + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $User -API $APINAME -message "Could not assign $($UserObject.userPrincipalName) to $($DeviceObject) for $($TenantFilter) Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $Results = "Could not assign $($UserObject.userPrincipalName) to $($DeviceObject) for $($TenantFilter) Error: $($ErrorMessage.NormalizedError)" + $StatusCode = [HttpStatusCode]::BadRequest } $Results = [pscustomobject]@{'Results' = "$results" } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode Body = $Results }) 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 59527aa0dc92..f89edf45c78d 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 @@ -13,7 +13,7 @@ Function Invoke-AddDefenderDeployment { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenants = ($Request.body.selectedTenants).defaultDomainName + $Tenants = ($Request.body.selectedTenants).value if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants).defaultDomainName } $Compliance = $request.body.Compliance $PolicySettings = $request.body.Policy @@ -43,192 +43,195 @@ Function Invoke-AddDefenderDeployment { "$($Tenant): Successfully set Defender Compliance and Reporting settings" } - - $Settings = switch ($PolicySettings) { - { $_.ScanArchives } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowarchivescanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowarchivescanning_1'; settingValueTemplateReference = @{settingValueTemplateId = '9ead75d4-6f30-4bc5-8cc5-ab0f999d79f0' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '7c5c9cde-f74d-4d11-904f-de4c27f72d89' } } } - } { $_.AllowBehavior } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowbehaviormonitoring' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowbehaviormonitoring_1'; settingValueTemplateReference = @{settingValueTemplateId = '905921da-95e2-4a10-9e30-fe5540002ce1' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '8eef615a-1aa0-46f4-a25a-12cbe65de5ab' } } } - } { $_.AllowCloudProtection } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowcloudprotection'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowcloudprotection_1'; settingValueTemplateReference = @{settingValueTemplateId = '16fe8afd-67be-4c50-8619-d535451a500c' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '7da139f1-9b7e-407d-853a-c2e5037cdc70' } } } - } { $_.AllowEmailScanning } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowemailscanning' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowemailscanning_1'; settingValueTemplateReference = @{settingValueTemplateId = 'fdf107fd-e13b-4507-9d8f-db4d93476af9' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'b0d9ee81-de6a-4750-86d7-9397961c9852' } } } - } { $_.AllowFullScanNetwork } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowfullscanonmappednetworkdrives' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowfullscanonmappednetworkdrives_1' ; settingValueTemplateReference = @{settingValueTemplateId = '3e920b10-3773-4ac5-957e-e5573aec6d04' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'dac47505-f072-48d6-9f23-8d93262d58ed' } } } - } { $_.AllowFullScanRemovable } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowfullscanremovabledrivescanning' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowfullscanremovabledrivescanning_1' ; settingValueTemplateReference = @{settingValueTemplateId = '366c5727-629b-4a81-b50b-52f90282fa2c' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'fb36e70b-5bc9-488a-a949-8ea3ac1634d5' } } } - } { $_.AllowIPS } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowintrusionpreventionsystem' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowintrusionpreventionsystem_1'; settingValueTemplateReference = @{settingValueTemplateId = '03738a99-7065-44cb-ba1e-93530ed906a7' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'd47f06e2-5378-43f2-adbc-e924538f1512' } } } - } { $_.AllowDownloadable } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowioavprotection' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowioavprotection_1'; settingValueTemplateReference = @{settingValueTemplateId = 'df4e6cbd-f7ff-41c8-88cd-fa25264a237e' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'fa06231d-aed4-4601-b631-3a37e85b62a0' } } } - } { $_.AllowRealTime } { - @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowrealtimemonitoring'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowrealtimemonitoring_1'; settingValueTemplateReference = @{settingValueTemplateId = '0492c452-1069-4b91-9363-93b8e006ab12' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f0790e28-9231-4d37-8f44-84bb47ca1b3e' } } } - } { $_.AllowNetwork } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowscanningnetworkfiles' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowscanningnetworkfiles_1' ; settingValueTemplateReference = @{settingValueTemplateId = '7b8c858c-a17d-4623-9e20-f34b851670ce' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f8f28442-0a6b-4b52-b42c-d31d9687c1cf' } } } - } { $_.AllowScriptScan } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowscriptscanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowscriptscanning_1'; settingValueTemplateReference = @{settingValueTemplateId = 'ab9e4320-c953-4067-ac9a-be2becd06b4a' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = '000cf176-949c-4c08-a5d4-90ed43718db7' } } } - } { $_.AllowUI } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowuseruiaccess' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowuseruiaccess_1' ; settingValueTemplateReference = @{settingValueTemplateId = '4b6c9739-4449-4006-8e5f-3049136470ea' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '0170a900-b0bc-4ccc-b7ce-dda9be49189b' } } } - } { $_.CheckSig } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_checkforsignaturesbeforerunningscan' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_checkforsignaturesbeforerunningscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = '010779d1-edd4-441d-8034-89ad57a863fe' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = '4fea56e3-7bb6-4ad3-88c6-e364dd2f97b9' } } } - } { $_.DisableCatchupFullScan } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_disablecatchupfullscan'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_disablecatchupfullscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = '1b26092f-48c4-447b-99d4-e9c501542f1c' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f881b08c-f047-40d2-b7d9-3dde7ce9ef64' } } } - } { $_.DisableCatchupQuickScan } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_disablecatchupquickscan' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_disablecatchupquickscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = 'd263ced7-0d23-4095-9326-99c8b3f5d35b' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'dabf6781-9d5d-42da-822a-d4327aa2bdd1' } } } - } { $_.NetworkProtectionBlock } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_enablenetworkprotection' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_enablenetworkprotection_1' ; settingValueTemplateReference = @{settingValueTemplateId = 'ee58fb51-9ae5-408b-9406-b92b643f388a' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f53ab20e-8af6-48f5-9fa1-46863e1e517e' } } } - } { $_.LowCPU } { - @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_enablelowcpupriority' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_enablelowcpupriority_1' ; settingValueTemplateReference = @{settingValueTemplateId = '045a4a13-deee-4e24-9fe4-985c9357680d' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'cdeb96cf-18f5-4477-a710-0ea9ecc618af' } } } + if ($PolicySettings) { + $Settings = switch ($PolicySettings) { + { $_.ScanArchives } { + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowarchivescanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowarchivescanning_1'; settingValueTemplateReference = @{settingValueTemplateId = '9ead75d4-6f30-4bc5-8cc5-ab0f999d79f0' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '7c5c9cde-f74d-4d11-904f-de4c27f72d89' } } } + } { $_.AllowBehavior } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowbehaviormonitoring' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowbehaviormonitoring_1'; settingValueTemplateReference = @{settingValueTemplateId = '905921da-95e2-4a10-9e30-fe5540002ce1' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '8eef615a-1aa0-46f4-a25a-12cbe65de5ab' } } } + } { $_.AllowCloudProtection } { + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowcloudprotection'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowcloudprotection_1'; settingValueTemplateReference = @{settingValueTemplateId = '16fe8afd-67be-4c50-8619-d535451a500c' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '7da139f1-9b7e-407d-853a-c2e5037cdc70' } } } + } { $_.AllowEmailScanning } { + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowemailscanning' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowemailscanning_1'; settingValueTemplateReference = @{settingValueTemplateId = 'fdf107fd-e13b-4507-9d8f-db4d93476af9' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'b0d9ee81-de6a-4750-86d7-9397961c9852' } } } + } { $_.AllowFullScanNetwork } { + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowfullscanonmappednetworkdrives' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowfullscanonmappednetworkdrives_1' ; settingValueTemplateReference = @{settingValueTemplateId = '3e920b10-3773-4ac5-957e-e5573aec6d04' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'dac47505-f072-48d6-9f23-8d93262d58ed' } } } + } { $_.AllowFullScanRemovable } { + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowfullscanremovabledrivescanning' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowfullscanremovabledrivescanning_1' ; settingValueTemplateReference = @{settingValueTemplateId = '366c5727-629b-4a81-b50b-52f90282fa2c' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'fb36e70b-5bc9-488a-a949-8ea3ac1634d5' } } } + } { $_.AllowIPS } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowintrusionpreventionsystem' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowintrusionpreventionsystem_1'; settingValueTemplateReference = @{settingValueTemplateId = '03738a99-7065-44cb-ba1e-93530ed906a7' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'd47f06e2-5378-43f2-adbc-e924538f1512' } } } + } { $_.AllowDownloadable } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowioavprotection' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowioavprotection_1'; settingValueTemplateReference = @{settingValueTemplateId = 'df4e6cbd-f7ff-41c8-88cd-fa25264a237e' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'fa06231d-aed4-4601-b631-3a37e85b62a0' } } } + } { $_.AllowRealTime } { + @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowrealtimemonitoring'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowrealtimemonitoring_1'; settingValueTemplateReference = @{settingValueTemplateId = '0492c452-1069-4b91-9363-93b8e006ab12' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f0790e28-9231-4d37-8f44-84bb47ca1b3e' } } } + } { $_.AllowNetwork } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowscanningnetworkfiles' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_allowscanningnetworkfiles_1' ; settingValueTemplateReference = @{settingValueTemplateId = '7b8c858c-a17d-4623-9e20-f34b851670ce' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f8f28442-0a6b-4b52-b42c-d31d9687c1cf' } } } + } { $_.AllowScriptScan } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowscriptscanning'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowscriptscanning_1'; settingValueTemplateReference = @{settingValueTemplateId = 'ab9e4320-c953-4067-ac9a-be2becd06b4a' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = '000cf176-949c-4c08-a5d4-90ed43718db7' } } } + } { $_.AllowUI } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_allowuseruiaccess' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_allowuseruiaccess_1' ; settingValueTemplateReference = @{settingValueTemplateId = '4b6c9739-4449-4006-8e5f-3049136470ea' } }; settingInstanceTemplateReference = @{settingInstanceTemplateId = '0170a900-b0bc-4ccc-b7ce-dda9be49189b' } } } + } { $_.CheckSig } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_checkforsignaturesbeforerunningscan' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_checkforsignaturesbeforerunningscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = '010779d1-edd4-441d-8034-89ad57a863fe' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = '4fea56e3-7bb6-4ad3-88c6-e364dd2f97b9' } } } + } { $_.DisableCatchupFullScan } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_disablecatchupfullscan'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_disablecatchupfullscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = '1b26092f-48c4-447b-99d4-e9c501542f1c' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f881b08c-f047-40d2-b7d9-3dde7ce9ef64' } } } + } { $_.DisableCatchupQuickScan } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_disablecatchupquickscan' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_disablecatchupquickscan_1' ; settingValueTemplateReference = @{settingValueTemplateId = 'd263ced7-0d23-4095-9326-99c8b3f5d35b' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'dabf6781-9d5d-42da-822a-d4327aa2bdd1' } } } + } { $_.NetworkProtectionBlock } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting'; settingInstance = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_enablenetworkprotection' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_enablenetworkprotection_1' ; settingValueTemplateReference = @{settingValueTemplateId = 'ee58fb51-9ae5-408b-9406-b92b643f388a' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'f53ab20e-8af6-48f5-9fa1-46863e1e517e' } } } + } { $_.LowCPU } { + @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' ; settingInstance = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_enablelowcpupriority' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_enablelowcpupriority_1' ; settingValueTemplateReference = @{settingValueTemplateId = '045a4a13-deee-4e24-9fe4-985c9357680d' } } ; settingInstanceTemplateReference = @{settingInstanceTemplateId = 'cdeb96cf-18f5-4477-a710-0ea9ecc618af' } } } + } + } + $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant + Write-Host ($CheckExististing | ConvertTo-Json) + if ('Default AV Policy' -in $CheckExististing.Name) { + "$($Tenant): AV Policy already exists. Skipping" + } else { + $PolBody = ConvertTo-Json -Depth 10 -Compress -InputObject @{ + name = 'Default AV Policy' + description = '' + platforms = 'windows10' + technologies = 'mdm,microsoftSense' + roleScopeTagIds = @('0') + templateReference = @{templateId = '804339ad-1553-4478-a742-138fb5807418_1' } + settings = $Settings + } + $PolicyRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $PolBody + if ($PolicySettings.AssignTo -ne 'None') { + $AssignBody = if ($PolicySettings.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($PolicySettings.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } + $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($PolicyRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($PolicySettings.AssignTo)" -Sev 'Info' + } + "$($Tenant): Successfully set Default AV Policy settings" } } - $CheckExististing = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant - Write-Host ($CheckExististing | ConvertTo-Json) - if ('Default AV Policy' -in $CheckExististing.Name) { - "$($Tenant): AV Policy already exists. Skipping" - } else { - $PolBody = ConvertTo-Json -Depth 10 -Compress -InputObject @{ - name = 'Default AV Policy' + if ($ASR) { + $ASRSettings = switch ($ASR) { + { $_.BlockAdobeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_block' } } } + { $_.BlockWin32Macro } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_block' } } } + { $_.BlockCredentialStealing } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_block' } } } + { $_.BlockPSExec } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands_block' } } } + { $_.WMIPersistence } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription_block' } } } + { $_.BlockOfficeExes } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent_block' } } } + { $_.BlockOfficeApps } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses_block' } } } + { $_.BlockYoungExe } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion_block' } } } + { $_.blockJSVB } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent_block' } } } + { $_.blockOfficeComChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses_block' } } } + { $_.blockOfficeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_block' } } } + { $_.BlockUntrustedUSB } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb_block' } } } + { $_.EnableRansomwareVac } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware_block' } } } + { $_.BlockExesMail } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail_block' } } } + { $_.BlockUnsignedDrivers } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers_block' } } } + + } + + + $ASRbody = ConvertTo-Json -Depth 15 -Compress -InputObject @{ + name = 'ASR Default rules' description = '' platforms = 'windows10' technologies = 'mdm,microsoftSense' roleScopeTagIds = @('0') - templateReference = @{templateId = '804339ad-1553-4478-a742-138fb5807418_1' } - settings = $Settings - } - $PolicyRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $PolBody - if ($PolicySettings.AssignTo -ne 'None') { - $AssignBody = if ($PolicySettings.AssignTo -ne 'AllDevicesAndUsers') { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.' + $($PolicySettings.AssignTo) + 'AssignmentTarget"}}]}' } else { '{"assignments":[{"id":"","target":{"@odata.type":"#microsoft.graph.allDevicesAssignmentTarget"}},{"id":"","target":{"@odata.type":"#microsoft.graph.allLicensedUsersAssignmentTarget"}}]}' } - $assign = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($PolicyRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($PolicySettings.AssignTo)" -Sev 'Info' + templateReference = @{templateId = 'e8c053d6-9f95-42b1-a7f1-ebfd71c67a4b_1' } + settings = @(@{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + settingInstance = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' + groupSettingCollectionValue = @(@{children = $asrSettings }) + settingInstanceTemplateReference = @{settingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' } + } + }) } - "$($Tenant): Successfully set Default AV Policy settings" - } - $ASRSettings = switch ($ASR) { - { $_.BlockAdobeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_block' } } } - { $_.BlockWin32Macro } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_block' } } } - { $_.BlockCredentialStealing } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_block' } } } - { $_.BlockPSExec } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockprocesscreationsfrompsexecandwmicommands_block' } } } - { $_.WMIPersistence } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockpersistencethroughwmieventsubscription_block' } } } - { $_.BlockOfficeExes } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfromcreatingexecutablecontent_block' } } } - { $_.BlockOfficeApps } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficeapplicationsfrominjectingcodeintootherprocesses_block' } } } - { $_.BlockYoungExe } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion_block' } } } - { $_.blockJSVB } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent_block' } } } - { $_.blockOfficeComChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses' ; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockofficecommunicationappfromcreatingchildprocesses_block' } } } - { $_.blockOfficeChild } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_block' } } } - { $_.BlockUntrustedUSB } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' ; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockuntrustedunsignedprocessesthatrunfromusb_block' } } } - { $_.EnableRansomwareVac } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware'; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware_block' } } } - { $_.BlockExesMail } { @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail' ; choiceSettingValue = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue' ; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockexecutablecontentfromemailclientandwebmail_block' } } } - { $_.BlockUnsignedDrivers } { @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'; settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers'; choiceSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationchoiceSettingValue'; value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockabuseofexploitedvulnerablesigneddrivers_block' } } } - - } - - - $ASRbody = ConvertTo-Json -Depth 15 -Compress -InputObject @{ - name = 'ASR Default rules' - description = '' - platforms = 'windows10' - technologies = 'mdm,microsoftSense' - roleScopeTagIds = @('0') - templateReference = @{templateId = 'e8c053d6-9f95-42b1-a7f1-ebfd71c67a4b_1' } - settings = @(@{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' - settingInstance = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' - groupSettingCollectionValue = @(@{children = $asrSettings }) - settingInstanceTemplateReference = @{settingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' } - } - }) - } - $CheckExististingASR = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant - if ('ASR Default rules' -in $CheckExististingASR.Name) { - "$($Tenant): ASR Policy already exists. Skipping" - } else { - Write-Host $ASRbody - $ASRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $ASRbody - Write-Host ($ASRRequest.id) - 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('$($ASRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + $CheckExististingASR = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant + if ('ASR Default rules' -in $CheckExististingASR.Name) { + "$($Tenant): ASR Policy already exists. Skipping" + } else { + Write-Host $ASRbody + $ASRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $ASRbody + Write-Host ($ASRRequest.id) + 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('$($ASRRequest.id)')/assign" -tenantid $tenant -type POST -body $AssignBody + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + } + "$($Tenant): Successfully added ASR Settings" } - "$($Tenant): Successfully added ASR Settings" } - - $EDRSettings = switch ($EDR) { - { $_.SampleSharing } { - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' - settingInstance = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_samplesharing' - choiceSettingValue = @{ - settingValueTemplateReference = @{settingValueTemplateId = 'f72c326c-7c5b-4224-b890-0b9b54522bd9' } - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' - 'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_samplesharing_1' + if ($EDR) { + $EDRSettings = switch ($EDR) { + { $_.SampleSharing } { + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + settingInstance = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_samplesharing' + choiceSettingValue = @{ + settingValueTemplateReference = @{settingValueTemplateId = 'f72c326c-7c5b-4224-b890-0b9b54522bd9' } + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + 'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_samplesharing_1' + } + settingInstanceTemplateReference = @{settingInstanceTemplateId = '6998c81e-2814-4f5e-b492-a6159128a97b' } } - settingInstanceTemplateReference = @{settingInstanceTemplateId = '6998c81e-2814-4f5e-b492-a6159128a97b' } } } - } - { $_.Telemetry } { - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' - settingInstance = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_telemetryreportingfrequency' - choiceSettingValue = @{ - settingValueTemplateReference = @{settingValueTemplateId = '350b0bea-b67b-43d4-9a04-c796edb961fd' } - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' - 'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_telemetryreportingfrequency_2' + { $_.Telemetry } { + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + settingInstance = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_telemetryreportingfrequency' + choiceSettingValue = @{ + settingValueTemplateReference = @{settingValueTemplateId = '350b0bea-b67b-43d4-9a04-c796edb961fd' } + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + 'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configuration_telemetryreportingfrequency_2' + } + settingInstanceTemplateReference = @{settingInstanceTemplateId = '03de6095-07c4-4f35-be38-c1cd3bae4484' } } - settingInstanceTemplateReference = @{settingInstanceTemplateId = '03de6095-07c4-4f35-be38-c1cd3bae4484' } } - } - } - { $_.Config } { - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' - settingInstance = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configurationtype' - choiceSettingValue = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' - 'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configurationtype_autofromconnector' - settingValueTemplateReference = @{settingValueTemplateId = 'e5c7c98c-c854-4140-836e-bd22db59d651' } - children = @(@{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' ; settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_onboarding_fromconnector' ; simpleSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSecretSettingValue' ; value = 'Microsoft ATP connector enabled'; valueState = 'NotEncrypted' } } ) + } + { $_.Config } { + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + settingInstance = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_configurationtype' + choiceSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + 'value' = 'device_vendor_msft_windowsadvancedthreatprotection_configurationtype_autofromconnector' + settingValueTemplateReference = @{settingValueTemplateId = 'e5c7c98c-c854-4140-836e-bd22db59d651' } + children = @(@{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' ; settingDefinitionId = 'device_vendor_msft_windowsadvancedthreatprotection_onboarding_fromconnector' ; simpleSettingValue = @{'@odata.type' = '#microsoft.graph.deviceManagementConfigurationSecretSettingValue' ; value = 'Microsoft ATP connector enabled'; valueState = 'NotEncrypted' } } ) + } + + settingInstanceTemplateReference = @{settingInstanceTemplateId = '23ab0ea3-1b12-429a-8ed0-7390cf699160' } } - - settingInstanceTemplateReference = @{settingInstanceTemplateId = '23ab0ea3-1b12-429a-8ed0-7390cf699160' } } - } + } } - } - $EDRbody = ConvertTo-Json -Depth 15 -Compress -InputObject @{ - name = 'EDR Configuration' - description = '' - platforms = 'windows10' - technologies = 'mdm,microsoftSense' - roleScopeTagIds = @('0') - templateReference = @{templateId = '0385b795-0f2f-44ac-8602-9f65bf6adede_1' } - settings = @($EDRSettings) - } - Write-Host ( $EDRbody) - $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 - 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 - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned EDR policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + $EDRbody = ConvertTo-Json -Depth 15 -Compress -InputObject @{ + name = 'EDR Configuration' + description = '' + platforms = 'windows10' + technologies = 'mdm,microsoftSense' + roleScopeTagIds = @('0') + templateReference = @{templateId = '0385b795-0f2f-44ac-8602-9f65bf6adede_1' } + settings = @($EDRSettings) + } + Write-Host ( $EDRbody) + $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 + 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 + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned EDR policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + } + "$($Tenant): Successfully added EDR Settings" } - "$($Tenant): Successfully added EDR Settings" } - } catch { "Failed to add policy for $($Tenant): $($_.Exception.Message)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Failed adding policy $($Displayname). Error: $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 index 847c5f1174c7..884688b42915 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 @@ -38,11 +38,11 @@ Function Invoke-AddIntuneTemplate { $body = [pscustomobject]@{'Results' = 'Successfully added template' } } else { - $TenantFilter = $Request.Query.TenantFilter - $URLName = $Request.Query.URLName - $ID = $Request.Query.id + $TenantFilter = $Request.Body.tenantFilter ?? $Request.Query.tenantFilter + $URLName = $Request.Body.URLName ?? $Request.Query.URLName + $ID = $Request.Body.ID ?? $Request.Query.ID $Template = New-CIPPIntuneTemplate -TenantFilter $TenantFilter -URLName $URLName -ID $ID - + Write-Host "Template: $Template" $object = [PSCustomObject]@{ Displayname = $Template.DisplayName Description = $Template.Description diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 index 9d6865355490..88c4a6136022 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddPolicy.ps1 @@ -13,7 +13,7 @@ Function Invoke-AddPolicy { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenants = ($Request.Body | Select-Object Select_*).psobject.properties.value + $Tenants = ($Request.Body.tenantFilter.value) if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants).defaultDomainName } $displayname = $Request.Body.displayName $description = $Request.Body.Description diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 index 8000d6f46d2f..4af8ca501a15 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecAssignPolicy.ps1 @@ -13,14 +13,14 @@ Function Invoke-ExecAssignPolicy { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenant = $request.query.tenantfilter - $ID = $request.query.id - $displayname = $request.query.Displayname - $AssignTo = if ($request.query.Assignto -ne 'on') { $request.query.Assignto } + $Tenant = $request.body.tenantfilter + $ID = $request.body.id + $displayname = $request.body.Displayname + $AssignTo = if ($request.body.Assignto -ne 'on') { $request.body.Assignto } $results = try { if ($AssignTo) { - $assign = Set-CIPPAssignedPolicy -PolicyId $ID -TenantFilter $tenant -GroupName $AssignTo -Type $Request.query.Type + $assign = Set-CIPPAssignedPolicy -PolicyId $ID -TenantFilter $tenant -GroupName $AssignTo -Type $Request.body.Type Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $AssignTo" -Sev 'Info' } "Successfully edited policy for $($Tenant)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 index ca788cb979da..7d5dfc2b29bc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecDeviceAction.ps1 @@ -13,14 +13,27 @@ Function Invoke-ExecDeviceAction { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Interact with query parameters or the body of the request. + # Interact with Body parameters or the body of the request. try { - if ($Request.Query.Action -eq 'setDeviceName') { + if ($Request.Body.Action -eq 'setDeviceName') { $ActionBody = @{ deviceName = $Request.Body.input } | ConvertTo-Json -Compress } - $ActionResult = New-CIPPDeviceAction -Action $Request.Query.Action -ActionBody $ActionBody -DeviceFilter $Request.Query.GUID -TenantFilter $Request.Query.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' -APINAME $APINAME + else { + $ActionBody = $Request.Body | ConvertTo-Json -Compress + } + + $cmdparams = @{ + Action = $Request.Body.Action + ActionBody = $ActionBody + DeviceFilter = $Request.Body.GUID + TenantFilter = $Request.Body.TenantFilter + ExecutingUser = $request.headers.'x-ms-client-principal' + APINAME = $APINAME + } + $ActionResult = New-CIPPDeviceAction @cmdparams + $body = [pscustomobject]@{'Results' = "$ActionResult" } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 index f2850548e8c2..46af5fc50f77 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetLocalAdminPassword.ps1 @@ -13,7 +13,7 @@ Function Invoke-ExecGetLocalAdminPassword { $APIName = $TriggerMetadata.FunctionName try { - $GraphRequest = Get-CIPPLapsPassword -device $($request.query.guid) -tenantFilter $Request.Query.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $GraphRequest = Get-CIPPLapsPassword -device $($request.body.guid) -tenantFilter $Request.body.TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' $Body = [pscustomobject]@{'Results' = $GraphRequest } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 index 14101947635f..7fd95cdeb8f4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Devices/Invoke-ExecDeviceDelete.ps1 @@ -11,29 +11,28 @@ Function Invoke-ExecDeviceDelete { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Interact with query parameters or the body of the request. + $ExecutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' + # Interact with body parameters or the body of the request. + $TenantFilter = $Request.body.tenantFilter ?? $Request.Query.tenantFilter + $Action = $Request.body.action ?? $Request.Query.action + $DeviceID = $Request.body.ID ?? $Request.Query.ID try { - $url = "https://graph.microsoft.com/beta/devices/$($request.query.id)" - if ($Request.query.action -eq 'delete') { - $ActionResult = New-GraphPOSTRequest -uri $url -type DELETE -tenantid $Request.Query.TenantFilter - } elseif ($Request.query.action -eq 'disable') { - $ActionResult = New-GraphPOSTRequest -uri $url -type PATCH -tenantid $Request.Query.TenantFilter -body '{"accountEnabled": false }' - } elseif ($Request.query.action -eq 'enable') { - $ActionResult = New-GraphPOSTRequest -uri $url -type PATCH -tenantid $Request.Query.TenantFilter -body '{"accountEnabled": true }' - } - Write-Host $ActionResult - $body = [pscustomobject]@{'Results' = "Executed action $($Request.query.action) on $($Request.query.id)" } + $Results = Set-CIPPDeviceState -Action $Action -DeviceID $DeviceID -TenantFilter $TenantFilter -ExecutingUser $ExecutingUser -APIName $APINAME + $StatusCode = [HttpStatusCode]::OK } catch { - $body = [pscustomobject]@{'Results' = "Failed to queue action $($Request.query.action) on $($request.query.id): $($_.Exception.Message)" } + $Results = $_.Exception.Message + $StatusCode = [HttpStatusCode]::BadRequest } + Write-Host $Results + $body = [pscustomobject]@{'Results' = "$Results" } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode Body = $body }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 index 322ed5774b17..69447b0d084b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroup.ps1 @@ -14,14 +14,14 @@ Function Invoke-AddGroup { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $groupobj = $Request.body - $SelectedTenants = if ($Request.body.selectedTenants) { $request.body.selectedTenants.defaultDomainName } else { $Request.body.tenantid } + $SelectedTenants = $request.body.tenantfilter.value ? $request.body.tenantfilter.value : $request.body.tenantfilter if ('AllTenants' -in $SelectedTenants) { $SelectedTenants = (Get-Tenants).defaultDomainName } # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' $results = foreach ($tenant in $SelectedTenants) { try { - $email = if ($groupobj.domain) { "$($groupobj.username)@$($groupobj.domain)" } else { "$($groupobj.username)@$($tenant)" } + $email = if ($groupobj.primDomain.value) { "$($groupobj.username)@$($groupobj.primDomain.value)" } else { "$($groupobj.username)@$($tenant)" } if ($groupobj.groupType -in 'Generic', 'azurerole', 'dynamic', 'm365') { $BodyToship = [pscustomobject] @{ @@ -68,7 +68,7 @@ Function Invoke-AddGroup { } $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params } - $GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params + #$GraphRequest = New-ExoRequest -tenantid $tenant -cmdlet 'New-DistributionGroup' -cmdParams $params # At some point add logic to use AddOwner/AddMember for New-DistributionGroup, but idk how we're going to brr that - rvdwegen } "Successfully created group $($groupobj.displayname) for $($tenant)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 index 6574633a16c7..ba41d2e6ed0d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-AddGroupTemplate.ps1 @@ -20,7 +20,7 @@ Function Invoke-AddGroupTemplate { Displayname = $request.body.displayname Description = $request.body.description groupType = $request.body.groupType - MembershipRules = $request.body.membershipRule + MembershipRules = $request.body.membershipRules allowExternal = $request.body.allowExternal username = $request.body.username GUID = $GUID diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 index 9deb382c2d85..2a56ba875dca 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 @@ -15,57 +15,83 @@ Function Invoke-EditGroup { $Results = [System.Collections.ArrayList]@() $userobj = $Request.body - $GroupType = $userobj.groupType -join ',' - + $GroupType = $userobj.groupId.addedFields.groupType ? $userobj.groupId.addedFields.groupType : $userobj.groupType + $GroupName = $userobj.groupName ? $userobj.groupName : $userobj.groupId.addedFields.groupName # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $AddMembers = ($userobj.Addmember).value + $AddMembers = ($userobj.Addmember).value ?? $userobj.AddMember + $userobj.groupId = $userobj.groupId.value ?? $userobj.groupId + + $TenantId = $userobj.tenantid ?? $userobj.tenantFilter + if ($AddMembers) { $AddMembers | ForEach-Object { try { $member = $_ - if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } - $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $Userobj.tenantid).id + $MemberIDs = 'https://graph.microsoft.com/v1.0/directoryObjects/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($member)" -tenantid $TenantId).id $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $userobj.groupid; Member = $member; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + New-ExoRequest -tenantid $TenantId -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)" -tenantid $Userobj.tenantid -type patch -body $addmemberbody -Verbose + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)" -tenantid $TenantId -type patch -body $addmemberbody -Verbose } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Added $member to $($userobj.groupName) group" -Sev 'Info' - $null = $results.add("Success. $member has been added to $($userobj.groupName)") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Added $member to $($GroupName) group" -Sev 'Info' + $null = $results.add("Success. $member has been added to $($GroupName)") } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to add member $member to $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' - $null = $results.add("Failed to add member $member to $($userobj.groupName): $($_.Exception.Message)") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Failed to add member $member to $($GroupName). Error:$($_.Exception.Message)" -Sev 'Error' + $null = $results.add("Failed to add member $member to $($GroupName): $($_.Exception.Message)") } } } - $AddContacts = ($userobj.AddContacts).value + $AddContacts = ($userobj.AddContact).value if ($AddContacts) { $AddContacts | ForEach-Object { try { $member = $_ - if ($userobj.groupType -eq 'Distribution list' -or $userobj.groupType -eq 'Mail-Enabled Security') { + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $userobj.groupid; Member = $member; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true - Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Added $member to $($userobj.groupName) group" -Sev 'Info' - $null = $results.add("Success. $member has been added to $($userobj.groupName)") + New-ExoRequest -tenantid $TenantId -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + Write-LogMessage -API $APINAME -tenant $TenantId -user $request.headers.'x-ms-client-principal' -message "Added $member to $($GroupName) group" -Sev 'Info' + $null = $results.add("Success. $member has been added to $($GroupName)") } else { - Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message 'You cannot add a contact to a security group' -Sev 'Error' + Write-LogMessage -API $APINAME -tenant $TenantId -user $request.headers.'x-ms-client-principal' -message 'You cannot add a contact to a security group' -Sev 'Error' $null = $results.add('You cannot add a contact to a security group') } } catch { - $null = $results.add("Failed to add member $member to $($userobj.groupName): $($_.Exception.Message)") + $null = $results.add("Failed to add member $member to $($GroupName): $($_.Exception.Message)") } } } + $RemoveContact = ($userobj.RemoveContact).value + try { + if ($RemoveContact) { + $RemoveContact | ForEach-Object { + $member = $_ + if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } + if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { + $Params = @{ Identity = $userobj.groupid; Member = $member ; BypassSecurityGroupManagerCheck = $true } + New-ExoRequest -tenantid $TenantId -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + } else { + $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $TenantId) + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/members/$($MemberInfo.id)/`$ref" -tenantid $TenantId -type DELETE + } + Write-LogMessage -API $APINAME -tenant $TenantId -user $request.headers.'x-ms-client-principal' -message "Removed $member from $($GroupName) group" -Sev 'Info' + $null = $results.add("Success. Member $member has been removed from $($GroupName)") + } + } + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Failed to remove $RemoveContact from $($GroupName). Error:$($_.Exception.Message)" -Sev 'Error' + $null = $results.add("Could not remove $RemoveContact from $($GroupName). $($_.Exception.Message)") + } + + $RemoveMembers = ($userobj.Removemember).value try { if ($RemoveMembers) { @@ -74,18 +100,18 @@ Function Invoke-EditGroup { if ($member -like '*#EXT#*') { $member = [System.Web.HttpUtility]::UrlEncode($member) } if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $userobj.groupid; Member = $member ; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + New-ExoRequest -tenantid $TenantId -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { - $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid) - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/members/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE + $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $TenantId) + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/members/$($MemberInfo.id)/`$ref" -tenantid $TenantId -type DELETE } - Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Removed $member from $($userobj.groupName) group" -Sev 'Info' - $null = $results.add("Success. Member $member has been removed from $($userobj.groupName)") + Write-LogMessage -API $APINAME -tenant $TenantId -user $request.headers.'x-ms-client-principal' -message "Removed $member from $($GroupName) group" -Sev 'Info' + $null = $results.add("Success. Member $member has been removed from $($GroupName)") } } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to remove $RemoveMembers from $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' - $null = $results.add("Could not remove $RemoveMembers from $($userobj.groupName). $($_.Exception.Message)") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Failed to remove $RemoveMembers from $($GroupName). Error:$($_.Exception.Message)" -Sev 'Error' + $null = $results.add("Could not remove $RemoveMembers from $($GroupName). $($_.Exception.Message)") } $AddOwners = $userobj.Addowner.value @@ -93,20 +119,20 @@ Function Invoke-EditGroup { if ($AddOwners) { $AddOwners | ForEach-Object { try { - $ID = 'https://graph.microsoft.com/beta/users/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid).id + $ID = 'https://graph.microsoft.com/beta/users/' + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $TenantId).id Write-Host $ID - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/`$ref" -tenantid $Userobj.tenantid -type POST -body ('{"@odata.id": "' + $ID + '"}') - Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Added owner $_ to $($userobj.groupName) group" -Sev 'Info' - $null = $results.add("Success. $_ has been added $($userobj.groupName)") + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/`$ref" -tenantid $TenantId -type POST -body ('{"@odata.id": "' + $ID + '"}') + Write-LogMessage -API $APINAME -tenant $TenantId -user $request.headers.'x-ms-client-principal' -message "Added owner $_ to $($GroupName) group" -Sev 'Info' + $null = $results.add("Success. $_ has been added $($GroupName)") } catch { - $null = $results.add("Failed to add owner $_ to $($userobj.groupName): Error:$($_.Exception.Message)") + $null = $results.add("Failed to add owner $_ to $($GroupName): Error:$($_.Exception.Message)") } } } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $Userobj.tenantid -API $APINAME -message "Add member API failed. $($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -tenant $TenantId -API $APINAME -message "Add member API failed. $($_.Exception.Message)" -Sev 'Error' } $RemoveOwners = ($userobj.RemoveOwner).value @@ -114,27 +140,27 @@ Function Invoke-EditGroup { if ($RemoveOwners) { $RemoveOwners | ForEach-Object { try { - $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $Userobj.tenantid) - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/$($MemberInfo.id)/`$ref" -tenantid $Userobj.tenantid -type DELETE - Write-LogMessage -API $APINAME -tenant $Userobj.tenantid -user $request.headers.'x-ms-client-principal' -message "Removed $($MemberInfo.UserPrincipalname) from $($userobj.displayname) group" -Sev 'Info' - $null = $results.add("Success. Member $_ has been removed from $($userobj.groupName)") + $MemberInfo = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $TenantId) + New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($userobj.groupid)/owners/$($MemberInfo.id)/`$ref" -tenantid $TenantId -type DELETE + Write-LogMessage -API $APINAME -tenant $TenantId -user $request.headers.'x-ms-client-principal' -message "Removed $($MemberInfo.UserPrincipalname) from $($userobj.displayname) group" -Sev 'Info' + $null = $results.add("Success. Member $_ has been removed from $($GroupName)") } catch { - $null = $results.add("Failed to remove $_ from $($userobj.groupName): $($_.Exception.Message)") + $null = $results.add("Failed to remove $_ from $($GroupName): $($_.Exception.Message)") } } } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to remove $RemoveMembers from $($userobj.groupName). Error:$($_.Exception.Message)" -Sev 'Error' - $body = $results.add("Could not remove $RemoveMembers from $($userobj.groupName). $($_.Exception.Message)") + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Failed to remove $RemoveMembers from $($GroupName). Error:$($_.Exception.Message)" -Sev 'Error' + $body = $results.add("Could not remove $RemoveMembers from $($GroupName). $($_.Exception.Message)") } if ($userobj.allowExternal -eq 'true') { try { - Set-CIPPGroupAuthentication -ID $userobj.mail -GroupType $userobj.groupType -tenantFilter $Userobj.tenantid -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + Set-CIPPGroupAuthentication -ID $userobj.mail -GroupType $GroupType -tenantFilter $TenantId -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' $body = $results.add("Allowed external senders to send to $($userobj.mail).") } catch { $body = $results.add("Failed to allow external senders to send to $($userobj.mail).") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to allow external senders for $($userobj.mail). Error:$($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Failed to allow external senders for $($userobj.mail). Error:$($_.Exception.Message)" -Sev 'Error' } } @@ -142,22 +168,22 @@ Function Invoke-EditGroup { if ($userobj.sendCopies -eq 'true') { try { $Params = @{ Identity = $userobj.Groupid; subscriptionEnabled = $true; AutoSubscribeNewMembers = $true } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Set-UnifiedGroup' -cmdParams $params -useSystemMailbox $true + New-ExoRequest -tenantid $TenantId -cmdlet 'Set-UnifiedGroup' -cmdParams $params -useSystemMailbox $true $MemberParams = @{ Identity = $userobj.Groupid; LinkType = 'members' } - $Members = New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Get-UnifiedGrouplinks' -cmdParams $MemberParams + $Members = New-ExoRequest -tenantid $TenantId -cmdlet 'Get-UnifiedGrouplinks' -cmdParams $MemberParams $MemberSmtpAddresses = $Members | ForEach-Object { $_.PrimarySmtpAddress } $subscriberParams = @{ Identity = $userobj.Groupid; LinkType = 'subscribers'; Links = @($MemberSmtpAddresses) } - New-ExoRequest -tenantid $Userobj.tenantid -cmdlet 'Add-UnifiedGrouplinks' -cmdParams $subscriberParams -Anchor $userobj.mail + New-ExoRequest -tenantid $TenantId -cmdlet 'Add-UnifiedGrouplinks' -cmdParams $subscriberParams -Anchor $userobj.mail $body = $results.add("Send Copies of team emails and events to team members inboxes for $($userobj.mail) enabled.") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Send Copies of team emails and events to team members inboxes for $($userobj.mail) enabled." -Sev 'Info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Send Copies of team emails and events to team members inboxes for $($userobj.mail) enabled." -Sev 'Info' } catch { $body = $results.add("Failed to Send Copies of team emails and events to team members inboxes for $($userobj.mail).") - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $Userobj.tenantid -message "Failed to Send Copies of team emails and events to team members inboxes for $($userobj.mail). Error:$($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $TenantId -message "Failed to Send Copies of team emails and events to team members inboxes for $($userobj.mail). Error:$($_.Exception.Message)" -Sev 'Error' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 index 43e1dc49d393..440d8c3d2865 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddGuest.ps1 @@ -25,8 +25,7 @@ Function Invoke-AddGuest { 'inviteRedirectUrl' = $($userobj.RedirectURL) 'sendInvitationMessage' = [boolean]$userobj.SendInvite } - } - else { + } else { $BodyToship = [pscustomobject] @{ 'InvitedUserDisplayName' = $userobj.Displayname 'InvitedUserEmailAddress' = $($userobj.mail) @@ -35,18 +34,16 @@ Function Invoke-AddGuest { } } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress - $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/invitations' -tenantid $Userobj.tenantid -type POST -body $BodyToship -verbose + $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/invitations' -tenantid $Userobj.tenantFilter -type POST -body $BodyToship -verbose if ($Userobj.sendInvite -eq 'true') { $results.add('Invited Guest. Invite Email sent') - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Invited Guest $($userobj.displayname) with Email Invite " -Sev 'Info' - } - else { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantFilter) -message "Invited Guest $($userobj.displayname) with Email Invite " -Sev 'Info' + } else { $results.add('Invited Guest. No Invite Email was sent') - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Invited Guest $($userobj.displayname) with no Email Invite " -Sev 'Info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantFilter) -message "Invited Guest $($userobj.displayname) with no Email Invite " -Sev 'Info' } - } - catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Guest Invite API failed. $($_.Exception.Message)" -Sev 'Error' + } catch { + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantFilter) -message "Guest Invite API failed. $($_.Exception.Message)" -Sev 'Error' $body = $results.add("Failed to Invite Guest. $($_.Exception.Message)" ) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 index 320a196a0f3a..0d4f7f24a488 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUser.ps1 @@ -17,8 +17,8 @@ Function Invoke-AddUser { if ($UserObj.Scheduled.Enabled) { $TaskBody = [pscustomobject]@{ - TenantFilter = $UserObj.tenantID - Name = "New user creation: $($UserObj.User)@$($UserObj.Domain)" + TenantFilter = $UserObj.tenantfilter + Name = "New user creation: $($UserObj.mailNickname)@$($UserObj.PrimDomain.value)" Command = @{ value = 'New-CIPPUserTask' label = 'New-CIPPUserTask' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 index a0def20c1b22..25150677f7cd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddUserBulk.ps1 @@ -14,7 +14,9 @@ Function Invoke-AddUserBulk { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantFilter = $Request.body.TenantFilter $Body = foreach ($userobj in $request.body.BulkUser) { - Write-Host 'PowerShell HTTP trigger function processed a request.' + if ($userobj.usageLocation.value) { + $userobj.usageLocation = $userobj.usageLocation.value + } try { $password = if ($userobj.password) { $userobj.password } else { New-passwordString } $UserprincipalName = "$($userobj.mailNickName)@$($userobj.domain)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 index 39e018d223df..4ed2b204bfc1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditUser.ps1 @@ -10,11 +10,12 @@ Function Invoke-EditUser { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $ApiName = $TriggerMetadata.FunctionName + $User = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $User -API $ApiName -message 'Accessed this API' -Sev 'Debug' $UserObj = $Request.body - if ($UserObj.UserID -eq '') { + if ($UserObj.id -eq '') { $body = @{'Results' = @('Failed to edit user. No user ID provided') } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::BadRequest @@ -22,8 +23,8 @@ Function Invoke-EditUser { }) return } - $Results = [System.Collections.Generic.List[string]]::new() - $licenses = ($UserObj | Select-Object 'License_*').psobject.properties.value + $Results = [System.Collections.Generic.List[object]]::new() + $licenses = ($UserObj.licenses).value $Aliases = if ($UserObj.AddedAliases) { ($UserObj.AddedAliases) -split '\s' } $AddToGroups = $Request.body.AddToGroups $RemoveFromGroups = $Request.body.RemoveFromGroups @@ -32,77 +33,84 @@ Function Invoke-EditUser { Write-Host 'PowerShell HTTP trigger function processed a request.' #Edit the user try { - Write-Host "$([boolean]$UserObj.mustchangepass)" - $Email = "$($UserObj.Username)@$($UserObj.Domain)" - $UserprincipalName = "$($UserObj.Username)@$($UserObj.Domain)" + Write-Host "$([boolean]$UserObj.MustChangePass)" + $UserPrincipalName = "$($UserObj.Username ? $UserObj.username :$UserObj.mailNickname)@$($UserObj.Domain ? $UserObj.Domain : $UserObj.primDomain.value)" $BodyToship = [pscustomobject] @{ - 'givenName' = $UserObj.firstName - 'surname' = $UserObj.LastName + 'givenName' = $UserObj.givenName + 'surname' = $UserObj.surname + 'accountEnabled' = $true + 'displayName' = $UserObj.displayName + 'department' = $UserObj.Department + 'mailNickname' = $UserObj.Username ? $UserObj.username :$UserObj.mailNickname + 'userPrincipalName' = $UserPrincipalName + 'usageLocation' = $UserObj.usageLocation.value ? $UserObj.usageLocation.value : $UserObj.usageLocation 'city' = $UserObj.City 'country' = $UserObj.Country - 'department' = $UserObj.Department - 'displayName' = $UserObj.DisplayName - 'postalCode' = $UserObj.PostalCode - 'companyName' = $UserObj.CompanyName - 'jobTitle' = $UserObj.JobTitle - 'userPrincipalName' = $Email - 'usageLocation' = $UserObj.usagelocation + 'jobTitle' = $UserObj.jobTitle 'mobilePhone' = $UserObj.MobilePhone 'streetAddress' = $UserObj.streetAddress - 'businessPhones' = @($UserObj.BusinessPhone) + 'postalCode' = $UserObj.PostalCode + 'companyName' = $UserObj.CompanyName + 'otherMails' = $UserObj.otherMails ? @($UserObj.otherMails) : @() 'passwordProfile' = @{ - 'forceChangePasswordNextSignIn' = [boolean]$UserObj.mustchangepass + 'forceChangePasswordNextSignIn' = [bool]$UserObj.MustChangePass } } | ForEach-Object { - $NonEmptyProperties = $_.psobject.Properties | Select-Object -ExpandProperty Name + $NonEmptyProperties = $_.PSObject.Properties | Select-Object -ExpandProperty Name $_ | Select-Object -Property $NonEmptyProperties } if ($UserObj.addedAttributes) { Write-Host 'Found added attribute' Write-Host "Added attributes: $($UserObj.addedAttributes | ConvertTo-Json)" - $UserObj.addedAttributes.getenumerator() | ForEach-Object { - $results.add("Edited property $($_.Key) with value $($_.Value)") + $UserObj.addedAttributes.GetEnumerator() | ForEach-Object { + $null = $results.Add("Edited property $($_.Key) with value $($_.Value)") $bodytoShip | Add-Member -NotePropertyName $_.Key -NotePropertyValue $_.Value -Force } } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)" -tenantid $UserObj.tenantID -type PATCH -body $BodyToship -verbose - $results.add( 'Success. The user has been edited.' ) - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "Edited user $($UserObj.DisplayName) with id $($UserObj.UserID)" -Sev 'Info' + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type PATCH -body $BodyToship -verbose + $null = $results.Add( 'Success. The user has been edited.' ) + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -user $User -message "Edited user $($UserObj.DisplayName) with id $($UserObj.id)" -Sev Info if ($UserObj.password) { - $passwordProfile = [pscustomobject]@{'passwordProfile' = @{ 'password' = $UserObj.password; 'forceChangePasswordNextSignIn' = [boolean]$UserObj.mustchangepass } } | ConvertTo-Json - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)" -tenantid $UserObj.tenantID -type PATCH -body $PasswordProfile -verbose - $results.add("Success. The password has been set to $($UserObj.password)") - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "Reset $($UserObj.DisplayName)'s Password" -Sev 'Info' + $passwordProfile = [pscustomobject]@{'passwordProfile' = @{ 'password' = $UserObj.password; 'forceChangePasswordNextSignIn' = [boolean]$UserObj.MustChangePass } } | ConvertTo-Json + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type PATCH -body $PasswordProfile -verbose + $null = $results.Add("Success. The password has been set to $($UserObj.password)") + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -user $User -message "Reset $($UserObj.DisplayName)'s Password" -Sev Info } } catch { - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "User edit API failed. $($_.Exception.Message)" -Sev 'Error' - $results.add( "Failed to edit user. $($_.Exception.Message)") + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -user $User -message "User edit API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $null = $results.Add( "Failed to edit user. $($ErrorMessage.NormalizedError)") } #Reassign the licenses try { - if ($licenses -or $UserObj.RemoveAllLicenses) { - $licenses = (($UserObj | Select-Object 'License_*').psobject.properties | Where-Object { $_.value -EQ $true }).name -replace 'License_', '' - $CurrentLicenses = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)" -tenantid $UserObj.tenantID - $RemovalList = ($CurrentLicenses.assignedLicenses | Where-Object -Property skuid -NotIn $licenses).skuid - $LicensesToRemove = if ($RemovalList) { ConvertTo-Json @( $RemovalList ) } else { '[]' } - - $liclist = foreach ($license in $Licenses) { '{"disabledPlans": [],"skuId": "' + $license + '" },' } - $LicenseBody = '{"addLicenses": [' + $LicList + '], "removeLicenses": ' + $LicensesToRemove + '}' - if ($UserObj.RemoveAllLicenses) { $LicenseBody = '{"addLicenses": [], "removeLicenses": ' + $LicensesToRemove + '}' } - Write-Host $LicenseBody - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)/assignlicense" -tenantid $UserObj.tenantID -type POST -body $LicenseBody -verbose + if ($licenses -or $UserObj.removeLicenses) { + $CurrentLicenses = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter + #if the list of skuIds in $CurrentLicenses.assignedLicenses is EXACTLY the same as $licenses, we don't need to do anything, but the order in both can be different. + if (($CurrentLicenses.assignedLicenses.skuId -join ',') -eq ($licenses -join ',') -and $UserObj.removeLicenses -eq $false) { + Write-Host "$($CurrentLicenses.assignedLicenses.skuId -join ',') $(($licenses -join ','))" + $null = $results.Add( 'Success. User license is already correct.' ) + } else { + if ($UserObj.removeLicenses) { + $licResults = Set-CIPPUserLicense -UserId $UserObj.id -TenantFilter $UserObj.tenantFilter -RemoveLicenses $CurrentLicenses.assignedLicenses.skuId + $null = $results.Add($licResults) + } else { + #Remove all objects from $CurrentLicenses.assignedLicenses.skuId that are in $licenses + $RemoveLicenses = $CurrentLicenses.assignedLicenses.skuId | Where-Object { $_ -notin $licenses } + $licResults = Set-CIPPUserLicense -UserId $UserObj.id -TenantFilter $UserObj.tenantFilter -RemoveLicenses $RemoveLicenses -AddLicenses $licenses + $null = $results.Add($licResults) + } - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "Changed user $($UserObj.DisplayName) license. Sent info: $licensebody" -Sev 'Info' - $results.add( 'Success. User license has been edited.' ) + } } } catch { - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "License assign API failed. $($_.Exception.Message)" -Sev 'Error' - $results.add( "We've failed to assign the license. $($_.Exception.Message)") + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -user $User -message "License assign API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $null = $results.Add( "We've failed to assign the license. $($ErrorMessage.NormalizedError)") } #Add Aliases, removal currently not supported. @@ -110,21 +118,22 @@ Function Invoke-EditUser { if ($Aliases) { Write-Host ($Aliases | ConvertTo-Json) foreach ($Alias in $Aliases) { - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)" -tenantid $UserObj.tenantID -type 'patch' -body "{`"mail`": `"$Alias`"}" -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type 'patch' -body "{`"mail`": `"$Alias`"}" -Verbose } - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)" -tenantid $UserObj.tenantID -type 'patch' -body "{`"mail`": `"$UserprincipalName`"}" -verbose - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "Added Aliases to $($UserObj.DisplayName)" -Sev 'Info' - $results.add( 'Success. added aliases to user.') + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)" -tenantid $UserObj.tenantFilter -type 'patch' -body "{`"mail`": `"$UserPrincipalName`"}" -Verbose + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -user $User -message "Added Aliases to $($UserObj.DisplayName)" -Sev Info + $null = $results.Add( 'Success. added aliases to user.') } } catch { - Write-LogMessage -API $APINAME -tenant ($UserObj.tenantID) -user $request.headers.'x-ms-client-principal' -message "Alias API failed. $($_.Exception.Message)" -Sev 'Error' - $results.add( "Successfully edited user. The password is $password. We've failed to create the Aliases: $($_.Exception.Message)") + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $ApiName -tenant ($UserObj.tenantFilter) -user $User -message "Alias API failed. $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $null = $results.Add( "Successfully edited user. The password is $password. We've failed to create the Aliases: $($ErrorMessage.NormalizedError)") } - if ($Request.body.CopyFrom -ne '') { - $CopyFrom = Set-CIPPCopyGroupMembers -ExecutingUser $request.headers.'x-ms-client-principal' -CopyFromId $Request.body.CopyFrom -UserID $UserprincipalName -TenantFilter $UserObj.tenantID - $results.AddRange($CopyFrom) + if ($Request.body.CopyFrom.value) { + $CopyFrom = Set-CIPPCopyGroupMembers -ExecutingUser $User -CopyFromId $Request.body.CopyFrom.value -UserID $UserPrincipalName -TenantFilter $UserObj.tenantFilter + $null = $results.AddRange(@($CopyFrom)) } if ($AddToGroups) { @@ -140,35 +149,36 @@ Function Invoke-EditUser { if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { Write-Host 'Adding to group via Add-DistributionGroupMember ' - $Params = @{ Identity = $GroupID; Member = $UserObj.UserID; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $UserObj.tenantID -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + $Params = @{ Identity = $GroupID; Member = $UserObj.id; BypassSecurityGroupManagerCheck = $true } + $null = New-ExoRequest -tenantid $UserObj.tenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { Write-Host 'Adding to group via Graph' $UserBody = [PSCustomObject]@{ - '@odata.id' = "https://graph.microsoft.com/beta/directoryObjects/$($UserObj.UserID)" + '@odata.id' = "https://graph.microsoft.com/beta/directoryObjects/$($UserObj.id)" } $UserBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $UserBody - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/`$ref" -tenantid $UserObj.tenantID -type POST -body $UserBodyJSON -Verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/`$ref" -tenantid $UserObj.tenantFilter -type POST -body $UserBodyJSON -Verbose } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $UserObj.tenantID -message "Added $($UserObj.DisplayName) to $GroupName group" -Sev 'Info' - $null = $results.add("Success. $($UserObj.DisplayName) has been added to $GroupName") + Write-LogMessage -user $User -API $ApiName -tenant $UserObj.tenantFilter -message "Added $($UserObj.DisplayName) to $GroupName group" -Sev Info + $null = $results.Add("Success. $($UserObj.DisplayName) has been added to $GroupName") } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $UserObj.tenantID -message "Failed to add member $($UserObj.DisplayName) to $GroupName. Error:$($_.Exception.Message)" -Sev 'Error' - $null = $results.add("Failed to add member $($UserObj.DisplayName) to $GroupName : $($_.Exception.Message)") + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $User -API $ApiName -tenant $UserObj.tenantFilter -message "Failed to add member $($UserObj.DisplayName) to $GroupName. Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $null = $results.Add("Failed to add member $($UserObj.DisplayName) to $GroupName : $($ErrorMessage.NormalizedError)") } } } - if ($Request.body.setManager) { + if ($Request.body.setManager.value) { $ManagerBody = [PSCustomObject]@{'@odata.id' = "https://graph.microsoft.com/beta/users/$($Request.body.setManager.value)" } $ManagerBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $ManagerBody - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.UserID)/manager/`$ref" -tenantid $UserObj.tenantID -type PUT -body $ManagerBodyJSON -Verbose - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $UserObj.tenantID -message "Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)" -Sev 'Info' - $results.add("Success. Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)") + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)/manager/`$ref" -tenantid $UserObj.tenantFilter -type PUT -body $ManagerBodyJSON -Verbose + Write-LogMessage -user $User -API $ApiName -tenant $UserObj.tenantFilter -message "Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)" -Sev Info + $null = $results.Add("Success. Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)") } if ($RemoveFromGroups) { @@ -184,21 +194,22 @@ Function Invoke-EditUser { if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { Write-Host 'Removing From group via Remove-DistributionGroupMember ' - $Params = @{ Identity = $GroupID; Member = $UserObj.UserID; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $UserObj.tenantID -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + $Params = @{ Identity = $GroupID; Member = $UserObj.id; BypassSecurityGroupManagerCheck = $true } + $null = New-ExoRequest -tenantid $UserObj.tenantFilter -cmdlet 'Remove-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { Write-Host 'Removing From group via Graph' - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/$($UserObj.UserID)/`$ref" -tenantid $UserObj.tenantID -type DELETE + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$GroupID/members/$($UserObj.id)/`$ref" -tenantid $UserObj.tenantFilter -type DELETE } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $UserObj.tenantID -message "Removed $($UserObj.DisplayName) from $GroupName group" -Sev 'Info' - $null = $results.add("Success. $($UserObj.DisplayName) has been removed from $GroupName") + Write-LogMessage -user $User -API $ApiName -tenant $UserObj.tenantFilter -message "Removed $($UserObj.DisplayName) from $GroupName group" -Sev Info + $null = $results.Add("Success. $($UserObj.DisplayName) has been removed from $GroupName") } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $UserObj.tenantID -message "Failed to remove member $($UserObj.DisplayName) from $GroupName. Error:$($_.Exception.Message)" -Sev 'Error' - $null = $results.add("Failed to remove member $($UserObj.DisplayName) from $GroupName : $($_.Exception.Message)") + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $User -API $ApiName -tenant $UserObj.tenantFilter -message "Failed to remove member $($UserObj.DisplayName) from $GroupName. Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $null = $results.Add("Failed to remove member $($UserObj.DisplayName) from $GroupName : $($ErrorMessage.NormalizedError)") } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 index 3ae22c37ffa7..5aa1ac84f245 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecCreateTAP.ps1 @@ -16,7 +16,7 @@ Function Invoke-ExecCreateTAP { # Interact with query parameters or the body of the request. try { $TAP = New-CIPPTAP -userid $Request.query.ID -TenantFilter $Request.query.tenantfilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' - $Results = [pscustomobject]@{'Results' = "$TAP" } + $Results = [pscustomobject]@{'Results' = $TAP } } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } } 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 b0c29871ae9d..1ef908304c17 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecJITAdmin.ps1 @@ -12,7 +12,7 @@ Function Invoke-ExecJITAdmin { $APIName = 'ExecJITAdmin' $User = $Request.Headers.'x-ms-client-principal' - + $TenantFilter = $Request.body.TenantFilter.value ? $Request.body.TenantFilter.value : $Request.body.TenantFilter Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' if ($Request.Query.Action -eq 'List') { @@ -60,31 +60,31 @@ Function Invoke-ExecJITAdmin { } } else { - if ($Request.Body.UserId -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') { - $Username = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.UserId)" -tenantid $Request.Body.TenantFilter).userPrincipalName + if ($Request.Body.existingUser.value -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') { + $Username = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.existingUser.value)" -tenantid $TenantFilter).userPrincipalName } - Write-LogMessage -user $User -API $APINAME -message "Executing JIT Admin for $Username" -tenant $Request.Body.TenantFilter -Sev 'Info' + Write-LogMessage -user $User -API $APINAME -message "Executing JIT Admin for $Username" -tenant $TenantFilter -Sev 'Info' $Start = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.StartDate)).DateTime.ToLocalTime() $Expiration = ([System.DateTimeOffset]::FromUnixTimeSeconds($Request.Body.EndDate)).DateTime.ToLocalTime() $Results = [System.Collections.Generic.List[string]]::new() if ($Request.Body.useraction -eq 'Create') { - Write-LogMessage -user $User -API $APINAME -tenant $Request.Body.TenantFilter -message "Creating JIT Admin user $($Request.Body.UserPrincipalName)" -Sev 'Info' - Write-Information "Creating JIT Admin user $($Request.Body.UserPrincipalName)" + Write-LogMessage -user $User -API $APINAME -tenant $TenantFilter -message "Creating JIT Admin user $($Request.Body.Username)" -Sev 'Info' + Write-Information "Creating JIT Admin user $($Request.Body.username)" $JITAdmin = @{ User = @{ 'FirstName' = $Request.Body.FirstName 'LastName' = $Request.Body.LastName - 'UserPrincipalName' = $Request.Body.UserPrincipalName + 'UserPrincipalName' = "$($Request.Body.Username)@$($Request.Body.Domain.value)" } Expiration = $Expiration Action = 'Create' - TenantFilter = $Request.Body.TenantFilter + TenantFilter = $TenantFilter } $CreateResult = Set-CIPPUserJITAdmin @JITAdmin - $Username = $CreateResult.userPrincipalName - $Results.Add("Created User: $($CreateResult.userPrincipalName)") + $Username = "$($Request.Body.Username)@$($Request.Body.Domain.value)" + $Results.Add("Created User: $($Request.Body.Username)@$($Request.Body.Domain.value)") if (!$Request.Body.UseTAP) { $Results.Add("Password: $($CreateResult.password)") } @@ -92,6 +92,7 @@ Function Invoke-ExecJITAdmin { Start-Sleep -Seconds 1 } + #Region TAP creation if ($Request.Body.UseTAP) { try { if ($Start -gt (Get-Date)) { @@ -102,19 +103,20 @@ Function Invoke-ExecJITAdmin { } else { $TapBody = '{}' } - Write-Information "https://graph.microsoft.com/beta/users/$Username/authentication/temporaryAccessPassMethods" - # Retry creating the TAP up to 5 times, since it can fail due to the user not being fully created yet + # Write-Information "https://graph.microsoft.com/beta/users/$Username/authentication/temporaryAccessPassMethods" + # Retry creating the TAP up to 10 times, since it can fail due to the user not being fully created yet. Sometimes it takes 2 reties, sometimes it takes 8+. Very annoying. -Bobby $Retries = 0 + $MAX_TAP_RETRIES = 10 do { try { - $TapRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($Username)/authentication/temporaryAccessPassMethods" -tenantid $Request.Body.TenantFilter -type POST -body $TapBody + $TapRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($Username)/authentication/temporaryAccessPassMethods" -tenantid $TenantFilter -type POST -body $TapBody } catch { Start-Sleep -Seconds 2 - Write-Information 'ERROR: Failed to create TAP, retrying' - Write-Information ( ConvertTo-Json -Depth 5 -InputObject (Get-CippException -Exception $_)) + Write-Information "ERROR: Run $Retries of $MAX_TAP_RETRIES : Failed to create TAP, retrying" + # Write-Information ( ConvertTo-Json -Depth 5 -InputObject (Get-CippException -Exception $_)) } $Retries++ - } while ( $null -eq $TapRequest.temporaryAccessPass -and $Retries -le 5 ) + } while ( $null -eq $TapRequest.temporaryAccessPass -and $Retries -le $MAX_TAP_RETRIES ) $TempPass = $TapRequest.temporaryAccessPass $PasswordExpiration = $TapRequest.LifetimeInMinutes @@ -135,19 +137,20 @@ Function Invoke-ExecJITAdmin { } } } + #EndRegion TAP creation $Parameters = @{ - TenantFilter = $Request.Body.TenantFilter + TenantFilter = $TenantFilter User = @{ 'UserPrincipalName' = $Username } - Roles = $Request.Body.AdminRoles + Roles = $Request.Body.AdminRoles.value Action = 'AddRoles' Expiration = $Expiration } if ($Start -gt (Get-Date)) { $TaskBody = @{ - TenantFilter = $Request.Body.TenantFilter + TenantFilter = $TenantFilter Name = "JIT Admin (enable): $Username" Command = @{ value = 'Set-CIPPUserJITAdmin' @@ -156,14 +159,14 @@ Function Invoke-ExecJITAdmin { Parameters = [pscustomobject]$Parameters ScheduledTime = $Request.Body.StartDate PostExecution = @{ - Webhook = [bool]$Request.Body.PostExecution.Webhook - Email = [bool]$Request.Body.PostExecution.Email - PSA = [bool]$Request.Body.PostExecution.PSA + Webhook = [bool]($Request.Body.PostExecution | Where-Object -Property value -EQ 'webhook') + Email = [bool]($Request.Body.PostExecution | Where-Object -Property value -EQ 'email') + PSA = [bool]($Request.Body.PostExecution | Where-Object -Property value -EQ 'PSA') } } Add-CIPPScheduledTask -Task $TaskBody -hidden $false if ($Request.Body.useraction -ne 'Create') { - Set-CIPPUserJITAdminProperties -TenantFilter $Request.Body.TenantFilter -UserId $Request.Body.UserId -Expiration $Expiration + Set-CIPPUserJITAdminProperties -TenantFilter $TenantFilter -UserId $Request.Body.existingUser.value -Expiration $Expiration } $Results.Add("Scheduling JIT Admin enable task for $Username") } else { @@ -172,29 +175,29 @@ Function Invoke-ExecJITAdmin { } $DisableTaskBody = [pscustomobject]@{ - TenantFilter = $Request.Body.TenantFilter - Name = "JIT Admin ($($Request.Body.ExpireAction)): $Username" + TenantFilter = $TenantFilter + Name = "JIT Admin ($($Request.Body.ExpireAction.value)): $Username" Command = @{ value = 'Set-CIPPUserJITAdmin' label = 'Set-CIPPUserJITAdmin' } Parameters = [pscustomobject]@{ - TenantFilter = $Request.Body.TenantFilter + TenantFilter = $TenantFilter User = @{ 'UserPrincipalName' = $Username } - Roles = $Request.Body.AdminRoles - Action = $Request.Body.ExpireAction + Roles = $Request.Body.AdminRoles.value + Action = $Request.Body.ExpireAction.value } PostExecution = @{ - Webhook = [bool]$Request.Body.PostExecution.Webhook - Email = [bool]$Request.Body.PostExecution.Email - PSA = [bool]$Request.Body.PostExecution.PSA + Webhook = [bool]($Request.Body.PostExecution | Where-Object -Property value -EQ 'webhook') + Email = [bool]($Request.Body.PostExecution | Where-Object -Property value -EQ 'email') + PSA = [bool]($Request.Body.PostExecution | Where-Object -Property value -EQ 'PSA') } ScheduledTime = $Request.Body.EndDate } $null = Add-CIPPScheduledTask -Task $DisableTaskBody -hidden $false - $Results.Add("Scheduling JIT Admin $($Request.Body.ExpireAction) task for $Username") + $Results.Add("Scheduling JIT Admin $($Request.Body.ExpireAction.value) task for $Username") $Body = @{ Results = @($Results) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 index 81707b1b22ef..c692f729818d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOffboardUser.ps1 @@ -9,13 +9,13 @@ Function Invoke-ExecOffboardUser { #> [CmdletBinding()] param($Request, $TriggerMetadata) - if ($Request.body.user.value) { $AllUsers = $Request.body.user.value } else { $AllUsers = @($Request.body.user) } + $AllUsers = $Request.body.user.value + $Tenantfilter = $request.body.tenantfilter.value $Results = foreach ($username in $AllUsers) { try { $APIName = 'ExecOffboardUser' Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.body.tenantfilter if ($Request.body.Scheduled.enabled) { $taskObject = [PSCustomObject]@{ TenantFilter = $Tenantfilter diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 index ddc282908b68..d34101aa3923 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOneDriveShortCut.ps1 @@ -14,10 +14,10 @@ Function Invoke-ExecOneDriveShortCut { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' Try { - $MessageResult = New-CIPPOneDriveShortCut -username $Request.body.username -userid $Request.body.userid -TenantFilter $Request.Body.TenantFilter -URL $Request.body.input -ExecutingUser $request.headers.'x-ms-client-principal' + $MessageResult = New-CIPPOneDriveShortCut -username $Request.Body.username -userid $Request.Body.userid -TenantFilter $Request.Body.tenantFilter -URL $Request.Body.siteUrl.value -ExecutingUser $request.headers.'x-ms-client-principal' $Results = [pscustomobject]@{ 'Results' = "$MessageResult" } } catch { - $Results = [pscustomobject]@{'Results' = "Onedrive Shortcut creation failed: $($_.Exception.Message)" } + $Results = [pscustomobject]@{'Results' = "OneDrive Shortcut creation failed: $($_.Exception.Message)" } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOnedriveProvision.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOnedriveProvision.ps1 index 2ab46bfed86a..bc84330fccef 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOnedriveProvision.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecOnedriveProvision.ps1 @@ -11,8 +11,9 @@ Function Invoke-ExecOneDriveProvision { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName + $Params = $Request.Body ?? $Request.Query try { - $State = Request-CIPPSPOPersonalSite -TenantFilter $Request.Query.TenantFilter -UserEmails $Request.Query.UserPrincipalName -ExecutingUser $request.headers.'x-ms-client-principal' -APIName $APINAME + $State = Request-CIPPSPOPersonalSite -TenantFilter $Params.TenantFilter -UserEmails $Params.UserPrincipalName -ExecutingUser $Request.Headers.'x-ms-client-principal' -APIName $APINAME $Results = [pscustomobject]@{'Results' = "$State" } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message @@ -24,5 +25,4 @@ Function Invoke-ExecOneDriveProvision { StatusCode = [HttpStatusCode]::OK Body = $Results }) - } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 index b52a1595f513..58155d6fa8e3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecPerUserMFA.ps1 @@ -14,7 +14,7 @@ function Invoke-ExecPerUserMFA { $Request = @{ userId = $Request.Body.userId TenantFilter = $Request.Body.TenantFilter - State = $Request.Body.State + State = $Request.Body.State.value ? $Request.Body.State.value : $Request.Body.State executingUser = $Request.Headers.'x-ms-client-principal' } $Result = Set-CIPPPerUserMFA @Request @@ -25,4 +25,4 @@ function Invoke-ExecPerUserMFA { StatusCode = [HttpStatusCode]::OK Body = $Body }) -} \ No newline at end of file +} 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 6c59d1cd9346..ee9e9b65487c 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 @@ -17,16 +17,19 @@ Function Invoke-ExecResetMFA { $TenantFilter = $Request.Query.TenantFilter $UserID = $Request.Query.ID try { - $Results = Remove-CIPPUserMFA -UserPrincipalName $UserID -TenantFilter $TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + + $Body = @{ + Results = Remove-CIPPUserMFA -UserPrincipalName $UserID -TenantFilter $TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + } } catch { - $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $($Request.Query.ID): $(Get-NormalizedError -message $_.Exception.Message)" } + $Body = [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'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $Results + Body = $Body }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 index c9be1da38759..98be3b461aa4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecResetPass.ps1 @@ -23,7 +23,7 @@ Function Invoke-ExecResetPass { try { $Reset = Set-CIPPResetPassword -userid $Request.query.ID -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' -forceChangePasswordNextSignIn $mustChange - $Results = [pscustomobject]@{'Results' = "$Reset" } + $Results = [pscustomobject]@{'Results' = $Reset } } catch { $Results = [pscustomobject]@{'Results' = "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" -Sev 'Error' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 index 1dabd29f6efb..38ca6d3d876e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 @@ -13,8 +13,8 @@ Function Invoke-ExecSendPush { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $Request.Query.TenantFilter - $UserEmail = $Request.Query.UserEmail + $TenantFilter = $Request.body.TenantFilter + $UserEmail = $Request.body.UserEmail $MFAAppID = '981f26a1-7f43-403b-a875-f8b09b8cd720' # Function to keep trying to get the access token while we wait for MS to actually set the temp password @@ -92,7 +92,7 @@ Function Invoke-ExecSendPush { try { $ClientToken = get-clientaccess -Uri $ClientUri -Body $body } catch { - $Body = 'Failed to create temporary password' + $Body = 'Failed to create temporary token for MFA Application. Error: ' + $_.Exception.Message } # If we got a token send a push @@ -104,15 +104,16 @@ Function Invoke-ExecSendPush { if ($obj.BeginTwoWayAuthenticationResponse.result) { $Body = "Received an MFA confirmation: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" + $colour = 'success' } if ($obj.BeginTwoWayAuthenticationResponse.AuthenticationResult -ne $true) { $Body = "Authentication Failed! Does the user have Push/Phone call MFA configured? Errorcode: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" - $colour = 'danger' + $colour = 'error' } } - $Results = [pscustomobject]@{'Results' = $Body; colour = $colour } + $Results = [pscustomobject]@{'Results' = $Body; severity = $colour } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Sent push request to $UserEmail - Result: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" -Sev 'Info' Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListPerUserMFA.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListPerUserMFA.ps1 new file mode 100644 index 000000000000..39bbcd9bc268 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListPerUserMFA.ps1 @@ -0,0 +1,50 @@ +using namespace System.Net + +function Invoke-ListPerUserMFA { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.User.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $User = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Parse query parameters + $Tenant = $Request.query.tenantFilter + try { + $AllUsers = [System.Convert]::ToBoolean($Request.query.allUsers) + } catch { + $AllUsers = $false + } + $UserId = $Request.query.userId + + # Get the MFA state for the user/all users + try { + if ($AllUsers -eq $true) { + $Results = Get-CIPPPerUserMFA -TenantFilter $Tenant -AllUsers $true + } else { + $Results = Get-CIPPPerUserMFA -TenantFilter $Tenant -userId $UserId + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $Results = "Failed to get MFA State for $UserId : $ErrorMessage" + $StatusCode = [HttpStatusCode]::Forbidden + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($Results) + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 index 152323e21b4e..fad747bb3e2f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 @@ -13,7 +13,6 @@ Function Invoke-ListUserMailboxDetails { $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.' @@ -21,152 +20,174 @@ Function Invoke-ListUserMailboxDetails { $TenantFilter = $Request.Query.TenantFilter $UserID = $Request.Query.UserID - - $TenantFilter = $Request.Query.TenantFilter try { - $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Request.Query.UserID) - $base64IdentityParam = [Convert]::ToBase64String($Bytes) - $CASRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $MailRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$UserID')" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $FetchParam = @{ - anr = $MailRequest.PrimarySmtpAddress - } - $MailboxDetailedRequest = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-Mailbox' -cmdParams $FetchParam + $Requests = @( + @{ + CmdletInput = @{ + CmdletName = 'Get-Mailbox' + Parameters = @{ Identity = $UserID } + } + }, + @{ + CmdletInput = @{ + CmdletName = 'Get-MailboxPermission' + Parameters = @{ Identity = $UserID } + } + }, + @{ + CmdletInput = @{ + CmdletName = 'Get-CASMailbox' + Parameters = @{ Identity = $UserID } + } + }, + @{ + CmdletInput = @{ + CmdletName = 'Get-OrganizationConfig' + } + }, + @{ + CmdletInput = @{ + CmdletName = 'Get-MailboxStatistics' + Parameters = @{ Identity = $UserID; Archive = $true } + } + }, + @{ + CmdletInput = @{ + CmdletName = 'Get-BlockedSenderAddress' + Parameters = @{ Identity = $UserID } + } + }, + @{ + CmdletInput = @{ + CmdletName = 'Get-RecipientPermission' + Parameters = @{ Identity = $UserID } + } + } + ) + Write-Host $UserID + #$username = (New-GraphGetRequest -tenantid $TenantFilter -uri "https://graph.microsoft.com/beta/users/$UserID").userPrincipalName + $Results = New-ExoBulkRequest -TenantId $TenantFilter -CmdletArray $Requests -returnWithCommand $true -Anchor $username + + # Assign variables from $Results + $MailboxDetailedRequest = $Results.'Get-Mailbox' + $PermsRequest = $Results.'Get-MailboxPermission' + $CASRequest = $Results.'Get-CASMailbox' + $OrgConfig = $Results.'Get-OrganizationConfig' + $ArchiveSizeRequest = $Results.'Get-MailboxStatistics' + $BlockedSender = $Results.'Get-BlockedSenderAddress' + $PermsRequest2 = $Results.'Get-RecipientPermission' + $StatsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailboxDetailedRequest.UserPrincipalName)')/Exchange.GetMailboxStatistics()" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true + + + # Handle ArchiveEnabled and AutoExpandingArchiveEnabled try { if ($MailboxDetailedRequest.ArchiveStatus -eq 'Active') { $ArchiveEnabled = $True } else { $ArchiveEnabled = $False } - # Get organization config of auto expanding archive if it's disabled on user level - if (!$MailboxDetailedRequest.AutoExpandingArchiveEnabled -and $ArchiveEnabled) { - $OrgConfig = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-OrganizationConfig' + + # Get organization config of auto-expanding archive if it's disabled on user level + if (-not $MailboxDetailedRequest.AutoExpandingArchiveEnabled -and $ArchiveEnabled) { $AutoExpandingArchiveEnabled = $OrgConfig.AutoExpandingArchiveEnabled } else { $AutoExpandingArchiveEnabled = $MailboxDetailedRequest.AutoExpandingArchiveEnabled } - - $FetchParam = @{ - Identity = $MailRequest.PrimarySmtpAddress - Archive = $true - } - - $ArchiveSize = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-MailboxStatistics' -cmdParams $FetchParam } catch { $ArchiveEnabled = $False - $ArchiveSize = @{ + $ArchiveSizeRequest = @{ TotalItemSize = '0' ItemCount = '0' } } - $FetchParam = @{ - SenderAddress = $MailRequest.PrimarySmtpAddress - } - $BlockedSender = New-ExoRequest -TenantID $TenantFilter -cmdlet 'Get-BlockedSenderAddress' -cmdParams $FetchParam - if ($BlockedSender) { + + + # Determine if the user is blocked for spam + if ($BlockedSender -and $BlockedSender.Count -gt 0) { $BlockedForSpam = $True } else { $BlockedForSpam = $False } - $StatsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/Exchange.GetMailboxStatistics()" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($MailRequest.PrimarySmtpAddress)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true - $PermsRequest2 = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Recipient('$base64IdentityParam')?`$expand=RecipientPermission&isEncoded=true" -Tenantid $tenantfilter -scope ExchangeOnline - } catch { Write-Error "Failed Fetching Data $($_.Exception.message): $($_.InvocationInfo.ScriptLineNumber)" } - $ParsedPerms = foreach ($Perm in $PermsRequest, $PermsRequest2.RecipientPermission) { + # Parse permissions - if ($perm.Trustee) { - $perm | Where-Object Trustee | ForEach-Object { [PSCustomObject]@{ - User = $_.Trustee - AccessRights = $_.accessRights -join ', ' - } - } - - } - if ($perm.PermissionList) { - $perm | Where-Object User | ForEach-Object { [PSCustomObject]@{ - User = $_.User - AccessRights = $_.PermissionList.accessRights -join ', ' + $ParsedPerms = foreach ($PermSet in @($PermsRequest, $PermsRequest2)) { + foreach ($Perm in $PermSet) { + # Check if Trustee or User is not NT AUTHORITY\SELF + $user = $Perm.Trustee ? $Perm.Trustee : $Perm.User + if ($user -ne 'NT AUTHORITY\SELF') { + [PSCustomObject]@{ + User = $user + AccessRights = ($Perm.AccessRights) -join ', ' } } } } - $forwardingaddress = if ($MailboxDetailedRequest.ForwardingAddress) { - (New-GraphGetRequest -tenantid $TenantFilter -uri "https://graph.microsoft.com/beta/users/$($MailboxDetailedRequest.ForwardingAddress)").UserPrincipalName + # Get forwarding address + $ForwardingAddress = if ($MailboxDetailedRequest.ForwardingAddress) { + try { + (New-GraphGetRequest -TenantId $TenantFilter -Uri "https://graph.microsoft.com/beta/users/$($MailboxDetailedRequest.ForwardingAddress)").UserPrincipalName + } catch { + try { + '{0} ({1})' -f $MailboxDetailedRequest.ForwardingAddress, (($((New-GraphGetRequest -TenantId $TenantFilter -Uri "https://graph.microsoft.com/beta/users?`$filter=displayName eq '$($MailboxDetailedRequest.ForwardingAddress)'") | Select-Object -First 1 -ExpandProperty UserPrincipalName))) + } catch { + $MailboxDetailedRequest.ForwardingAddress + } + } } elseif ($MailboxDetailedRequest.ForwardingSmtpAddress -and $MailboxDetailedRequest.ForwardingAddress) { - $MailboxDetailedRequest.ForwardingAddress + ' ' + $MailboxDetailedRequest.ForwardingSmtpAddress + "$($MailboxDetailedRequest.ForwardingAddress) $($MailboxDetailedRequest.ForwardingSmtpAddress)" } else { $MailboxDetailedRequest.ForwardingSmtpAddress } - if ($ArchiveSize) { - $GraphRequest = [ordered]@{ - ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward - ForwardingAddress = $ForwardingAddress - LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled - HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled - EWSEnabled = $CASRequest.EwsEnabled - MailboxMAPIEnabled = $CASRequest.MAPIEnabled - MailboxOWAEnabled = $CASRequest.OWAEnabled - MailboxImapEnabled = $CASRequest.ImapEnabled - MailboxPopEnabled = $CASRequest.PopEnabled - MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled - Permissions = $ParsedPerms - ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) - ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) - ItemCount = [math]::Round($StatsRequest.ItemCount, 2) - TotalItemSize = [math]::Round($StatsRequest.TotalItemSize / 1Gb, 2) - TotalArchiveItemSize = $ArchiveSize.totalItemSize.split('(')[0] - TotalArchiveItemCount = [math]::Round($ArchiveSize.ItemCount, 2) - BlockedForSpam = $BlockedForSpam - ArchiveMailBox = $ArchiveEnabled - AutoExpandingArchive = $AutoExpandingArchiveEnabled - RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails - } - } else { - $GraphRequest = [ordered]@{ - ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward - ForwardingAddress = $ForwardingAddress - LitiationHold = $MailboxDetailedRequest.LitigationHoldEnabled - HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled - EWSEnabled = $CASRequest.EwsEnabled - MailboxMAPIEnabled = $CASRequest.MAPIEnabled - MailboxOWAEnabled = $CASRequest.OWAEnabled - MailboxImapEnabled = $CASRequest.ImapEnabled - MailboxPopEnabled = $CASRequest.PopEnabled - MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled - Permissions = $ParsedPerms - ProhibitSendQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendQuota -split ' GB')[0], 2) - ProhibitSendReceiveQuota = [math]::Round([float]($MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' GB')[0], 2) - ItemCount = [math]::Round($StatsRequest.ItemCount, 2) - TotalItemSize = [math]::Round($StatsRequest.TotalItemSize / 1Gb, 2) - TotalArchiveItemSize = 0 - TotalArchiveItemCount = 0 - BlockedForSpam = $BlockedForSpam - ArchiveMailBox = $ArchiveEnabled - AutoExpandingArchive = $AutoExpandingArchiveEnabled - RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails - } - } + $ProhibitSendQuotaString = $MailboxDetailedRequest.ProhibitSendQuota -split ' ' + $ProhibitSendReceiveQuotaString = $MailboxDetailedRequest.ProhibitSendReceiveQuota -split ' ' + $TotalItemSizeString = $StatsRequest.TotalItemSize -split ' ' + $TotalArchiveItemSizeString = $ArchiveSizeRequest.TotalItemSize -split ' ' + $ProhibitSendQuota = try { [math]::Round([float]($ProhibitSendQuotaString[0]), 2) } catch { 0 } + $ProhibitSendReceiveQuota = try { [math]::Round([float]($ProhibitSendReceiveQuotaString[0]), 2) } catch { 0 } - #$GraphRequest = [ordered]@{ - # Connectivity = $CASRequest - # Mailbox = $MailRequest - # MailboxDetail = $MailboxDetailedRequest - # Stats = $StatsRequest - # Permissions = $ParsedPerms - # Result = $Result - #} + $ItemSizeType = '1{0}' -f ($TotalItemSizeString[1] ?? 'Gb') + $TotalItemSize = try { [math]::Round([float]($TotalItemSizeString[0]) / $ItemSizeType, 2) } catch { 0 } + + if ($ArchiveEnabled) { + $ArchiveSizeType = '1{0}' -f ($TotalArchiveItemSizeString[1] ?? 'Gb') + $TotalArchiveItemSize = [math]::Round([float]($TotalArchiveItemSizeString[0]) / $ArchiveSizeType, 2) + } + + # Build the GraphRequest object + $GraphRequest = [ordered]@{ + ForwardAndDeliver = $MailboxDetailedRequest.DeliverToMailboxAndForward + ForwardingAddress = $ForwardingAddress + LitigationHold = $MailboxDetailedRequest.LitigationHoldEnabled + HiddenFromAddressLists = $MailboxDetailedRequest.HiddenFromAddressListsEnabled + EWSEnabled = $CASRequest.EwsEnabled + MailboxMAPIEnabled = $CASRequest.MAPIEnabled + MailboxOWAEnabled = $CASRequest.OWAEnabled + MailboxImapEnabled = $CASRequest.ImapEnabled + MailboxPopEnabled = $CASRequest.PopEnabled + MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled + Permissions = @($ParsedPerms) + ProhibitSendQuota = $ProhibitSendQuota + ProhibitSendReceiveQuota = $ProhibitSendReceiveQuota + ItemCount = [math]::Round($StatsRequest.ItemCount, 2) + TotalItemSize = $TotalItemSize + TotalArchiveItemSize = if ($ArchiveEnabled) { $TotalArchiveItemSize } else { '0' } + TotalArchiveItemCount = if ($ArchiveEnabled) { try { [math]::Round($ArchiveSizeRequest.ItemCount, 2) } catch { 0 } } else { 0 } + BlockedForSpam = $BlockedForSpam + ArchiveMailBox = $ArchiveEnabled + AutoExpandingArchive = $AutoExpandingArchiveEnabled + RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails + Mailbox = $MailboxDetailedRequest + } - # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @($GraphRequest) }) - } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 index a8c4af96c998..4ea9b6d8a35a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxRules.ps1 @@ -23,14 +23,7 @@ Function Invoke-ListUserMailboxRules { $TenantFilter = $Request.Query.TenantFilter $UserID = $Request.Query.UserID $UserEmail = if ([string]::IsNullOrWhiteSpace($Request.Query.userEmail)) { $UserID } else { $Request.Query.userEmail } - $GraphRequest = New-ExoRequest -Anchor $UserID -tenantid $TenantFilter -cmdlet 'Get-InboxRule' -cmdParams @{mailbox = $UserID; IncludeHidden = $true } | Where-Object { $_.Name -ne 'Junk E-Mail Rule' -and $_.Name -notlike 'Microsoft.Exchange.OOF.*' } | Select-Object - @{ Name = 'DisplayName'; Expression = { $_.displayName } }, - @{ Name = 'Description'; Expression = { $_.Description } }, - @{ Name = 'Redirect To'; Expression = { $_.RedirectTo } }, - @{ Name = 'Copy To Folder'; Expression = { $_.CopyToFolder } }, - @{ Name = 'Move To Folder'; Expression = { $_.MoveToFolder } }, - @{ Name = 'Soft Delete Message'; Expression = { $_.SoftDeleteMessage } }, - @{ Name = 'Delete Message'; Expression = { $_.DeleteMessage } } + $GraphRequest = New-ExoRequest -Anchor $UserID -tenantid $TenantFilter -cmdlet 'Get-InboxRule' -cmdParams @{mailbox = $UserID; IncludeHidden = $true } | Where-Object { $_.Name -ne 'Junk E-Mail Rule' -and $_.Name -notlike 'Microsoft.Exchange.OOF.*' } | Select-Object * -ExcludeProperty RuleIdentity } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -user $User -API $APINAME -message "Failed to retrieve mailbox rules $($UserEmail): $($ErrorMessage.NormalizedError) " -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 index 757784ad320d..3881208d6a5b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserPhoto.ps1 @@ -10,27 +10,28 @@ Function Invoke-ListUserPhoto { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - - # Interact with query parameters or the body of the request. $tenantFilter = $Request.Query.TenantFilter $userId = $Request.Query.UserID + $URI = "/users/$userId/photo/`$value" - $URI = "https://graph.microsoft.com/v1.0/users/$userId/photos/240x240/`$value" - Write-Host $URI - $graphRequest = New-GraphGetRequest -uri $URI -tenantid $tenantFilter + $Requests = @( + @{ + id = 'photo' + url = $URI + method = 'GET' + } + ) + $ImageData = New-GraphBulkRequest -Requests $Requests -tenantid $tenantFilter -NoAuthCheck $true + #convert body from base64 to byte array + $Body = [Convert]::FromBase64String($ImageData.body) # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @($graphRequest) + StatusCode = [HttpStatusCode]::OK + ContentType = $ImageData.headers.'Content-Type' + Body = $Body }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 index 32c2cc24f28a..d92d6e241df5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserSigninLogs.ps1 @@ -13,7 +13,7 @@ Function Invoke-ListUserSigninLogs { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - + $top = $Request.Query.top ? $Request.Query.top : 50 # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' @@ -21,35 +21,14 @@ Function Invoke-ListUserSigninLogs { $TenantFilter = $Request.Query.TenantFilter $UserID = $Request.Query.UserID try { - $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$UserID')&`$top=50&`$orderby=createdDateTime desc" + $URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$UserID')&`$top=$top&`$orderby=createdDateTime desc" Write-Host $URI - $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'Date'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } }, - id, - @{ Name = 'Application'; Expression = { $_.resourceDisplayName } }, - @{ Name = 'LoginStatus'; Expression = { $_.status.errorCode } }, - @{ Name = 'ConditionalAccessStatus'; Expression = { $_.conditionalAccessStatus } }, - @{ Name = 'OverallLoginStatus'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } }, - @{ Name = 'IPAddress'; Expression = { $_.ipAddress } }, - @{ Name = 'Town'; Expression = { $_.location.city } }, - @{ Name = 'State'; Expression = { $_.location.state } }, - @{ Name = 'Country'; Expression = { $_.location.countryOrRegion } }, - @{ Name = 'Device'; Expression = { $_.deviceDetail.displayName } }, - @{ Name = 'DeviceCompliant'; Expression = { $_.deviceDetail.isCompliant } }, - @{ Name = 'OS'; Expression = { $_.deviceDetail.operatingSystem } }, - @{ Name = 'Browser'; Expression = { $_.deviceDetail.browser } }, - @{ Name = 'AppliedCAPs'; Expression = { ($_.appliedConditionalAccessPolicies | ForEach-Object { @{Result = $_.result; Name = $_.displayName } }) } }, - @{ Name = 'AdditionalDetails'; Expression = { $_.status.additionalDetails } }, - @{ Name = 'FailureReason'; Expression = { $_.status.failureReason } }, - @{ Name = 'FullDetails'; Expression = { $_ } } + $GraphRequest = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose + Write-Host $GraphRequest # Associate values to output bindings by calling 'Push-OutputBinding'. - if ($GraphRequest.FullDetails -eq $null) { - $GraphRequest = $null - } else { - $GraphRequest = @($GraphRequest) - } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $GraphRequest + Body = @($GraphRequest) }) } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to retrieve Sign In report: $($_.Exception.message) " -Sev 'Error' -tenant $TenantFilter diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 index ef2870bc0649..e138cc02e470 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUsers.ps1 @@ -12,7 +12,6 @@ Function Invoke-ListUsers { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $selectlist = 'id', 'accountEnabled', 'displayName', 'userPrincipalName', 'username', 'userType', 'createdDateTime', 'companyName', 'country', 'department', 'businessPhones', 'city', 'faxNumber', 'givenName', 'isResourceAccount', 'jobTitle', 'mobilePhone', 'officeLocation', 'postalCode', 'preferredDataLocation', 'preferredLanguage', 'mail', 'mailNickname', 'proxyAddresses', 'Aliases', 'otherMails', 'showInAddressList', 'state', 'streetAddress', 'surname', 'usageLocation', 'LicJoined', 'assignedLicenses', 'onPremisesSyncEnabled', 'OnPremisesImmutableId', 'onPremisesDistinguishedName', 'onPremisesLastSyncDateTime', 'primDomain', 'Tenant', 'CippStatus' # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' $ConvertTable = Import-Csv ConversionTable.csv | Sort-Object -Property 'guid' -Unique @@ -22,13 +21,13 @@ Function Invoke-ListUsers { $userid = $Request.Query.UserID $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)?`$top=999&`$select=$($selectlist -join ',')&`$filter=$GraphFilter&`$count=true" -tenantid $TenantFilter -ComplexFilter | Select-Object $selectlist | ForEach-Object { - $_.onPremisesSyncEnabled = [bool]($_.onPremisesSyncEnabled) - $_.UserName = $_.userPrincipalName -split '@' | Select-Object -First 1 - $_.Aliases = $_.Proxyaddresses -join ', ' + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)?`$top=999&`$filter=$GraphFilter&`$count=true" -tenantid $TenantFilter -ComplexFilter | ForEach-Object { + $_ | Add-Member -MemberType NoteProperty -Name 'onPremisesSyncEnabled' -Value ([bool]($_.onPremisesSyncEnabled)) -Force + $_ | Add-Member -MemberType NoteProperty -Name 'username' -Value ($_.userPrincipalName -split '@' | Select-Object -First 1) -Force + $_ | Add-Member -MemberType NoteProperty -Name 'Aliases' -Value ($_.ProxyAddresses -join ', ') -Force $SkuID = $_.AssignedLicenses.skuid - $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' - $_.primDomain = ($_.userPrincipalName -split '@' | Select-Object -Last 1) + $_ | Add-Member -MemberType NoteProperty -Name 'LicJoined' -Value (($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ') -Force + $_ | Add-Member -MemberType NoteProperty -Name 'primDomain' -Value @{value = ($_.userPrincipalName -split '@' | Select-Object -Last 1); label = ($_.userPrincipalName -split '@' | Select-Object -Last 1); } -Force $_ } } else { @@ -44,7 +43,7 @@ Function Invoke-ListUsers { $_.Aliases = $_.Proxyaddresses -join ', ' $SkuID = $_.AssignedLicenses.skuid $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' - $_.primDomain = ($_.userPrincipalName -split '@' | Select-Object -Last 1) + $_.primDomain = @{value = ($_.userPrincipalName -split '@' | Select-Object -Last 1) } $_ } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 index 29b622550ef2..bf31040b83a8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Invoke-ExecIncidentsList.ps1 @@ -89,7 +89,7 @@ Function Invoke-ExecIncidentsList { if (!$body) { $StatusCode = [HttpStatusCode]::OK $body = [PSCustomObject]@{ - MSResults = ($GraphRequest | Where-Object -Property id -NE $null) + Results = @($GraphRequest | Where-Object -Property id -NE $null) } } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddSiteBulk.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddSiteBulk.ps1 index 97f779f10c76..ff9eb3cfce9e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddSiteBulk.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddSiteBulk.ps1 @@ -16,7 +16,7 @@ Function Invoke-AddSiteBulk { $Results = [System.Collections.ArrayList]@() - foreach ($sharepointObj in $Request.body.BulkSite) { + foreach ($sharepointObj in $Request.Body.bulkSites) { try { $SharePointSite = New-CIPPSharepointSite -SiteName $SharePointObj.siteName -SiteDescription $SharePointObj.siteDescription -SiteOwner $SharePointObj.siteOwner -TemplateName $SharePointObj.templateName -SiteDesign $SharePointObj.siteDesign -SensitivityLabel $SharePointObj.sensitivityLabel -TenantFilter $Request.body.TenantFilter $Results.add($SharePointSite) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 index ea3412dd22b4..94647e739f8b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-AddTeam.ps1 @@ -18,11 +18,11 @@ Function Invoke-AddTeam { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $Owners = ($userobj.owner).Split([Environment]::NewLine) | Where-Object { $_ -ne $null -or $_ -ne '' } + $Owners = ($userobj.owner).value try { $Owners = $Owners | ForEach-Object { - $OwnerID = "https://graph.microsoft.com/beta/users('" + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$_" -tenantid $Userobj.tenantid).id + "')" + $OwnerID = "https://graph.microsoft.com/beta/users('$($_)')" @{ '@odata.type' = '#microsoft.graph.aadUserConversationMember' 'roles' = @('owner') @@ -44,8 +44,7 @@ Function Invoke-AddTeam { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Added Team $($userobj.displayname)" -Sev 'Info' $body = [pscustomobject]@{'Results' = 'Success. Team has been added' } - } - catch { + } catch { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantid) -message "Adding Team failed. Error: $($_.Exception.Message)" -Sev 'Error' $body = [pscustomobject]@{'Results' = "Failed. Error message: $($_.Exception.Message)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 index 9c59f13662c3..e5851ab0fd44 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 @@ -10,13 +10,21 @@ Function Invoke-ExecSetSharePointMember { [CmdletBinding()] param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $ExecutingUser = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.body.tenantFilter + + + if ($Request.body.SharePointType -eq 'Group') { - $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)'" -tenantid $Request.Body.TenantFilter).id + $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)' or proxyAddresses/any(x:endsWith(x,'$($Request.Body.GroupID)'))&`$count=true" -ComplexFilter -tenantid $TenantFilter).id if ($Request.body.Add -eq $true) { - $Results = Add-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $Request.Body.input -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = Add-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $Request.Body.user.value -TenantFilter $TenantFilter -ExecutingUser $ExecutingUser } else { - $UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.input)" -tenantid $Request.Body.TenantFilter).id - $Results = Remove-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $UserID -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + $UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.user.value)" -tenantid $TenantFilter).id + $Results = Remove-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $UserID -TenantFilter $TenantFilter -ExecutingUser $ExecutingUser } } else { $Results = 'This type of SharePoint site is not supported.' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointPerms.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointPerms.ps1 index 347a5e5721bd..40934b0bb546 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointPerms.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSharePointPerms.ps1 @@ -11,17 +11,36 @@ Function Invoke-ExecSharePointPerms { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - $tenantFilter = $Request.Body.TenantFilter + $tenantFilter = $Request.Body.tenantFilter + $ExecutingUser = $Request.Headers.'x-ms-client-principal' + + Write-LogMessage -user $ExecutingUser -API $APIName -message 'Accessed this API' -Sev Debug + + # The UPN or ID of the users OneDrive we are changing permissions on + $UserId = $Request.body.UPN + # The UPN of the user we are adding or removing permissions for + $OnedriveAccessUser = $Request.body.onedriveAccessUser.value + try { - $State = Set-CIPPSharePointPerms -tenantFilter $tenantFilter -userid $request.body.UPN -OnedriveAccessUser $request.body.input -ExecutingUser $ExecutingUser -APIName $APIName -RemovePermission $request.body.RemovePermission -URL $Request.Body.URL + + $State = Set-CIPPSharePointPerms -tenantFilter $tenantFilter ` + -UserId $UserId ` + -OnedriveAccessUser $OnedriveAccessUser ` + -ExecutingUser $ExecutingUser ` + -APIName $APIName ` + -RemovePermission $Request.body.RemovePermission ` + -URL $Request.Body.URL $Results = [pscustomobject]@{'Results' = "$State" } + $StatusCode = [HttpStatusCode]::OK } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $ErrorMessage = Get-CippException -Exception $_ + $Results = [pscustomobject]@{'Results' = "Failed. $($ErrorMessage.NormalizedError)" } + $StatusCode = [HttpStatusCode]::BadRequest } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode 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 index fa04ac2c41d8..4714c300685a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecTeamsVoicePhoneNumberAssignment.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecTeamsVoicePhoneNumberAssignment.ps1 @@ -11,26 +11,30 @@ Function Invoke-ExecTeamsVoicePhoneNumberAssignment { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $ExecutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Identity = $Request.Body.input.value $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)"} + $null = New-TeamsRequest -TenantFilter $TenantFilter -Cmdlet 'Set-CsPhoneNumberAssignment' -CmdParams @{LocationId = $Identity; 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)"} + $null = New-TeamsRequest -TenantFilter $TenantFilter -Cmdlet 'Set-CsPhoneNumberAssignment' -CmdParams @{Identity = $Identity; PhoneNumber = $Request.Body.PhoneNumber; PhoneNumberType = $Request.Body.PhoneNumberType; ErrorAction = 'stop' } + $Results = [pscustomobject]@{'Results' = "Successfully assigned $($Request.Body.PhoneNumber) to $($Identity)" } } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev 'Info' + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev Info + $StatusCode = [HttpStatusCode]::OK } 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' + $ErrorMessage = Get-CippException -Exception $_ + $Results = [pscustomobject]@{'Results' = $ErrorMessage.NormalizedError } + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $($TenantFilter) -message $($Results.Results) -Sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK + StatusCode = $StatusCode Body = $Results }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 index d94c6b0ce4bd..2d23640c9fcd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 @@ -10,72 +10,112 @@ Function Invoke-ListSites { [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 + $Type = $request.query.Type + $UserUPN = $request.query.UserUPN + if (!$TenantFilter) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = 'TenantFilter is required' + }) + return + } - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + if (!$Type) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = 'Type is required' + }) + return + } + + $Tenant = Get-Tenants -TenantFilter $TenantFilter + $TenantId = $Tenant.customerId + + if ($Type -eq 'SharePointSiteUsage') { + $Filter = 'isPersonalSite eq false' + } else { + $Filter = 'isPersonalSite eq true' + } - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $type = $request.query.Type - $UserUPN = $request.query.UserUPN try { - $Result = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv + $BulkRequests = @( + @{ + id = 'listAllSites' + method = 'GET' + url = "sites/getAllSites?`$filter=$($Filter)&`$select=id,createdDateTime,description,name,displayName,isPersonalSite,lastModifiedDateTime,webUrl,siteCollection,sharepointIds&`$top=999" + } + @{ + id = 'usage' + method = 'GET' + url = "reports/get$($type)Detail(period='D7')?`$format=application/json&`$top=999" + } + ) + + $Result = New-GraphBulkRequest -tenantid $TenantFilter -Requests @($BulkRequests) -asapp $true + $Sites = ($Result | Where-Object { $_.id -eq 'listAllSites' }).body.value + $UsageBase64 = ($Result | Where-Object { $_.id -eq 'usage' }).body + $UsageJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UsageBase64)) + $Usage = ($UsageJson | ConvertFrom-Json).value - if ($UserUPN) { - $ParsedRequest = $Result | Where-Object { $_.'Owner Principal Name' -eq $UserUPN } - } else { - $ParsedRequest = $Result + $GraphRequest = foreach ($Site in $Sites) { + $SiteUsage = $Usage | Where-Object { $_.siteId -eq $Site.sharepointIds.siteId } + [PSCustomObject]@{ + siteId = $Site.sharepointIds.siteId + webId = $Site.sharepointIds.webId + createdDateTime = $Site.createdDateTime + displayName = $Site.displayName + webUrl = $Site.webUrl + ownerDisplayName = $SiteUsage.ownerDisplayName + ownerPrincipalName = $SiteUsage.ownerPrincipalName + lastActivityDate = $SiteUsage.lastActivityDate + fileCount = $SiteUsage.fileCount + storageUsedInGigabytes = [math]::round($SiteUsage.storageUsedInBytes / 1GB, 2) + storageAllocatedInGigabytes = [math]::round($SiteUsage.storageAllocatedInBytes / 1GB, 2) + storageUsedInBytes = $SiteUsage.storageUsedInBytes + storageAllocatedInBytes = $SiteUsage.storageAllocatedInBytes + rootWebTemplate = $SiteUsage.rootWebTemplate + reportRefreshDate = $SiteUsage.reportRefreshDate + AutoMapUrl = '' + } } - $GraphRequest = $ParsedRequest | Select-Object AutoMapUrl, @{ Name = 'UPN'; Expression = { $_.'Owner Principal Name' } }, - @{ Name = 'displayName'; Expression = { $_.'Owner Display Name' } }, - @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, - @{ Name = 'FileCount'; Expression = { [int]$_.'File Count' } }, - @{ Name = 'UsedGB'; Expression = { [math]::round($_.'Storage Used (Byte)' / 1GB, 2) } }, - @{ Name = 'URL'; Expression = { $_.'Site URL' } }, - @{ Name = 'Allocated'; Expression = { [math]::round($_.'Storage Allocated (Byte)' / 1GB, 2) } }, - @{ Name = 'Template'; Expression = { $_.'Root Web Template' } }, - @{ Name = 'siteid'; Expression = { $_.'site Id' } } - #Temporary workaround for url as report is broken. - #This API is so stupid its great. - $URLs = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/getAllSites?$select=SharePointIds,name,webUrl,displayName,siteCollection' -asapp $true -tenantid $TenantFilter $int = 0 if ($Type -eq 'SharePointSiteUsage') { - $Requests = foreach ($url in $URLs) { + $Requests = foreach ($Site in $GraphRequest) { @{ id = $int++ method = 'GET' - url = "sites/$($url.sharepointIds.siteId)/lists?`$select=id,name,list,parentReference" + url = "sites/$($Site.siteId)/lists?`$select=id,name,list,parentReference" } } - $Requests = (New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true).body.value | Where-Object { $_.list.template -eq 'DocumentLibrary' } - } - $GraphRequest = foreach ($site in $GraphRequest) { - $SiteURLs = ($URLs.SharePointIds | Where-Object { $_.siteId -eq $site.SiteId }) - $site.URL = $SiteURLs.siteUrl - $ListId = ($Requests | Where-Object { $_.parentReference.siteId -like "*$($SiteURLs.siteId)*" }).id - $site.AutoMapUrl = "tenantId=$($SiteUrls.tenantId)&webId={$($SiteUrls.webId)}&siteid={$($SiteURLs.siteId)}&webUrl=$($SiteURLs.siteUrl)&listId={$($ListId)}" - $site + try { + $Requests = (New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true).body.value | Where-Object { $_.list.template -eq 'DocumentLibrary' } + } catch { + Write-LogMessage -Message "Error getting auto map urls: $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter -API 'ListSites' -LogData (Get-CippException -Exception $_) + } + $GraphRequest = foreach ($Site in $GraphRequest) { + $ListId = ($Requests | Where-Object { $_.parentReference.siteId -like "*$($Site.siteId)*" }).id + $site.AutoMapUrl = "tenantId=$($TenantId)&webId={$($Site.webId)}&siteid={$($Site.siteId)}&webUrl=$($Site.webUrl)&listId={$($ListId)}" + $site + } } - $StatusCode = [HttpStatusCode]::OK - + } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden $GraphRequest = $ErrorMessage } if ($Request.query.URLOnly -eq 'true') { - $GraphRequest = $GraphRequest | Where-Object { $null -ne $_.URL } + $GraphRequest = $GraphRequest | Where-Object { $null -ne $_.webUrl } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @($GraphRequest | Sort-Object -Property UPN) + Body = @($GraphRequest | Sort-Object -Property displayName) }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 index 2459ff22f13c..5dd1c14a4ede 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsVoice.ps1 @@ -21,12 +21,17 @@ Function Invoke-ListTeamsVoice { $TenantFilter = $Request.Query.TenantFilter $tenantid = (Get-Tenants | Where-Object -Property defaultDomainName -EQ $Request.Query.TenantFilter).customerId try { - $users = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=id,userPrincipalName,displayname" -tenantid $TenantFilter) + $users = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=id,userPrincipalName,displayName" -tenantid $TenantFilter) $skip = 0 $GraphRequest = do { $data = (New-TeamsAPIGetRequest -uri "https://api.interfaces.records.teams.microsoft.com/Skype.TelephoneNumberMgmt/Tenants/$($Tenantid)/telephone-numbers?skip=$($skip)&locale=en-US&top=999" -tenantid $TenantFilter).TelephoneNumbers | ForEach-Object { - $CompleteRequest = $_ | Select-Object *, 'AssignedTo' - $CompleteRequest.AcquisitionDate = $CompleteRequest.AcquisitionDate -split 'T' | Select-Object -First 1 + try { + $CompleteRequest = $_ | Select-Object *, 'AssignedTo', 'AcquisitionDate' -ErrorAction SilentlyContinue + $CompleteRequest.AcquisitionDate = $CompleteRequest.AcquisitionDate -split 'T' | Select-Object -First 1 + } catch { + $CompleteRequest = $_ | Select-Object *, 'AssignedTo' -ErrorAction SilentlyContinue + } + if ($CompleteRequest.TargetId -eq '00000000-0000-0000-0000-000000000000') { $CompleteRequest.AssignedTo = 'Unassigned' } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 index 2cbba9b5fa42..abbb442d17fa 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 @@ -11,38 +11,17 @@ Function Invoke-AddAlert { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $URL = ($request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 $Tenants = $request.body.tenantFilter - $Table = get-cipptable -TableName 'SchedulerConfig' - $Results = foreach ($Tenant in $Tenants) { - try { - Write-Host "Working on $($Tenant.value) - $($Tenant.fullValue.displayName)" - $CompleteObject = @{ - tenant = [string]$($Tenant.value) - tenantid = [string]$($Tenant.fullValue.customerId) - webhookType = [string]$request.body.logbook.value - type = 'webhookcreation' - RowKey = "$($Tenant.value)-$($request.body.logbook.value)" - PartitionKey = 'webhookcreation' - Configured = $false - CIPPURL = [string]$URL - } - Add-CIPPAzDataTableEntity @Table -Entity $CompleteObject -Force - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant.fullValue.defaultDomainName -message "Successfully added Audit Log Webhook for $($Tenant.fullValue.displayName) to queue." -Sev 'Info' - } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant.fullValue.defaultDomainName -message "Failed to add Audit Log Webhook for $($Tenant.fullValue.displayName) to queue" -Sev 'Error' - "Failed to add Alert for for $($Tenant) to queue $($_.Exception.message)" - } - } $Conditions = $request.body.conditions | ConvertTo-Json -Compress -Depth 10 | Out-String $TenantsJson = $Tenants | ConvertTo-Json -Compress -Depth 10 | Out-String $Actions = $request.body.actions | ConvertTo-Json -Compress -Depth 10 | Out-String + $RowKey = $Request.body.RowKey ? $Request.body.RowKey : (New-Guid).ToString() $CompleteObject = @{ Tenants = [string]$TenantsJson Conditions = [string]$Conditions Actions = [string]$Actions type = $request.body.logbook.value - RowKey = [string](New-Guid) + RowKey = $RowKey PartitionKey = 'Webhookv2' } $WebhookTable = get-cipptable -TableName 'WebhookRules' @@ -56,4 +35,4 @@ Function Invoke-AddAlert { Body = $body }) -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAuditLogSearch.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAuditLogSearch.ps1 index ee418b6b145b..9df2ffaf6737 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAuditLogSearch.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ExecAuditLogSearch.ps1 @@ -40,6 +40,7 @@ function Invoke-ExecAuditLogSearch { } try { + $Query = $Query | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashtable $Results = New-CippAuditLogSearch @Query Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 index 0b90937f4feb..fe7aaa7ebc88 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAlertsQueue.ps1 @@ -27,12 +27,12 @@ Function Invoke-ListAlertsQueue { $AllTasksArrayList = [system.collections.generic.list[object]]::new() foreach ($Task in $WebhookRules) { - $Conditions = $Task.Conditions | ConvertFrom-Json -ErrorAction SilentlyContinue + $Conditions = $Task.Conditions | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue $TranslatedConditions = ($Conditions | ForEach-Object { "When $($_.Property.label) is $($_.Operator.label) $($_.input.value)" }) -join ' and ' - $TranslatedActions = ($Task.Actions | ConvertFrom-Json -ErrorAction SilentlyContinue).label -join ',' - $Tenants = ($Task.Tenants | ConvertFrom-Json -ErrorAction SilentlyContinue).fullValue + $TranslatedActions = ($Task.Actions | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue).label -join ',' + $Tenants = ($Task.Tenants | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue) $TaskEntry = [PSCustomObject]@{ - Tenants = $Tenants.defaultDomainName -join ',' + Tenants = @($Tenants.label) Conditions = $TranslatedConditions Actions = $TranslatedActions LogType = $Task.type @@ -40,6 +40,15 @@ Function Invoke-ListAlertsQueue { RowKey = $Task.RowKey PartitionKey = $Task.PartitionKey RepeatsEvery = 'When received' + RawAlert = @{ + Conditions = @($Conditions) + Actions = @($($Task.Actions | ConvertFrom-Json -Depth 10 -ErrorAction SilentlyContinue)) + Tenants = @($Tenants) + type = $Task.type + RowKey = $Task.RowKey + PartitionKey = $Task.PartitionKey + + } } if ($AllowedTenants -notcontains 'AllTenants') { @@ -58,12 +67,13 @@ Function Invoke-ListAlertsQueue { $TaskEntry = [PSCustomObject]@{ RowKey = $Task.RowKey PartitionKey = $Task.PartitionKey - Tenants = $Task.Tenant + Tenants = @($Task.Tenant) Conditions = $Task.Name Actions = $Task.PostExecution LogType = 'Scripted' EventType = 'Scheduled Task' RepeatsEvery = $Task.Recurrence + RawAlert = $Task } if ($AllowedTenants -notcontains 'AllTenants') { $Tenant = $TenantList | Where-Object -Property defaultDomainName -EQ $Task.Tenant @@ -74,10 +84,12 @@ Function Invoke-ListAlertsQueue { $AllTasksArrayList.Add($TaskEntry) } } + + $finalList = ConvertTo-Json -InputObject @($AllTasksArrayList) -Depth 10 # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @($AllTasksArrayList) + Body = $finalList }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogs.ps1 index 2582bc961e74..c70fdcb98bdb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogs.ps1 @@ -22,7 +22,7 @@ function Invoke-ListAuditLogs { } if (!$Request.Query.StartDate -and !$Request.Query.EndDate -and !$Request.Query.RelativeTime) { - $Request.Query.StartDate = (Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $Request.Query.StartDate = (Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') $Request.Query.EndDate = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } @@ -42,7 +42,7 @@ function Invoke-ListAuditLogs { } else { if ($Request.Query.StartDate) { if ($Request.Query.StartDate -match '^\d+$') { - $Request.Query.StartDate = [DateTimeOffset]::FromUnixTimeSeconds($Request.Query.StartDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $StartDate = [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.Query.StartDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } else { $StartDate = (Get-Date $Request.Query.StartDate).ToString('yyyy-MM-ddTHH:mm:ssZ') } @@ -50,7 +50,7 @@ function Invoke-ListAuditLogs { if ($Request.Query.EndDate) { if ($Request.Query.EndDate -match '^\d+$') { - $Request.Query.EndDate = [DateTimeOffset]::FromUnixTimeSeconds($Request.Query.EndDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $EndDate = [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.Query.EndDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } else { $EndDate = (Get-Date $Request.Query.EndDate).ToString('yyyy-MM-ddTHH:mm:ssZ') } @@ -66,7 +66,7 @@ function Invoke-ListAuditLogs { } $AuditLogs = Get-CIPPAzDataTableEntity @Table | ForEach-Object { $_.Data = try { $_.Data | ConvertFrom-Json } catch { $_.AuditData } - $_ + $_ | Select-Object @{n = 'LogId'; exp = { $_.RowKey } }, @{ n = 'Timestamp'; exp = { $_.Data.RawData.CreationTime } }, Tenant, Title, Data } $Body = @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 index dd03e24f8b3d..f614bee7290e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecAddMultiTenantApp.ps1 @@ -22,10 +22,10 @@ function Invoke-ExecAddMultiTenantApp { } else { $Command = 'ExecAddMultiTenantApp' } - if ('allTenants' -in $Request.Body.SelectedTenants.defaultDomainName) { + if ('allTenants' -in $Request.Body.tenantFilter.value) { $TenantFilter = (Get-Tenants).defaultDomainName } else { - $TenantFilter = $Request.Body.SelectedTenants.defaultDomainName + $TenantFilter = $Request.Body.tenantFilter.value } $TenantCount = ($TenantFilter | Measure-Object).Count diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 index 4a5cdd8708bc..c256f36c97e0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOffboardTenant.ps1 @@ -12,15 +12,15 @@ Function Invoke-ExecOffboardTenant { try { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.body.tenantfilter - - # temp fix -rvdwegen - $tenantId = (Invoke-RestMethod -Method GET "https://login.windows.net/$Tenantfilter/.well-known/openid-configuration").token_endpoint.Split('/')[3] + $TenantQuery = $Request.Body.TenantFilter.value ?? $Request.Body.TenantFilter + $Tenant = Get-Tenants -IncludeAll -TenantFilter $TenantQuery + $TenantId = $Tenant.customerId + $TenantFilter = $Tenant.defaultDomainName $results = [System.Collections.ArrayList]@() $errors = [System.Collections.ArrayList]@() - if ($request.body.RemoveCSPGuestUsers) { + if ($request.body.RemoveCSPGuestUsers -eq $true) { # Delete guest users who's domains match the CSP tenants try { try { @@ -42,7 +42,7 @@ Function Invoke-ExecOffboardTenant { $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter $results.Add('Successfully removed guest users') - Write-LogMessage -user $ExecutingUser -API $APIName -message "CSP Guest users were removed" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message 'CSP Guest users were removed' -Sev 'Info' -tenant $TenantFilter } else { $results.Add('No guest users found to remove') } @@ -51,7 +51,7 @@ Function Invoke-ExecOffboardTenant { } } - if ($request.body.RemoveCSPnotificationContacts) { + if ($request.body.RemoveCSPnotificationContacts -eq $true) { # Remove all email adresses that match the CSP tenants domains from the contact properties in /organization try { try { @@ -72,19 +72,19 @@ Function Invoke-ExecOffboardTenant { } # foreach through the properties we want to check/update - @('marketingNotificationEmails','securityComplianceNotificationMails','technicalNotificationMails') | ForEach-Object { + @('marketingNotificationEmails', 'securityComplianceNotificationMails', 'technicalNotificationMails') | ForEach-Object { $property = $_ $propertyContacts = $orgContacts.($($property)) - if ($propertyContacts -AND ($domains -notcontains ($propertyContacts | ForEach-Object { $_.Split("@")[1] }))) { - $newPropertyContent = [System.Collections.Generic.List[object]]($propertyContacts | Where-Object { $domains -notcontains $_.Split("@")[1] }) + if ($propertyContacts -AND ($domains -notcontains ($propertyContacts | ForEach-Object { $_.Split('@')[1] }))) { + $newPropertyContent = [System.Collections.Generic.List[object]]($propertyContacts | Where-Object { $domains -notcontains $_.Split('@')[1] }) $patchContactBody = if (!($newPropertyContent)) { "{ `"$($property)`" : [] }" } else { [pscustomobject]@{ $property = $newPropertyContent } | ConvertTo-Json } try { - New-GraphPostRequest -type PATCH -body $patchContactBody -Uri "https://graph.microsoft.com/v1.0/organization/$($orgContacts.id)" -tenantid $Tenantfilter -ContentType "application/json" - $results.Add("Successfully removed notification contacts from $($property): $(($propertyContacts | Where-Object { $domains -contains $_.Split("@")[1] }))") - Write-LogMessage -user $ExecutingUser -API $APIName -message "Contacts were removed from $($property)" -Sev "Info" -tenant $TenantFilter + New-GraphPostRequest -type PATCH -body $patchContactBody -Uri "https://graph.microsoft.com/v1.0/organization/$($orgContacts.id)" -tenantid $Tenantfilter -ContentType 'application/json' + $results.Add("Successfully removed notification contacts from $($property): $(($propertyContacts | Where-Object { $domains -contains $_.Split('@')[1] }))") + Write-LogMessage -user $ExecutingUser -API $APIName -message "Contacts were removed from $($property)" -Sev 'Info' -tenant $TenantFilter } catch { $errors.Add("Failed to update property $($property): $($_.Exception.message)") } @@ -95,13 +95,13 @@ Function Invoke-ExecOffboardTenant { # Add logic for privacyProfile later - rvdwegen } - - if ($request.body.RemoveVendorApps) { - $request.body.RemoveVendorApps | ForEach-Object { + $VendorApps = $Request.Body.vendorApplications + if ($VendorApps) { + $VendorApps | ForEach-Object { try { $delete = (New-GraphPostRequest -type 'DELETE' -Uri "https://graph.microsoft.com/v1.0/serviceprincipals/$($_.value)" -tenantid $Tenantfilter) $results.Add("Successfully removed app $($_.label)") - Write-LogMessage -user $ExecutingUser -API $APIName -message "App $($_.label) was removed" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "App $($_.label) was removed" -Sev 'Info' -tenant $TenantFilter } catch { #$results.Add("Failed to removed app $($_.displayName)") $errors.Add("Failed to removed app $($_.label)") @@ -110,7 +110,7 @@ Function Invoke-ExecOffboardTenant { } # All customer tenant specific actions ALWAYS have to be completed before this action! - if ($request.body.RemoveMultitenantCSPApps) { + if ($request.body.RemoveMultitenantCSPApps -eq $true) { # Remove multi-tenant apps with the CSP tenant as origin try { $multitenantCSPApps = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$count=true&`$select=displayName,appId,id,appOwnerOrganizationId&`$filter=appOwnerOrganizationId eq $($env:TenantID)" -tenantid $Tenantfilter -ComplexFilter) @@ -119,7 +119,7 @@ Function Invoke-ExecOffboardTenant { try { $delete = (New-GraphPostRequest -type 'DELETE' -Uri "https://graph.microsoft.com/v1.0/serviceprincipals/$($_.id)" -tenantid $Tenantfilter) $results.Add("Successfully removed app $($_.displayName)") - Write-LogMessage -user $ExecutingUser -API $APIName -message "App $($_.displayName) was removed" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "App $($_.displayName) was removed" -Sev 'Info' -tenant $TenantFilter } catch { #$results.Add("Failed to removed app $($_.displayName)") $errors.Add("Failed to removed app $($_.displayName)") @@ -130,19 +130,18 @@ Function Invoke-ExecOffboardTenant { $errors.Add("Failed to retrieve multitenant CSP apps, no apps have been removed: $($_.Exception.message)") } } - - if ($request.body.TerminateGDAP) { + $ClearCache = $false + if ($request.body.TerminateGDAP -eq $true) { # Terminate GDAP relationships + $ClearCache = $true try { - $TenantFilter - $TenantFilter - $TenantFilter $delegatedAdminRelationships = (New-GraphGETRequest -Uri "https://graph.microsoft.com/v1.0/tenantRelationships/delegatedAdminRelationships?`$filter=(status eq 'active') AND (customer/tenantId eq '$tenantid')" -tenantid $env:TenantID) $delegatedAdminRelationships | ForEach-Object { try { $terminate = (New-GraphPostRequest -type 'POST' -Uri "https://graph.microsoft.com/v1.0/tenantRelationships/delegatedAdminRelationships/$($_.id)/requests" -body '{"action":"terminate"}' -ContentType 'application/json' -tenantid $env:TenantID) $results.Add("Successfully terminated GDAP relationship $($_.displayName) from tenant $TenantFilter") - Write-LogMessage -user $ExecutingUser -API $APIName -message "GDAP Relationship $($_.displayName) has been terminated" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message "GDAP Relationship $($_.displayName) has been terminated" -Sev 'Info' -tenant $TenantFilter + } catch { $($_.Exception.message) #$results.Add("Failed to terminate GDAP relationship $($_.displayName): $($_.Exception.message)") @@ -156,18 +155,23 @@ Function Invoke-ExecOffboardTenant { } } - if ($request.body.TerminateContract) { + if ($request.body.TerminateContract -eq $true) { # Terminate contract relationship try { $terminate = (New-GraphPostRequest -type 'PATCH' -body '{ "relationshipToPartner": "none" }' -Uri "https://api.partnercenter.microsoft.com/v1/customers/$TenantFilter" -ContentType 'application/json' -scope 'https://api.partnercenter.microsoft.com/user_impersonation' -tenantid $env:TenantID) $results.Add('Successfully terminated contract relationship') - Write-LogMessage -user $ExecutingUser -API $APIName -message "Contract relationship terminated" -Sev "Info" -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message 'Contract relationship terminated' -Sev 'Info' -tenant $TenantFilter } catch { #$results.Add("Failed to terminate contract relationship: $($_.Exception.message)") $errors.Add("Failed to terminate contract relationship: $($_.Exception.message)") } } + if ($ClearCache) { + $null = Get-Tenants -CleanOld + $Results.Add('Tenant cache has been cleared') + } + $StatusCode = [HttpStatusCode]::OK $body = [pscustomobject]@{ 'Results' = @($results) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 index 4cf6b08f6cec..70576362b561 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecOnboardTenant.ps1 @@ -16,7 +16,7 @@ function Invoke-ExecOnboardTenant { try { $OnboardTable = Get-CIPPTable -TableName 'TenantOnboarding' - if ($Request.Query.Cancel -eq $true) { + if ($Request.Body.Cancel -eq $true) { $TenantOnboarding = Get-CIPPAzDataTableEntity @OnboardTable -Filter "RowKey eq '$Id'" if ($TenantOnboarding) { Remove-AzDataTableEntity -Force @OnboardTable -Entity $TenantOnboarding @@ -27,9 +27,9 @@ function Invoke-ExecOnboardTenant { $StatusCode = [HttpStatusCode]::NotFound } } else { - $TenMinutesAgo = (Get-Date).AddMinutes(-10).ToString('yyyy-MM-ddTHH:mm:ssZ') + $TenMinutesAgo = (Get-Date).AddMinutes(-10).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') $TenantOnboarding = Get-CIPPAzDataTableEntity @OnboardTable -Filter "RowKey eq '$Id' and Timestamp ge datetime'$TenMinutesAgo'" - if (!$TenantOnboarding -or [bool]$Request.Query.Retry) { + if (!$TenantOnboarding -or [bool]$Request.Body.Retry) { $OnboardingSteps = [PSCustomObject]@{ 'Step1' = @{ 'Status' = 'pending' @@ -74,6 +74,7 @@ function Invoke-ExecOnboardTenant { id = $Id Roles = $Request.Body.gdapRoles AddMissingGroups = $Request.Body.addMissingGroups + IgnoreMissingRoles = $Request.Body.ignoreMissingRoles AutoMapRoles = $Request.Body.autoMapRoles StandardsExcludeAllTenants = $Request.Body.standardsExcludeAllTenants } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecUpdateSecureScore.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecUpdateSecureScore.ps1 index 502a9e6f4896..cef9df318e34 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecUpdateSecureScore.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ExecUpdateSecureScore.ps1 @@ -16,7 +16,7 @@ Function Invoke-ExecUpdateSecureScore { # Interact with query parameters or the body of the request. $Body = @{ comment = $request.body.reason - state = $request.body.resolutionType + state = $request.body.resolutionType.value vendorInformation = $request.body.vendorInformation } try { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 index f8821c051a8a..8fee5dbf56f8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListTenantOnboarding.ps1 @@ -12,25 +12,26 @@ function Invoke-ListTenantOnboarding { try { $OnboardTable = Get-CIPPTable -TableName 'TenantOnboarding' $TenantOnboardings = Get-CIPPAzDataTableEntity @OnboardTable - $Results = foreach ($TenantOnboarding in $TenantOnboardings) { - $Steps = $TenantOnboarding.OnboardingSteps | ConvertFrom-Json - $OnboardingSteps = foreach ($Step in $Steps.PSObject.Properties.Name) { $Steps.$Step } - $Relationship = try { $TenantOnboarding.Relationship | ConvertFrom-Json -ErrorAction Stop } catch { @{} } - $Logs = try { $TenantOnboarding.Logs | ConvertFrom-Json -ErrorAction Stop } catch { @{} } - $TenantOnboarding.OnboardingSteps = $OnboardingSteps - $TenantOnboarding.Relationship = $Relationship - $TenantOnboarding.Logs = $Logs - $TenantOnboarding - } + $Results = @(foreach ($TenantOnboarding in $TenantOnboardings) { + $Steps = $TenantOnboarding.OnboardingSteps | ConvertFrom-Json + $OnboardingSteps = foreach ($Step in $Steps.PSObject.Properties.Name) { $Steps.$Step } + $Relationship = try { $TenantOnboarding.Relationship | ConvertFrom-Json -ErrorAction Stop } catch { @{} } + $Logs = try { $TenantOnboarding.Logs | ConvertFrom-Json -ErrorAction Stop } catch { @{} } + $TenantOnboarding.OnboardingSteps = $OnboardingSteps + $TenantOnboarding.Relationship = $Relationship + $TenantOnboarding.Logs = $Logs + $TenantOnboarding + }) + $Results = $Results | Sort-Object Timestamp -Descending $StatusCode = [HttpStatusCode]::OK } catch { - $ErrorMsg = Get-NormalizedError -message $($_.Exception.Message) - $Results = "Function Error: $($_.InvocationInfo.ScriptLineNumber) - $ErrorMsg" + $ErrorMessage = Get-CippException -Exception $_ + $Results = "Function Error: $($ErrorMessage.LineNumber) - $($ErrorMessage.NormalizedError)" $StatusCode = [HttpStatusCode]::BadRequest } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = $Results + Body = @($Results) }) -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 deleted file mode 100644 index fe98eae2eee1..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-EditTenant.ps1 +++ /dev/null @@ -1,66 +0,0 @@ -using namespace System.Net - -Function Invoke-EditTenant { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - CIPP.Core.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $tenantDisplayName = $request.body.displayName - $tenantDefaultDomainName = $request.body.defaultDomainName - $Tenant = $request.body.tenantid - $customerContextId = $request.body.customerId - - $tokens = try { - $AADGraphtoken = (Get-GraphToken -scope 'https://graph.windows.net/.default') - $allTenantsDetails = (Invoke-RestMethod -Method GET -Uri 'https://graph.windows.net/myorganization/contracts?api-version=1.6' -ContentType 'application/json' -Headers $AADGraphtoken) - $tenantObjectId = $allTenantsDetails.value | Where-Object { $_.customerContextId -eq $customerContextId } | Select-Object 'objectId' - } - catch { - $Results = "Failed to retrieve list of tenants. Error: $($_.Exception.Message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($tenantDisplayName) -message "Failed to retrieve list of tenants. Error:$($_.Exception.Message)" -Sev 'Error' - } - - - if ($tenantObjectId) { - try { - $bodyToPatch = '{"displayName":"' + $tenantDisplayName + '","defaultDomainName":"' + $tenantDefaultDomainName + '"}' - $patchTenant = (Invoke-RestMethod -Method PATCH -Uri "https://graph.windows.net/myorganization/contracts/$($tenantObjectId.objectId)?api-version=1.6" -Body $bodyToPatch -ContentType 'application/json' -Headers $AADGraphtoken -ErrorAction Stop) - $Filter = "PartitionKey eq 'Tenants' and defaultDomainName eq '{0}'" -f $tenantDefaultDomainName - try { - $TenantsTable = Get-CippTable -tablename Tenants - $Tenant = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - $Tenant.displayName = $tenantDisplayName - Update-AzDataTableEntity @TenantsTable -Entity $Tenant - } - catch { - $AddedText = 'but could not edit the tenant cache. Clear the tenant cache to display the updated details' - } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Edited tenant $tenantDisplayName" -Sev 'Info' - $results = "Successfully amended details for $($Tenant.displayName) $AddedText" - } - catch { - $results = "Failed to amend details for $tenantDisplayName : $($_.Exception.Message)" - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenantDisplayName -message "Failed amending details $tenantDisplayName. Error:$($_.Exception.Message)" -Sev 'Error' - } - } - else { - $Results = 'Could not find the tenant to edit in the contract endpoint. Please ensure you have a reseller relationship with the tenant you are trying to edit.' - } - - $body = [pscustomobject]@{'Results' = $results } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 index 001c8ac2cbcd..2b63da2523bd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenantDetails.ps1 @@ -14,38 +14,27 @@ Function Invoke-ListTenantDetails { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $tenantfilter = $Request.Query.TenantFilter + try { - $tenantfilter = $Request.Query.TenantFilter $org = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $tenantfilter | Select-Object displayName, id, city, country, countryLetterCode, street, state, postalCode, @{ Name = 'businessPhones'; Expression = { $_.businessPhones -join ', ' } }, @{ Name = 'technicalNotificationMails'; Expression = { $_.technicalNotificationMails -join ', ' } }, tenantType, createdDateTime, onPremisesLastPasswordSyncDateTime, onPremisesLastSyncDateTime, onPremisesSyncEnabled, assignedPlans - } catch { - $org = [PSCustomObject]@{ - displayName = 'Error loading tenant' - id = '' - city = '' - country = '' - countryLetterCode = '' - street = '' - state = '' - postalCode = '' - businessPhones = '' - technicalNotificationMails = '' - createdDateTime = '' - onPremisesLastPasswordSyncDateTime = '' - onPremisesLastSyncDateTime = '' - onPremisesSyncEnabled = '' - assignedPlans = @() - } - } finally { - $Body = $org - } - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body - }) + # Respond with the successful output + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $org + }) + } catch { + # Log the exception message + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Error: $($_.Exception.Message)" -Sev 'Error' + # Respond with a 500 error and include the exception message in the response body + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = Get-NormalizedError -message $_.Exception.Message + }) + } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 index 7e3d3da4e22c..4227a6f78be8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 @@ -14,6 +14,7 @@ Function Invoke-ListTenants { Write-LogMessage -user $Request.Headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $TenantAccess = Test-CIPPAccess -Request $Request -TenantList + Write-Host "Tenant Access: $TenantAccess" if ($TenantAccess -notcontains 'AllTenants') { $AllTenantSelector = $false @@ -45,7 +46,20 @@ Function Invoke-ListTenants { return } if ($Request.Query.TriggerRefresh) { - Get-Tenants -IncludeAll -TriggerRefresh + if ($Request.Query.TenantFilter -and $Request.Query.TenantFilter -ne 'AllTenants') { + Get-Tenants -TriggerRefresh -TenantFilter $Request.Query.TenantFilter + } else { + $InputObject = [PSCustomObject]@{ + Batch = @( + @{ + FunctionName = 'UpdateTenants' + } + ) + OrchestratorName = 'UpdateTenants' + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Compress -Depth 5) + } } try { $tenantfilter = $Request.Query.TenantFilter diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 index 7ced88078c10..e1f21ae1e974 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCAPolicy.ps1 @@ -13,7 +13,7 @@ Function Invoke-AddCAPolicy { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenants = ($Request.body | Select-Object Select_*).psobject.properties.value + $Tenants = $Request.body.tenantFilter.value if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants).defaultDomainName } $results = foreach ($Tenant in $tenants) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 index 339cbf077481..ade9db4a3232 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddCATemplate.ps1 @@ -13,7 +13,7 @@ Function Invoke-AddCATemplate { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Body.TenantFilter try { $GUID = (New-Guid).GUID $JSON = New-CIPPCATemplate -TenantFilter $TenantFilter -JSON $request.body diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 index 47dd98aa75dd..bdf30b746d29 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-AddNamedLocation.ps1 @@ -18,7 +18,7 @@ Function Invoke-AddNamedLocation { Write-Host 'PowerShell HTTP trigger function processed a request.' # Input bindings are passed in via param block. - $Tenants = $request.body.selectedTenants.defaultDomainName + $Tenants = $request.body.selectedTenants.value Write-Host ($Request.body | ConvertTo-Json) if ($Tenants -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } $results = foreach ($Tenant in $tenants) { @@ -32,8 +32,7 @@ Function Invoke-AddNamedLocation { ipRanges = @($IPRanges) isTrusted = $Request.body.Trusted } - } - else { + } else { [pscustomobject]@{ '@odata.type' = '#microsoft.graph.countryNamedLocation' displayName = $request.body.policyName @@ -46,8 +45,7 @@ Function Invoke-AddNamedLocation { "Successfully added Named Location for $($Tenant)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Added Named Location $($Displayname)" -Sev 'Info' - } - catch { + } catch { "Failed to add Named Location $($Tenant): $($_.Exception.Message)" Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $tenant -message "Failed adding Named Location$($Displayname). Error: $($_.Exception.Message)" -Sev 'Error' continue 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 cca477e4a3ce..56bdb6a64bea 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 @@ -23,7 +23,6 @@ Function Invoke-EditCAPolicy { } 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 } $body = [pscustomobject]@{'Results' = $results } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 index e1961e25313e..833586fb2298 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecNamedLocation.ps1 @@ -17,10 +17,10 @@ Function Invoke-ExecNamedLocation { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $TenantFilter = $Request.Body.TenantFilter - $NamedLocationId = $Request.Body.NamedLocationId - $change = $Request.Body.change - $content = $Request.Body.input + $TenantFilter = $Request.Body.TenantFilter ?? $Request.Query.TenantFilter + $NamedLocationId = $Request.Body.NamedLocationId ?? $Request.Query.NamedLocationId + $change = $Request.Body.change ?? $Request.Query.change + $content = $Request.Body.input ?? $Request.Query.input try { $results = Set-CIPPNamedLocation -NamedLocationId $NamedLocationId -TenantFilter $TenantFilter -change $change -content $content -ExecutingUser $request.headers.'x-ms-client-principal' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 index 7f4be467dd3a..41cbaaa0b1ca 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListCAtemplates.ps1 @@ -18,17 +18,23 @@ Function Invoke-ListCAtemplates { Write-Host $Request.query.id #Migrating old policies whenever you do a list $Table = Get-CippTable -tablename 'templates' - - $Templates = Get-ChildItem 'Config\*.CATemplate.json' | ForEach-Object { - $Entity = @{ - JSON = "$(Get-Content $_)" - RowKey = "$($_.name)" - PartitionKey = 'CATemplate' - GUID = "$($_.name)" + $Imported = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'settings'" + if ($Imported.CATemplate -ne $true) { + $Templates = Get-ChildItem 'Config\*.CATemplate.json' | ForEach-Object { + $Entity = @{ + JSON = "$(Get-Content $_)" + RowKey = "$($_.name)" + PartitionKey = 'CATemplate' + GUID = "$($_.name)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force } - Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + Add-CIPPAzDataTableEntity @Table -Entity @{ + CATemplate = $true + RowKey = 'CATemplate' + PartitionKey = 'settings' + } -Force } - #List new policies $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'CATemplate'" 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 9bf0ae558577..63d372e6c1c7 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 @@ -174,8 +174,8 @@ Function Invoke-ListConditionalAccessPolicies { displayName = $cap.displayName customer = $cap.Customer tenantID = $cap.TenantID - createdDateTime = $(if (![string]::IsNullOrEmpty($cap.createdDateTime)) { [datetime]$cap.createdDateTime | Get-Date -Format 'yyyy-MM-dd HH:mm' }else { '' }) - modifiedDateTime = $(if (![string]::IsNullOrEmpty($cap.modifiedDateTime)) { [datetime]$cap.modifiedDateTime | Get-Date -Format 'yyyy-MM-dd HH:mm' }else { '' }) + createdDateTime = $(if (![string]::IsNullOrEmpty($cap.createdDateTime)) { [datetime]$cap.createdDateTime } else { '' }) + modifiedDateTime = $(if (![string]::IsNullOrEmpty($cap.modifiedDateTime)) { [datetime]$cap.modifiedDateTime }else { '' }) state = $cap.state clientAppTypes = ($cap.conditions.clientAppTypes) -join ',' includePlatforms = ($cap.conditions.platforms.includePlatforms) -join ',' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 index f2ca561c1b36..922357511af4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAddGDAPRole.ps1 @@ -12,51 +12,111 @@ Function Invoke-ExecAddGDAPRole { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Groups = $Request.body.gdapRoles + + $CippDefaults = @( + @{ label = 'Application Administrator'; value = '9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3' }, + @{ label = 'User Administrator'; value = 'fe930be7-5e62-47db-91af-98c3a49a38b1' }, + @{ label = 'Intune Administrator'; value = '3a2c62db-5318-420d-8d74-23affee5d9d5' }, + @{ label = 'Exchange Administrator'; value = '29232cdf-9323-42fd-ade2-1d097af3e4de' }, + @{ label = 'Security Administrator'; value = '194ae4cb-b126-40b2-bd5b-6091b380977d' }, + @{ label = 'Cloud App Security Administrator'; value = '892c5842-a9a6-463a-8041-72aa08ca3cf6' }, + @{ label = 'Cloud Device Administrator'; value = '7698a772-787b-4ac8-901f-60d6b08affd2' }, + @{ label = 'Teams Administrator'; value = '69091246-20e8-4a56-aa4d-066075b2a7a8' }, + @{ label = 'Sharepoint Administrator'; value = 'f28a1f50-f6e7-4571-818b-6a12f2af6b6c' }, + @{ label = 'Authentication Policy Administrator'; value = '0526716b-113d-4c15-b2c8-68e3c22b9f80' }, + @{ label = 'Privileged Role Administrator'; value = 'e8611ab8-c189-46e8-94e1-60213ab1f814' }, + @{ label = 'Privileged Authentication Administrator'; value = '7be44c8a-adaf-4e2a-84d6-ab2649e08a13' } + ) + + $Groups = $Request.body.gdapRoles ?? $CippDefaults + $CustomSuffix = $Request.body.customSuffix $Table = Get-CIPPTable -TableName 'GDAPRoles' $Results = [System.Collections.Generic.List[string]]::new() + $Requests = [System.Collections.Generic.List[object]]::new() $ExistingGroups = New-GraphGetRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID -AsApp $true - $RoleMappings = foreach ($group in $Groups) { + $ExistingRoleMappings = foreach ($Group in $Groups) { + $RoleName = $Group.label ?? $Group.Name + $Value = $Group.value ?? $Group.ObjectId + if ($CustomSuffix) { - $GroupName = "M365 GDAP $($Group.Name) - $CustomSuffix" - $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))$($CustomSuffix)" + $GroupName = "M365 GDAP $($RoleName) - $CustomSuffix" + $MailNickname = "M365GDAP$(($RoleName).replace(' ',''))$($CustomSuffix.replace(' ',''))" } else { - $GroupName = "M365 GDAP $($Group.Name)" - $MailNickname = "M365GDAP$(($Group.Name).replace(' ',''))" + $GroupName = "M365 GDAP $($RoleName)" + $MailNickname = "M365GDAP$(($RoleName).replace(' ',''))" } - try { - if ($GroupName -in $ExistingGroups.displayName) { - @{ - PartitionKey = 'Roles' - RowKey = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id - RoleName = $Group.Name - GroupName = $GroupName - GroupId = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id - roleDefinitionId = $group.ObjectId - } - $Results.Add("M365 GDAP $($Group.Name) already exists") + + if ($GroupName -in $ExistingGroups.displayName) { + @{ + PartitionKey = 'Roles' + RowKey = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id + RoleName = $RoleName + GroupName = $GroupName + GroupId = ($ExistingGroups | Where-Object -Property displayName -EQ $GroupName).id + roleDefinitionId = $Value + } + $Results.Add("$GroupName already exists") + } else { + $Requests.Add(@{ + id = $Value + url = '/groups' + method = 'POST' + headers = @{ + 'Content-Type' = 'application/json' + } + body = @{ + displayName = $GroupName + description = "This group is used to manage M365 partner tenants at the $($RoleName) level." + securityEnabled = $true + mailEnabled = $false + mailNickname = $MailNickname + } + }) + } + } + if ($ExistingRoleMappings) { + Add-CIPPAzDataTableEntity @Table -Entity $ExistingRoleMappings -Force + } + + if ($Requests) { + $ReturnedData = New-GraphBulkRequest -Requests $Requests -tenantid $env:TenantID -NoAuthCheck $True -asapp $true + $NewRoleMappings = foreach ($Return in $ReturnedData) { + if ($Return.body.error) { + $Results.Add("Could not create GDAP group: $($Return.body.error.message)") } else { - $BodyToship = [pscustomobject] @{'displayName' = $GroupName; 'description' = "This group is used to manage M365 partner tenants at the $($group.name) level."; securityEnabled = $true; mailEnabled = $false; mailNickname = $MailNickname } | ConvertTo-Json - $GraphRequest = New-GraphPostRequest -NoAuthCheck $True -uri 'https://graph.microsoft.com/beta/groups' -tenantid $env:TenantID -type POST -body $BodyToship -AsApp $true + $GroupName = $Return.body.displayName @{ PartitionKey = 'Roles' - RowKey = $GraphRequest.Id - RoleName = $Group.Name - GroupName = $GroupName - GroupId = $GraphRequest.Id - roleDefinitionId = $group.ObjectId + RowKey = $Return.body.id + RoleName = $Return.body.displayName -replace '^M365 GDAP ', '' -replace " - $CustomSuffix$", '' + GroupName = $Return.body.displayName + GroupId = $Return.body.id + roleDefinitionId = $Return.id } - $Results.Add("$GroupName added successfully") + $Results.Add("Created $($GroupName)") } - } catch { - $Results.Add("Could not create GDAP group $($GroupName): $($_.Exception.Message)") + } + Write-Information ($NewRoleMappings | ConvertTo-Json -Depth 10 -Compress) + if ($NewRoleMappings) { + Add-CIPPAzDataTableEntity @Table -Entity $NewRoleMappings -Force } } - Add-CIPPAzDataTableEntity @Table -Entity $RoleMappings -Force + $RoleMappings = [System.Collections.Generic.List[object]]::new() + if ($ExistingRoleMappings) { + $RoleMappings.AddRange(@($ExistingRoleMappings)) + } + if ($NewRoleMappings) { + $RoleMappings.AddRange(@($NewRoleMappings)) + } + + if ($Request.Body.templateId) { + Add-CIPPGDAPRoleTemplate -TemplateId $Request.Body.templateId -RoleMappings ($RoleMappings | Select-Object -Property RoleName, GroupName, GroupId, roleDefinitionId) + $Results.Add("Added role mappings to template $($Request.Body.templateId)") + } $body = @{Results = @($Results) } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 index f57c65330f6f..6ef66517cef1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecAutoExtendGDAP.ps1 @@ -10,11 +10,8 @@ Function Invoke-ExecAutoExtendGDAP { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Interact with query parameters or the body of the request. - $Results = Set-CIPPGDAPAutoExtend -RelationShipid $Request.query.ID + $Id = $Request.query.ID ?? $Request.Body.ID + $Results = Set-CIPPGDAPAutoExtend -RelationShipid $Id # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 index 61164e8968be..2d0c88112d0b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRelationship.ps1 @@ -14,7 +14,7 @@ Function Invoke-ExecDeleteGDAPRelationship { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $GDAPID = $request.query.GDAPId + $GDAPID = $Request.Query.GDAPId ?? $Request.Body.GDAPId try { $DELETE = New-GraphPostRequest -NoAuthCheck $True -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$($GDAPID)/requests" -type POST -body '{"action":"terminate"}' -tenantid $env:TenantID $Results = [pscustomobject]@{'Results' = "Success. GDAP relationship for $($GDAPID) been revoked" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 index 05115ce42df2..a2758b8e8341 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecDeleteGDAPRoleMapping.ps1 @@ -14,13 +14,13 @@ Function Invoke-ExecDeleteGDAPRoleMapping { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Table = Get-CIPPTable -TableName 'GDAPRoles' - Write-Host $Table + $GroupId = $Request.Query.GroupId ?? $Request.Body.GroupId try { - $Filter = "PartitionKey eq 'Roles' and RowKey eq '{0}'" -f $Request.Query.GroupId + $Filter = "PartitionKey eq 'Roles' and RowKey eq '{0}'" -f $GroupId $Entity = Get-CIPPAzDataTableEntity @Table -Filter $Filter Remove-AzDataTableEntity -Force @Table -Entity $Entity $Results = [pscustomobject]@{'Results' = 'Success. GDAP relationship mapping deleted' } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "GDAP relationship mapping deleted for $($Request.Query.GroupId)" -Sev 'Info' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "GDAP relationship mapping deleted for $($GroupId)" -Sev 'Info' } catch { $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 index f93ae96552ba..e46e64443e1e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPInvite.ps1 @@ -12,7 +12,7 @@ Function Invoke-ExecGDAPInvite { $APIName = 'ExecGDAPInvite' Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $RoleMappings = $Request.Body.gdapRoles + $RoleMappings = $Request.Body.roleMappings if ($RoleMappings.roleDefinitionId -contains '62e90394-69f5-4237-9190-012177145e10') { $AutoExtendDuration = 'PT0S' @@ -24,7 +24,7 @@ Function Invoke-ExecGDAPInvite { try { $Step = 'Creating GDAP relationship' $JSONBody = @{ - 'displayName' = "$((New-Guid).GUID)" + 'displayName' = "CIPP_$((New-Guid).GUID)" 'accessDetails' = @{ 'unifiedRoles' = @($RoleMappings | Select-Object roleDefinitionId) } @@ -58,8 +58,7 @@ Function Invoke-ExecGDAPInvite { $InviteUrl = "https://admin.microsoft.com/AdminPortal/Home#/partners/invitation/granularAdminRelationships/$($NewRelationship.id)" try { $Uri = ([System.Uri]$TriggerMetadata.Headers.Referer) - $TableFilter = [System.Web.HttpUtility]::UrlEncode(('Complex: id eq {0}' -f $NewRelationship.id)) - $OnboardingUrl = $Uri.AbsoluteUri.Replace($Uri.PathAndQuery, "/tenant/administration/tenant-onboarding-wizard?tableFilter=$TableFilter") + $OnboardingUrl = $Uri.AbsoluteUri.Replace($Uri.PathAndQuery, "/tenant/gdap-management/onboarding/start?id=$($NewRelationship.id)") } catch { $OnboardingUrl = $null } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 index c6a60971f1c6..6a41ac39fb5f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRemoveGArole.ps1 @@ -9,10 +9,7 @@ Function Invoke-ExecGDAPRemoveGArole { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $GDAPID = $request.query.GDAPId + $GDAPID = $request.query.GDAPId ?? $request.Body.GDAPId try { $CheckActive = New-GraphGetRequest -NoAuthCheck $True -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$($GDAPID)" -tenantid $env:TenantID @@ -36,7 +33,7 @@ Function Invoke-ExecGDAPRemoveGArole { $Message = "Relationship status is currently $($CheckActive.status), it is not possible to remove the Global Administrator role in this state." } if ('62e90394-69f5-4237-9190-012177145e10' -notin $CheckActive.accessDetails.unifiedRoles.roleDefinitionId) { - $Message = "This relationship does not contain the Global Administrator role." + $Message = 'This relationship does not contain the Global Administrator role.' } } } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 new file mode 100644 index 000000000000..678015e11e83 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 @@ -0,0 +1,93 @@ +using namespace System.Net + +Function Invoke-ExecGDAPRoleTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Relationship.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Table = Get-CIPPTable -TableName 'GDAPRoleTemplates' + $Templates = Get-CIPPAzDataTableEntity @Table + + if ($Request.Query.TemplateId) { + $Template = $Templates | Where-Object -Property RowKey -EQ $Request.Query.TemplateId + if (!$Template) { + $Body = @{} + } else { + $Body = @{ + TemplateId = $Template.RowKey + RoleMappings = @($Template.RoleMappings | ConvertFrom-Json) + } + } + } else { + switch ($Request.Query.Action) { + 'Add' { + $RowKey = ($Request.Body | Select-Object -First 1 -ExpandProperty TemplateId).value ?? $Request.Body.TemplateId + if ($Request.Body.GroupId) { + $RoleMappings = $Request.Body | Select-Object * -ExcludeProperty TemplateId + } else { + $RoleMappings = $Request.Body.RoleMappings + } + Write-Information ($RoleMappings | ConvertTo-Json) + Add-CIPPGDAPRoleTemplate -TemplateId $RowKey -RoleMappings $RoleMappings + $Body = @{ + Results = "Added role mappings to template $RowKey" + } + } + 'Edit' { + $RowKey = $Request.Body.TemplateId + $Template = $Templates | Where-Object -Property RowKey -EQ $RowKey + if ($Template) { + $RoleMappings = $Request.Body.RoleMappings + Add-CIPPGDAPRoleTemplate -TemplateId $RowKey -RoleMappings $RoleMappings -Overwrite + $Body = @{ + Results = "Updated role mappings for template $RowKey" + } + } else { + $Body = @{ + Results = "Template $RowKey not found" + } + } + } + 'Delete' { + $RowKey = $Request.Body.TemplateId + $Template = $Templates | Where-Object -Property RowKey -EQ $RowKey + if ($Template) { + Remove-AzDataTableEntity -Force @Table -Entity $Template + $Body = @{ + Results = "Deleted template $RowKey" + } + } else { + $Body = @{ + Results = "Template $RowKey not found" + } + } + } + default { + $Results = foreach ($Template in $Templates) { + [PSCustomObject]@{ + TemplateId = $Template.RowKey + RoleMappings = @($Template.RoleMappings | ConvertFrom-Json) + } + } + $Body = @{ + Results = @($Results) + Metadata = @{ + Count = $Results.Count + } + } + } + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPAccessAssignments.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPAccessAssignments.ps1 new file mode 100644 index 000000000000..83fae86a70ea --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPAccessAssignments.ps1 @@ -0,0 +1,51 @@ +function Invoke-ListGDAPAccessAssignments { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $Id = $Request.Query.Id + $TenantFilter = $env:TenantID + + Write-Information "Getting access assignments for $Id" + + $AccessAssignments = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships/$Id/accessAssignments" -tenantid $TenantFilter + + # get groups asapp + $Groups = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/groups?`$top=999&`$select=id,displayName&`$filter=securityEnabled eq true" -tenantid $TenantFilter -asApp $true + + # Get all the access containers + $AccessContainers = $AccessAssignments.accessContainer.accessContainerId + + $ContainerMembers = foreach ($AccessContainer in $AccessContainers) { + @{ + 'id' = $AccessContainer + 'url' = "groups/$AccessContainer/members?`$select=id,displayName,userPrincipalName,isAssignableToRole&`$top=999" + 'method' = 'GET' + } + } + $Members = New-GraphBulkRequest -Requests $ContainerMembers -tenantid $TenantFilter -asApp $true -NoAuthCheck $true + + $Results = foreach ($AccessAssignment in $AccessAssignments) { + [PSCustomObject]@{ + 'id' = $AccessAssignment.id + 'status' = $AccessAssignment.status + 'createdDateTime' = $AccessAssignment.createdDateTime + 'modifiedDateTime' = $AccessAssignment.modifiedDateTime + 'roles' = $AccessAssignment.accessDetails.unifiedRoles + 'group' = $Groups | Where-Object id -EQ $AccessAssignment.accessContainer.accessContainerId + 'members' = ($Members | Where-Object id -EQ $AccessAssignment.accessContainer.accessContainerId).body.value + } + } + + $Body = @{ + Results = $Results + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 index 814cdf4ae693..9242f8da2588 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPInvite.ps1 @@ -22,13 +22,13 @@ Function Invoke-ListGDAPInvite { $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Query.RelationshipId)'" } else { $Invite = Get-CIPPAzDataTableEntity @Table | ForEach-Object { - $_.RoleMappings = try { $_.RoleMappings | ConvertFrom-Json } catch { $_.RoleMappings } + $_.RoleMappings = @(try { $_.RoleMappings | ConvertFrom-Json } catch { $_.RoleMappings }) $_ } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $Invite + Body = @($Invite) }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 index 66f0402b0171..a901e108b61b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 @@ -14,17 +14,24 @@ Function Invoke-AddStandardsTemplate { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $GUID = $Request.body.GUID ? $request.body.GUID : (New-Guid).GUID + #updatedBy = $request.headers.'x-ms-client-principal' + #updatedAt = (Get-Date).ToUniversalTime() + $request.body | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID -Force + $request.body | Add-Member -NotePropertyName 'createdAt' -NotePropertyValue ($Request.body.createdAt ? $Request.body.createdAt : (Get-Date).ToUniversalTime()) -Force + $Request.body | Add-Member -NotePropertyName 'updatedBy' -NotePropertyValue ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json).userDetails -Force + $Request.body | Add-Member -NotePropertyName 'updatedAt' -NotePropertyValue (Get-Date).ToUniversalTime() -Force $JSON = (ConvertTo-Json -Depth 100 -InputObject ($Request.body)) $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ JSON = "$JSON" RowKey = "$GUID" - PartitionKey = 'StandardsTemplate' + PartitionKey = 'StandardsTemplateV2' GUID = "$GUID" + } Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Created CA Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' - $body = [pscustomobject]@{'Results' = 'Successfully added template' } + $body = [pscustomobject]@{'Results' = 'Successfully added template'; id = $GUID } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardConvert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardConvert.ps1 new file mode 100644 index 000000000000..915ba2ef475b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecStandardConvert.ps1 @@ -0,0 +1,239 @@ +using namespace System.Net + +function Invoke-ExecStandardConvert { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Standards.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + function Convert-SingleStandardItem { + param( + [Parameter(Mandatory)] + $OldStd + ) + + $Actions = New-Object System.Collections.ArrayList + $RemediatePresent = ($OldStd.PSObject.Properties.Name -contains 'remediate') + $AlertPresent = ($OldStd.PSObject.Properties.Name -contains 'alert') + $ReportPresent = ($OldStd.PSObject.Properties.Name -contains 'report') + + $RemediateTrue = $RemediatePresent -and $OldStd.remediate -eq $true + $AlertTrue = $AlertPresent -and $OldStd.alert -eq $true + $ReportTrue = $ReportPresent -and $OldStd.report -eq $true + + if (-not ($RemediateTrue -or $AlertTrue -or $ReportTrue)) { + return $null + } + + if ($RemediateTrue) { + [void]$Actions.Add([pscustomobject]@{label = 'Remediate'; value = 'Remediate' }) + } + if ($AlertTrue) { + [void]$Actions.Add([pscustomobject]@{label = 'Alert'; value = 'warn' }) + } + if ($ReportTrue) { + [void]$Actions.Add([pscustomobject]@{label = 'Report'; value = 'Report' }) + } + + $propsToCopy = $OldStd | Select-Object * -ExcludeProperty alert, report, remediate + $Result = [ordered]@{} + if ($Actions.Count -gt 0) { + $ActionArray = $Actions | ForEach-Object { $_ } + $Result.action = @($ActionArray) + } + + foreach ($prop in $propsToCopy.PSObject.Properties) { + if ($prop.Name -ne 'PSObject') { + $Result.$($prop.Name) = $prop.Value + } + } + + return $Result + } + + function Convert-OldStandardToNewFormat { + param( + [Parameter(Mandatory = $true)] + $OldStandard, + [Parameter(Mandatory = $false)] + $AllTenantsExclusions = @() + ) + + $Tenant = $OldStandard.Tenant + if ($Tenant -eq 'AllTenants') { + $TenantFilter = @( + [pscustomobject]@{ + label = '*All Tenants (AllTenants)' + value = 'AllTenants' + addedFields = [pscustomobject]@{} + } + ) + if ($AllTenantsExclusions.Count -gt 0) { + $Excluded = $AllTenantsExclusions | ForEach-Object { + [pscustomobject]@{ + label = "$_ ($_)" + value = $_ + addedFields = [pscustomobject]@{} + } + } + } else { + $Excluded = $null + } + } else { + $TenantFilter = @( + [pscustomobject]@{ + label = "$Tenant ($Tenant)" + value = $Tenant + addedFields = [pscustomobject]@{} + } + ) + $Excluded = $null + } + + $NewStandards = [ordered]@{} + + foreach ($StdKey in $OldStandard.Standards.PSObject.Properties.Name) { + if ($StdKey -in ('tenant', 'OverrideAllTenants', 'v2', 'v2.1')) { + continue + } + + $OldStd = $OldStandard.Standards.$StdKey + $NewStdKey = if ($StdKey -eq 'ConditionalAccess') { + Write-Host 'Converting ConditionalAccess to ConditionalAccessTemplate' + 'ConditionalAccessTemplate' + } else { $StdKey } + $IsArrayStandard = ($NewStdKey -eq 'IntuneTemplate' -or $NewStdKey -eq 'ConditionalAccessTemplate') + $ConvertedObj = Convert-SingleStandardItem $OldStd + if ($ConvertedObj -eq $null) { + continue + } + + if ($IsArrayStandard) { + $FinalArray = New-Object System.Collections.ArrayList + $TemplateList = $ConvertedObj.TemplateList + $ConvertedObj.PSObject.Properties.Remove('TemplateList') + + if ($TemplateList -and $TemplateList.Count -gt 0) { + foreach ($TItem in $TemplateList) { + $NewItem = [ordered]@{} + if ($ConvertedObj.action) { + $NewItem.action = $ConvertedObj.action + } + foreach ($prop in $ConvertedObj.PSObject.Properties.Name) { + if ($prop -ne 'action') { + $NewItem.$prop = $ConvertedObj.$prop + } + } + $NewItem.TemplateList = $TItem + [void]$FinalArray.Add($NewItem) + } + } + + if ($FinalArray.Count -gt 0) { + $ArrayItems = $FinalArray | ForEach-Object { $_ } + $NewStandards.$NewStdKey = $ArrayItems + } + } else { + $Action = $ConvertedObj.action + if ($Action) { + $ConvertedObj.PSObject.Properties.Remove('action') + } + $Wrap = [ordered]@{} + if ($Action) { + $Wrap.action = $Action + } + $Wrap.standards = [ordered]@{} + $Wrap.standards.$NewStdKey = $ConvertedObj + $NewStandards.$NewStdKey = $Wrap + } + + } + + $NewTemplate = [pscustomobject]@{ + tenantFilter = $TenantFilter + templateName = "Converted Legacy Template for $Tenant" + standards = $NewStandards + runManually = $true + } + + if ($Tenant -eq 'AllTenants' -and $Excluded) { + $ExcludedArr = $Excluded | ForEach-Object { $_ } + $NewTemplate | Add-Member -NotePropertyName 'excludedTenants' -NotePropertyValue @($ExcludedArr) -Force + } + + return $NewTemplate + } + + $Table = Get-CippTable -tablename 'standards' + $Filter = "PartitionKey eq 'standards'" + $OldStandards = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json + + $AllTenantsStd = $OldStandards | Where-Object { $_.Tenant -eq 'AllTenants' } + $HasAllTenants = $AllTenantsStd -ne $null + + $AllTenantsExclusions = New-Object System.Collections.ArrayList + $StandardsToConvert = New-Object System.Collections.ArrayList + + foreach ($OldStd in $OldStandards) { + $Tenant = $OldStd.Tenant + $StdNames = $OldStd.Standards.PSObject.Properties.Name | Where-Object { $_ -notin ('tenant', 'OverrideAllTenants', 'v2', 'v2.1') } + $HasOverride = ($OldStd.Standards.PSObject.Properties.Name -contains 'OverrideAllTenants') + + if ($Tenant -ne 'AllTenants') { + if ($HasOverride -and $StdNames.Count -eq 0) { + [void]$AllTenantsExclusions.Add($Tenant) + continue + } + + if ($HasOverride -and $StdNames.Count -gt 0 -and $HasAllTenants) { + [void]$AllTenantsExclusions.Add($Tenant) + } + } + + [void]$StandardsToConvert.Add($OldStd) + } + + foreach ($OldStd in $StandardsToConvert) { + $Converted = Convert-OldStandardToNewFormat $OldStd ($AllTenantsExclusions) + $GUID = [guid]::NewGuid() + $Converted | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID -Force + $Converted | Add-Member -NotePropertyName 'createdAt' -NotePropertyValue ((Get-Date).ToUniversalTime()) -Force + $Converted | Add-Member -NotePropertyName 'updatedBy' -NotePropertyValue 'System' -Force + $Converted | Add-Member -NotePropertyName 'updatedAt' -NotePropertyValue (Get-Date).ToUniversalTime() -Force + $JSON = ConvertTo-Json -Depth 100 -InputObject $Converted -Compress + + $Table = Get-CippTable -tablename 'templates' + $Table.Force = $true + if ($Converted.standards) { + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = "$JSON" + RowKey = "$GUID" + PartitionKey = 'StandardsTemplateV2' + GUID = "$GUID" + } + } + } + + #delete the old standards + if ($StandardsToConvert.Count -gt 0) { + $StandardsToConvert | ForEach-Object { + $Table = Get-CippTable -tablename 'standards' + $OldStdsTableItems = Get-CIPPAzDataTableEntity @Table -Filter $Filter + try { + Remove-AzDataTableEntity @Table -Entity $OldStdsTableItems -Force + } catch { + #donothing + } + } + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = 'Successfully converted legacy standards to new format' + }) +} 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 7a400591b6f0..74c88643ce89 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 @@ -12,19 +12,29 @@ Function Invoke-ExecStandardsRun { $APIName = $TriggerMetadata.FunctionName 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' } + $TemplateId = if ($Request.Query.TemplateId) { $Request.Query.TemplateId } else { '*' } + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'StandardsTemplateV2'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | ConvertFrom-Json | Where-Object { + $_.guid -like $TemplateId + } + + $ConfigTable = Get-CIPPTable -tablename Config $Config = Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'OffloadFunctions' and RowKey eq 'OffloadFunctions'" if ($Config -and $Config.state -eq $true) { if ($env:CIPP_PROCESSOR -ne 'true') { - + $ProcessorFunction = [PSCustomObject]@{ PartitionKey = 'Function' RowKey = "Invoke-CIPPStandardsRun-$tenantfilter" FunctionName = 'Invoke-CIPPStandardsRun' Parameters = [string](ConvertTo-Json -Compress -InputObject @{ TenantFilter = $tenantfilter + TemplateId = $TemplateId + runManually = [bool]$Templates.runManually Force = $true }) } @@ -34,10 +44,12 @@ Function Invoke-ExecStandardsRun { } } else { try { - $null = Invoke-CIPPStandardsRun -Tenantfilter $tenantfilter -Force + $null = Invoke-CIPPStandardsRun -Tenantfilter $tenantfilter -TemplateID $TemplateId -runManually ([bool]$Templates.runManually) -Force $Results = "Successfully Started Standards Run for Tenant $tenantfilter" + Write-LogMessage -tenant $tenantfilter -API $APINAME -message $Results -Sev 'Info' } catch { $Results = "Failed to start standards run for $tenantfilter. Error: $($_.Exception.Message)" + Write-LogMessage -tenant $tenantfilter -API $APINAME -message $Results -Sev 'Error' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 index ca8b373bcadc..0df80f7d9f7a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListBPA.ps1 @@ -34,9 +34,9 @@ Function Invoke-ListBPA { if ($Request.query.tenantFilter -ne 'AllTenants' -and $Style -eq 'Tenant') { + $CustomerId = (Get-Tenants -TenantFilter $Request.query.tenantFilter).customerId $mergedObject = New-Object pscustomobject - - $Data = (Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Request.query.tenantFilter)'") | ForEach-Object { + $Data = (Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$CustomerId'") | ForEach-Object { $row = $_ $JSONFields | ForEach-Object { $jsonContent = $row.$_ @@ -48,6 +48,7 @@ Function Invoke-ListBPA { } } $row.PSObject.Properties | ForEach-Object { + Write-Host "Adding $($_.Name) to mergedObject" $mergedObject | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 index b866f1f814a0..ebf7a663e342 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 @@ -10,13 +10,19 @@ Function Invoke-listStandardTemplates { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'StandardsTemplate'" + $Filter = "PartitionKey eq 'StandardsTemplateV2'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) | ForEach-Object { - $data = $_.JSON | ConvertFrom-Json -Depth 100 + $JSON = $_.JSON + try { + $RowKey = $_.RowKey + $data = $_.JSON | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue + } catch { + Write-Host "$($RowKey)" + return + } $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force + if ($data.excludedTenants) { $data.excludedTenants = @($data.excludedTenants) } $data } | Sort-Object -Property templateName diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 index befe1b339f21..5019a66c9725 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Tools/Invoke-ExecGraphExplorerPreset.ps1 @@ -20,13 +20,13 @@ Function Invoke-ExecGraphExplorerPreset { switch ($Action) { 'Copy' { - $Id = (New-Guid).Guid + $Id = $Request.Body.preset.id ? $Request.Body.preset.id: (New-Guid).Guid } 'Save' { - $Id = $Request.Body.preset.reportTemplate.value + $Id = $Request.Body.preset.id } 'Delete' { - $Id = $Request.Body.preset.reportTemplate.value + $Id = $Request.Body.preset.id } default { $Action = 'Copy' @@ -55,7 +55,7 @@ Function Invoke-ExecGraphExplorerPreset { $Table = Get-CIPPTable -TableName 'GraphPresets' $Message = '{0} preset succeeded' -f $Action if ($Action -eq 'Copy') { - Add-CIPPAzDataTableEntity @Table -Entity $Preset + Add-CIPPAzDataTableEntity @Table -Entity $Preset -Force $Success = $true } else { $Entity = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$Id'" @@ -67,6 +67,7 @@ Function Invoke-ExecGraphExplorerPreset { } $Success = $true } else { + Write-Host "username in table: $($Entity.Owner). Username in request: $Username" $Message = 'Error: You can only modify your own presets.' $Success = $false } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBreachSearch.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBreachSearch.ps1 new file mode 100644 index 000000000000..5babb8345a72 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecBreachSearch.ps1 @@ -0,0 +1,23 @@ +using namespace System.Net + +Function Invoke-ExecBreachSearch { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Core.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 + #Move to background job + New-BreachTenantSearch -TenantFilter $TenantFilter + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = "Executing Search for $TenantFilter" } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 new file mode 100644 index 000000000000..3b2a14e1e100 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 @@ -0,0 +1,48 @@ +using namespace System.Net + +Function Invoke-ExecCSPLicense { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Directory.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + + # Write to the Azure Functions log stream. + Write-Host 'PowerShell HTTP trigger function processed a request.' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.body.TenantFilter + $Action = $Request.body.Action + try { + if ($Action -eq 'Add') { + $GraphRequest = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $Request.body.sku -add $Request.body.Add + } + + if ($Action -eq 'Remove') { + $GraphRequest = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $Request.body.sku -remove $Request.body.Remove + } + + if ($Action -eq 'NewSub') { + $GraphRequest = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $Request.body.sku.value -Quantity $Request.body.Quantity + } + if ($Action -eq 'Cancel') { + $GraphRequest = Remove-SherwebSubscription -tenantFilter $TenantFilter -SubscriptionIds $Request.body.SubscriptionIds + } + $Message = 'License change executed successfully.' + } catch { + $Message = "Failed to execute license change. Error: $_" + } + #If #GraphRequest is a GUID, the subscription was edited succesfully, and return that its done. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Message + }) -Clobber + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 index f16a350fc2c6..e5d18b453a87 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUniversalSearch.ps1 @@ -38,11 +38,11 @@ Function Invoke-ExecUniversalSearch { ) } } | ConvertTo-Json -Depth 10 - $GraphRequest = (New-GraphPOSTRequest -noauthcheck $true -type 'POST' -uri 'https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedTenantOperations' -tenantid $env:TenantID -body $payload -IgnoreErrors $true) + $GraphRequest = New-GraphPOSTRequest -noauthcheck $true -type 'POST' -uri 'https://graph.microsoft.com/beta/tenantRelationships/managedTenants/managedTenantOperations' -tenantid $env:TenantID -body $payload -IgnoreErrors $true if (!$GraphRequest.result.results) { $GraphRequest = ($GraphRequest.error.message | ConvertFrom-Json).result.results | ConvertFrom-Json | Where-Object { $_.'_TenantId' -in $tenantfilter.customerId } } else { - $GraphRequest.result.Results | ConvertFrom-Json -ErrorAction SilentlyContinue | Where-Object { $_.'_TenantId' -in $tenantfilter.customerId } + $GraphRequest = $GraphRequest.result.Results | ConvertFrom-Json -ErrorAction SilentlyContinue | Where-Object { $_.'_TenantId' -in $tenantfilter.customerId } } $StatusCode = [HttpStatusCode]::OK } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesAccount.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesAccount.ps1 new file mode 100644 index 000000000000..827a151ded72 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesAccount.ps1 @@ -0,0 +1,28 @@ +using namespace System.Net + +Function Invoke-ListBreachesAccount { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Core.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' + + if ($request.query.account -like '*@*') { + $Results = Get-HIBPRequest "breachedaccount/$($Request.query.account)?truncateResponse=false" + } else { + $Results = Get-BreachInfo -Domain $Request.query.account + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($results) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 new file mode 100644 index 000000000000..812a8c46b272 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 @@ -0,0 +1,34 @@ +using namespace System.Net + +Function Invoke-ListBreachesTenant { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Core.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $TenantFilter = $Request.query.TenantFilter + $Table = Get-CIPPTable -TableName UserBreaches + if ($TenantFilter -ne 'AllTenants') { + $filter = "PartitionKey eq '$TenantFilter'" + } else { + $filter = $null + } + try { + $usersResults = (Get-CIPPAzDataTableEntity @Table -Filter $filter).breaches | ConvertFrom-Json -ErrorAction SilentlyContinue + } catch { + $usersResults = $null + } + if ($usersResults -eq $null) { + $usersResults = @() + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($usersResults) + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPLicenses.ps1 new file mode 100644 index 000000000000..4a6959e2b5fc --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPLicenses.ps1 @@ -0,0 +1,23 @@ +using namespace System.Net + +Function Invoke-ListCSPLicenses { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Directory.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' + + $GraphRequest = Get-SherwebCurrentSubscription -TenantFilter $Request.Query.TenantFilter + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) -Clobber + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 new file mode 100644 index 000000000000..07f4ca8897eb --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 @@ -0,0 +1,28 @@ +using namespace System.Net + +Function Invoke-ListCSPsku { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Directory.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' + + if ($Request.Query.currentSkuOnly) { + $GraphRequest = Get-SherwebCurrentSubscription -TenantFilter $Request.Query.TenantFilter + } else { + $GraphRequest = Get-SherwebCatalog -TenantFilter $Request.Query.TenantFilter + } + + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @($GraphRequest) + }) -Clobber + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 index 78a4f1bcbbf0..fdd9388d3d79 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 @@ -20,15 +20,12 @@ Function Invoke-ListDefenderState { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/windowsProtectionStates?`$top=999&`$filter=tenantId eq '$TenantFilter'" - if ($GraphRequest.tenantDisplayName.length -lt 1) { - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = 'No data found - This client might not be onboarded in Lighthouse' - } + $GraphRequest = New-GraphGetRequest -tenantid $TenantFilter -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$expand=windowsProtectionState&`$select=id,deviceName,deviceType,operatingSystem,windowsProtectionState" + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = "Could not connect to Azure Lighthouse API: $($ErrorMessage)" + $GraphRequest = "$($ErrorMessage)" } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 index 01e7cacb254f..e61191283062 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 @@ -11,14 +11,12 @@ Function Invoke-ListDefenderTVM { 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 + $ExecutingUser = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter try { $GraphRequest = New-GraphgetRequest -tenantid $TenantFilter -uri "https://api.securitycenter.microsoft.com/api/machines/SoftwareVulnerabilitiesByMachine?`$top=999" -scope 'https://api.securitycenter.microsoft.com/.default' | Group-Object cveid $GroupObj = foreach ($cve in $GraphRequest) { @@ -42,6 +40,7 @@ Function Invoke-ListDefenderTVM { $StatusCode = [HttpStatusCode]::Forbidden $GroupObj = $ErrorMessage } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 index 26d68ac580b7..cb763699e04c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 @@ -11,22 +11,21 @@ Function Invoke-ListDeletedItems { 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 + $ExecutingUser = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $selectlist = 'id', 'accountEnabled', 'businessPhones', 'city', 'createdDateTime', 'companyName', 'country', 'department', 'displayName', 'faxNumber', 'givenName', 'isResourceAccount', 'jobTitle', 'mail', 'mailNickname', 'mobilePhone', 'onPremisesDistinguishedName', 'officeLocation', 'onPremisesLastSyncDateTime', 'otherMails', 'postalCode', 'preferredDataLocation', 'preferredLanguage', 'proxyAddresses', 'showInAddressList', 'state', 'streetAddress', 'surname', 'usageLocation', 'userPrincipalName', 'userType', 'assignedLicenses', 'onPremisesSyncEnabled', 'LicJoined', 'Aliases', 'primDomain' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter $Types = 'Application', 'User', 'Device', 'Group' $GraphRequest = foreach ($Type in $Types) { - (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | Where-Object -Property '@odata.context' -NotLike '*graph.microsoft.com*' | Select-Object *, @{ Name = 'TargetType'; Expression = { $Type } } + (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/directory/deletedItems/microsoft.graph.$($Type)" -tenantid $TenantFilter) | + Where-Object -Property '@odata.context' -NotLike '*graph.microsoft.com*' | + Select-Object *, @{ Name = 'TargetType'; Expression = { $Type } } } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = @($GraphRequest) }) - } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 index 8c96c119f2f0..7fbe2e3ab83c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 @@ -21,8 +21,8 @@ Function Invoke-ListExConnectorTemplates { $GUID = $_.RowKey $Direction = $_.direction $data = $_.JSON | ConvertFrom-Json - $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID - $data | Add-Member -NotePropertyName 'cippconnectortype' -NotePropertyValue $Direction + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $GUID -Force + $data | Add-Member -NotePropertyName 'cippconnectortype' -NotePropertyValue $Direction -Force $data } | Sort-Object -Property displayName diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 index dcb21450d67d..4f70f3c53929 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionParameters.ps1 @@ -63,6 +63,7 @@ function Invoke-ListFunctionParameters { Name = $Key Type = $Param.ParameterType.FullName Description = $ParamHelp.description + Required = $Param.Attributes.Mandatory } } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 index 1212c03efee0..e023ee91f0be 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphExplorerPresets.ps1 @@ -12,13 +12,11 @@ Function Invoke-ListGraphExplorerPresets { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Username = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($request.headers.'x-ms-client-principal')) | ConvertFrom-Json).userDetails - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + try { $Table = Get-CIPPTable -TableName 'GraphPresets' - $Presets = Get-CIPPAzDataTableEntity @Table -Filter "Owner eq '$Username' or IsShared eq true" + $Presets = Get-CIPPAzDataTableEntity @Table -Filter "Owner eq '$Username' or IsShared eq true" | Sort-Object -Property name $Results = foreach ($Preset in $Presets) { [PSCustomObject]@{ id = $Preset.Id @@ -28,8 +26,13 @@ Function Invoke-ListGraphExplorerPresets { params = ConvertFrom-Json -InputObject $Preset.Params } } + + if ($Request.Query.Endpoint) { + $Endpoint = $Request.Query.Endpoint -replace '^/', '' + $Results = $Results | Where-Object { ($_.params.endpoint -replace '^/', '') -eq $Endpoint } + } } catch { - $Presets = @() + $Results = @() } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ @@ -37,7 +40,7 @@ Function Invoke-ListGraphExplorerPresets { Body = @{ Results = @($Results) Metadata = @{ - Count = ($Presets | Measure-Object).Count + Count = ($Results | Measure-Object).Count } } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 index b59ceae2fd06..00d3d8eb9606 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 @@ -13,55 +13,74 @@ Function Invoke-ListGroups { $APIName = $TriggerMetadata.FunctionName Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter $selectstring = "id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,grouptypes,onPremisesSyncEnabled,resourceProvisioningOptions,userPrincipalName&`$expand=members(`$select=userPrincipalName)" + $BulkRequestArrayList = [System.Collections.ArrayList]@() + if ($Request.Query.GroupID) { - $groupid = $Request.query.groupid $selectstring = 'id,createdDateTime,displayName,description,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule,groupTypes,userPrincipalName' + $BulkRequestArrayList.add(@{ + id = 1 + method = 'GET' + url = "groups/$($Request.Query.GroupID)?`$select=$selectstring" + }) } if ($Request.Query.members) { - $members = 'members' $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' + $BulkRequestArrayList.add(@{ + id = 2 + method = 'GET' + url = "groups/$($Request.Query.GroupID)/members?`$top=999&select=$selectstring" + }) } if ($Request.Query.owners) { - $members = 'owners' $selectstring = 'id,userPrincipalName,displayName,hideFromOutlookClients,hideFromAddressLists,mail,mailEnabled,mailNickname,resourceProvisioningOptions,securityEnabled,visibility,organizationId,onPremisesSamAccountName,membershipRule' + $BulkRequestArrayList.add(@{ + id = 3 + method = 'GET' + url = "groups/$($Request.Query.GroupID)/owners?`$top=999&select=$selectstring" + }) } + try { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$selectstring" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, - @{Name = 'membersCsv'; Expression = { $_.members.userPrincipalName -join ',' } }, - @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true }else { $false } } }, - @{Name = 'calculatedGroupType'; Expression = { + if ($BulkRequestArrayList.Count -gt 0) { + $RawGraphRequest = New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($BulkRequestArrayList) -asapp $true + $GraphRequest = [PSCustomObject]@{ + groupInfo = ($RawGraphRequest | Where-Object { $_.id -eq 1 }).body + members = ($RawGraphRequest | Where-Object { $_.id -eq 2 }).body.value + owners = ($RawGraphRequest | Where-Object { $_.id -eq 3 }).body.value + } + } else { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupID)/$($members)?`$top=999&select=$selectstring" -tenantid $TenantFilter | Select-Object *, @{ Name = 'primDomain'; Expression = { $_.mail -split '@' | Select-Object -Last 1 } }, + @{Name = 'membersCsv'; Expression = { $_.members.userPrincipalName -join ',' } }, + @{Name = 'teamsEnabled'; Expression = { if ($_.resourceProvisioningOptions -Like '*Team*') { $true }else { $false } } }, + @{Name = 'calculatedGroupType'; Expression = { - if ($_.mailEnabled -and $_.securityEnabled) { - 'Mail-Enabled Security' - } - if (!$_.mailEnabled -and $_.securityEnabled) { - 'Security' - } - if ($_.groupTypes -contains 'Unified') { - 'Microsoft 365' + if ($_.mailEnabled -and $_.securityEnabled) { + 'Mail-Enabled Security' + } + if (!$_.mailEnabled -and $_.securityEnabled) { + 'Security' + } + if ($_.groupTypes -contains 'Unified') { + 'Microsoft 365' + } + if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { + 'Distribution List' + } } - if (([string]::isNullOrEmpty($_.groupTypes)) -and ($_.mailEnabled) -and (!$_.securityEnabled)) { - 'Distribution List' - } - } - }, - @{Name = 'dynamicGroupBool'; Expression = { - if ($_.groupTypes -contains 'DynamicMembership') { - $true - } else { - $false + }, + @{Name = 'dynamicGroupBool'; Expression = { + if ($_.groupTypes -contains 'DynamicMembership') { + $true + } else { + $false + } } } + $GraphRequest = @($GraphRequest | Sort-Object displayName) } $StatusCode = [HttpStatusCode]::OK @@ -73,7 +92,7 @@ Function Invoke-ListGroups { # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @($GraphRequest | Sort-Object displayName) + Body = $GraphRequest }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 index 2ad45b5488bb..5a36bb089ff0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 @@ -11,15 +11,21 @@ Function Invoke-ListInactiveAccounts { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $User = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. + # Convert the TenantFilter parameter to a list of tenant IDs for AllTenants or a single tenant ID $TenantFilter = $Request.Query.TenantFilter - if ($TenantFilter -eq 'AllTenants') { $TenantFilter = (get-tenants).customerId } + if ($TenantFilter -eq 'AllTenants') { + $TenantFilter = (Get-Tenants).customerId + } else { + $TenantFilter = (Get-Tenants -TenantFilter $TenantFilter).customerId + } + try { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/managedTenants/inactiveUsers?`$count=true" -tenantid $env:TenantID | Where-Object { $_.tenantId -in $TenantFilter } $StatusCode = [HttpStatusCode]::OK @@ -34,5 +40,4 @@ Function Invoke-ListInactiveAccounts { StatusCode = $StatusCode Body = @($GraphRequest) }) - } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 index 8e65b6f27001..c2ad60650959 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 @@ -57,47 +57,48 @@ Function Invoke-ListIntunePolicy { $BulkResults = New-GraphBulkRequest -Requests $BulkRequests -tenantid $TenantFilter $GraphRequest = $BulkResults | ForEach-Object { - $URLName = $_.Id - $_.body.Value | ForEach-Object { - $policyTypeName = switch -Wildcard ($_.'assignments@odata.context') { - '*microsoft.graph.windowsIdentityProtectionConfiguration*' { 'Identity Protection' } - '*microsoft.graph.windows10EndpointProtectionConfiguration*' { 'Endpoint Protection' } - '*microsoft.graph.windows10CustomConfiguration*' { 'Custom' } - '*microsoft.graph.windows10DeviceFirmwareConfigurationInterface*' { 'Firmware Configuration' } - '*groupPolicyConfigurations*' { 'Administrative Templates' } - '*windowsDomainJoinConfiguration*' { 'Domain Join configuration' } - '*windowsUpdateForBusinessConfiguration*' { 'Update Configuration' } - '*windowsHealthMonitoringConfiguration*' { 'Health Monitoring' } - '*microsoft.graph.macOSGeneralDeviceConfiguration*' { 'MacOS Configuration' } - '*microsoft.graph.macOSEndpointProtectionConfiguration*' { 'MacOS Endpoint Protection' } - '*microsoft.graph.androidWorkProfileGeneralDeviceConfiguration*' { 'Android Configuration' } - default { $_.'assignments@odata.context' } - } - $Assignments = $_.assignments.target | Select-Object -Property '@odata.type', groupId - $PolicyAssignment = [System.Collections.Generic.List[string]]::new() - $PolicyExclude = [System.Collections.Generic.List[string]]::new() - ForEach ($target in $Assignments) { - switch ($target.'@odata.type') { - '#microsoft.graph.allDevicesAssignmentTarget' { $PolicyAssignment.Add('All Devices') } - '#microsoft.graph.exclusionallDevicesAssignmentTarget' { $PolicyExclude.Add('All Devices') } - '#microsoft.graph.allUsersAssignmentTarget' { $PolicyAssignment.Add('All Users') } - '#microsoft.graph.exclusionallUsersAssignmentTarget' { $PolicyExclude.Add('All Users') } - '#microsoft.graph.groupAssignmentTarget' { $PolicyAssignment.Add($Groups.Where({ $_.id -eq $target.groupId }).displayName) } - '#microsoft.graph.exclusionGroupAssignmentTarget' { $PolicyExclude.Add($Groups.Where({ $_.id -eq $target.groupId }).displayName) } - default { - $PolicyAssignment.Add($null) - $PolicyExclude.Add($null) + $URLName = $_.Id + $_.body.Value | ForEach-Object { + $policyTypeName = switch -Wildcard ($_.'assignments@odata.context') { + '*microsoft.graph.windowsIdentityProtectionConfiguration*' { 'Identity Protection' } + '*microsoft.graph.windows10EndpointProtectionConfiguration*' { 'Endpoint Protection' } + '*microsoft.graph.windows10CustomConfiguration*' { 'Custom' } + '*microsoft.graph.windows10DeviceFirmwareConfigurationInterface*' { 'Firmware Configuration' } + '*groupPolicyConfigurations*' { 'Administrative Templates' } + '*windowsDomainJoinConfiguration*' { 'Domain Join configuration' } + '*windowsUpdateForBusinessConfiguration*' { 'Update Configuration' } + '*windowsHealthMonitoringConfiguration*' { 'Health Monitoring' } + '*microsoft.graph.macOSGeneralDeviceConfiguration*' { 'MacOS Configuration' } + '*microsoft.graph.macOSEndpointProtectionConfiguration*' { 'MacOS Endpoint Protection' } + '*microsoft.graph.androidWorkProfileGeneralDeviceConfiguration*' { 'Android Configuration' } + default { $_.'assignments@odata.context' } + } + $Assignments = $_.assignments.target | Select-Object -Property '@odata.type', groupId + $PolicyAssignment = [System.Collections.Generic.List[string]]::new() + $PolicyExclude = [System.Collections.Generic.List[string]]::new() + ForEach ($target in $Assignments) { + switch ($target.'@odata.type') { + '#microsoft.graph.allDevicesAssignmentTarget' { $PolicyAssignment.Add('All Devices') } + '#microsoft.graph.exclusionallDevicesAssignmentTarget' { $PolicyExclude.Add('All Devices') } + '#microsoft.graph.allUsersAssignmentTarget' { $PolicyAssignment.Add('All Users') } + '#microsoft.graph.allLicensedUsersAssignmentTarget' { $PolicyAssignment.Add('All Licenced Users') } + '#microsoft.graph.exclusionallUsersAssignmentTarget' { $PolicyExclude.Add('All Users') } + '#microsoft.graph.groupAssignmentTarget' { $PolicyAssignment.Add($Groups.Where({ $_.id -eq $target.groupId }).displayName) } + '#microsoft.graph.exclusionGroupAssignmentTarget' { $PolicyExclude.Add($Groups.Where({ $_.id -eq $target.groupId }).displayName) } + default { + $PolicyAssignment.Add($null) + $PolicyExclude.Add($null) + } } } - } - if ($_.displayname -eq $null) { $_ | Add-Member -NotePropertyName displayName -NotePropertyValue $_.name } - $_ | Add-Member -NotePropertyName PolicyTypeName -NotePropertyValue $policyTypeName - $_ | Add-Member -NotePropertyName URLName -NotePropertyValue $URLName - $_ | Add-Member -NotePropertyName PolicyAssignment -NotePropertyValue ($PolicyAssignment -join ', ') - $_ | Add-Member -NotePropertyName PolicyExclude -NotePropertyValue ($PolicyExclude -join ', ') - $_ - } | Where-Object { $_.DisplayName -ne $null } - } + if ($_.displayname -eq $null) { $_ | Add-Member -NotePropertyName displayName -NotePropertyValue $_.name } + $_ | Add-Member -NotePropertyName PolicyTypeName -NotePropertyValue $policyTypeName + $_ | Add-Member -NotePropertyName URLName -NotePropertyValue $URLName + $_ | Add-Member -NotePropertyName PolicyAssignment -NotePropertyValue ($PolicyAssignment -join ', ') + $_ | Add-Member -NotePropertyName PolicyExclude -NotePropertyValue ($PolicyExclude -join ', ') + $_ + } | Where-Object { $_.DisplayName -ne $null } + } } $StatusCode = [HttpStatusCode]::OK } catch { diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 index a11384cf8e85..240d12d26d98 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 @@ -14,34 +14,45 @@ Function Invoke-ListIntuneTemplates { Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Table = Get-CippTable -tablename 'templates' - - $Templates = Get-ChildItem 'Config\*.IntuneTemplate.json' | ForEach-Object { - $Entity = @{ - JSON = "$(Get-Content $_)" - RowKey = "$($_.name)" - PartitionKey = 'IntuneTemplate' - GUID = "$($_.name)" + $Imported = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'settings'" + if ($Imported.IntuneTemplate -ne $true) { + $Templates = Get-ChildItem 'Config\*.IntuneTemplate.json' | ForEach-Object { + $Entity = @{ + JSON = "$(Get-Content $_)" + RowKey = "$($_.name)" + PartitionKey = 'IntuneTemplate' + GUID = "$($_.name)" + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force } - Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + Add-CIPPAzDataTableEntity @Table -Entity @{ + IntuneTemplate = $true + RowKey = 'IntuneTemplate' + PartitionKey = 'settings' + } -Force } - #List new policies $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'IntuneTemplate'" - $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json + $RawTemplates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter) if ($Request.query.View) { - $Templates = $Templates | ForEach-Object { - $data = $_.RAWJson | ConvertFrom-Json -Depth 100 - $data | Add-Member -NotePropertyName 'displayName' -NotePropertyValue $_.Displayname -Force - $data | Add-Member -NotePropertyName 'description' -NotePropertyValue $_.Description -Force - $data | Add-Member -NotePropertyName 'Type' -NotePropertyValue $_.Type -Force - $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force + $Templates = $RawTemplates | ForEach-Object { + $JSONData = $_.JSON | ConvertFrom-Json + $data = $JSONData.RAWJson | ConvertFrom-Json -Depth 100 + $data | Add-Member -NotePropertyName 'displayName' -NotePropertyValue $JSONData.Displayname -Force + $data | Add-Member -NotePropertyName 'description' -NotePropertyValue $JSONData.Description -Force + $data | Add-Member -NotePropertyName 'Type' -NotePropertyValue $JSONData.Type -Force + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.RowKey -Force $data } | Sort-Object -Property displayName + } else { + $Templates = $RawTemplates.JSON | ConvertFrom-Json } if ($Request.query.ID) { $Templates = $Templates | Where-Object -Property guid -EQ $Request.query.id } + # Sort all output regardless of view condition + $Templates = $Templates | Sort-Object -Property displayName # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 index e5bd0a1530c9..570702815e40 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 @@ -10,13 +10,6 @@ Function Invoke-ListMailboxRules { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter @@ -26,11 +19,12 @@ Function Invoke-ListMailboxRules { } $Rows = Get-CIPPAzDataTableEntity @Table | Where-Object -Property Timestamp -GT (Get-Date).Addhours(-1) + $Metadata = @{} if (!$Rows -or ($TenantFilter -eq 'AllTenants' -and ($Rows | Measure-Object).Count -eq 1)) { - $GraphRequest = [PSCustomObject]@{ - Tenant = 'Loading data. Please check back in 1 minute' - Licenses = 'Loading data. Please check back in 1 minute' + $Metadata = [PSCustomObject]@{ + QueueMessage = 'Loading data. Please check back in 1 minute' } + $GraphRequest = @() if ($TenantFilter -eq 'AllTenants') { $Tenants = Get-Tenants -IncludeErrors | Select-Object defaultDomainName @@ -40,8 +34,7 @@ Function Invoke-ListMailboxRules { $Type = $TenantFilter } $Queue = New-CippQueueEntry -Name "Mailbox Rules ($Type)" -TotalTasks ($Tenants | Measure-Object).Count - $Batch = $Tenants | Select-Object defaultDomainName, @{Name = 'FunctionName'; Expression = { 'ListMailboxRulesQueue' } }, @{Name = 'QueueName'; Expression = { $_.defaultDomainName } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'QueueName'; Expression = { $_.defaultDomainName } } - + $Batch = $Tenants | Select-Object defaultDomainName, @{Name = 'FunctionName'; Expression = { 'ListMailboxRulesQueue' } }, @{Name = 'QueueName'; Expression = { $_.defaultDomainName } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } } if (($Batch | Measure-Object).Count -gt 0) { $InputObject = [PSCustomObject]@{ OrchestratorName = 'ListMailboxRulesOrchestrator' @@ -58,15 +51,20 @@ Function Invoke-ListMailboxRules { $Rows = $Rows | Where-Object -Property Tenant -EQ $TenantFilter } $GraphRequest = $Rows | ForEach-Object { - $NewObj = $_.Rules | ConvertFrom-Json - $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $_.Tenant + $NewObj = $_.Rules | ConvertFrom-Json -ErrorAction SilentlyContinue + $NewObj | Add-Member -NotePropertyName 'Tenant' -NotePropertyValue $_.Tenant -Force $NewObj } } + $Body = @{ + Results = @($GraphRequest) + Metadata = $Metadata + } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = @($GraphRequest) + Body = $Body }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 index 3da81ef8f734..0be3e36c27e5 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 @@ -20,7 +20,7 @@ Function Invoke-ListMailboxes { # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter try { - $Select = 'id,ExchangeGuid,ExternalDirectoryObjectId,ArchiveGuid,UserPrincipalName,DisplayName,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses,WhenSoftDeleted,IsInactiveMailbox,ForwardingSmtpAddress,DeliverToMailboxAndForward,ForwardingAddress' + $Select = 'id,ExchangeGuid,ArchiveGuid,UserPrincipalName,DisplayName,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses,WhenSoftDeleted,IsInactiveMailbox,ForwardingSmtpAddress,DeliverToMailboxAndForward,ForwardingAddress,HiddenFromAddressListsEnabled,ExternalDirectoryObjectId' $ExoRequest = @{ tenantid = $TenantFilter cmdlet = 'Get-Mailbox' @@ -58,8 +58,7 @@ Function Invoke-ListMailboxes { } } - Write-Host ($ExoRequest | ConvertTo-Json) - $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ExternalDirectoryObjectId, ArchiveGuid, WhenSoftDeleted, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, + $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ArchiveGuid, WhenSoftDeleted, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, @{ Name = 'primarySmtpAddress'; Expression = { $_.'PrimarySMTPAddress' } }, @@ -68,7 +67,9 @@ Function Invoke-ListMailboxes { @{ Name = 'AdditionalEmailAddresses'; Expression = { ($_.'EmailAddresses' | Where-Object { $_ -clike 'smtp:*' }).Replace('smtp:', '') -join ', ' } }, @{Name = 'ForwardingSmtpAddress'; Expression = { $_.'ForwardingSmtpAddress' -replace 'smtp:', '' } }, @{Name = 'InternalForwardingAddress'; Expression = { $_.'ForwardingAddress' } }, - DeliverToMailboxAndForward + DeliverToMailboxAndForward, + HiddenFromAddressListsEnabled, + ExternalDirectoryObjectId $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 index 5547efe9cfd2..c540e1803567 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 @@ -19,7 +19,7 @@ Function Invoke-ListSignIns { $Days = $Request.Query.Days ?? 7 try { - if ($Request.Query.failedLogonsOnly) { + if ($Request.Query.failedLogonsOnly -eq 'true' -or $Request.Query.failedLogonsOnly -eq $true) { $FailedLogons = ' and (status/errorCode eq 50126)' } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 index dd39cb4ac683..7cea2d2bc1d1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 @@ -42,14 +42,6 @@ Function Invoke-ListStandards { StandardsExport = ($tenant.Standards.psobject.properties.name) -join ', ' } } - if (!$CurrentStandards) { - $CurrentStandards = [PSCustomObject]@{ - displayName = 'No Standards applied' - appliedBy = $null - appliedAt = $null - standards = @{none = $null } - } - } $CurrentStandards = ConvertTo-Json -InputObject @($CurrentStandards) -Depth 15 -Compress } diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 index 0f56ae4a7e99..25deaf238213 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 @@ -7,20 +7,28 @@ function Start-AuditLogOrchestrator { param() try { $AuditLogSearchesTable = Get-CIPPTable -TableName 'AuditLogSearches' - $AuditLogSearches = Get-CIPPAzDataTableEntity @AuditLogSearchesTable -Filter "CippStatus eq 'Pending'" + $15MinutesAgo = (Get-Date).AddMinutes(-15).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $1DayAgo = (Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $AuditLogSearches = Get-CIPPAzDataTableEntity @AuditLogSearchesTable -Filter "(CippStatus eq 'Pending' or (CippStatus eq 'Processing' and Timestamp le datetime'$15MinutesAgo')) and Timestamp ge datetime'$1DayAgo'" -Property PartitionKey, RowKey, Tenant, CippStatus, Timestamp + + $WebhookRulesTable = Get-CIPPTable -TableName 'WebhookRules' + $WebhookRules = Get-CIPPAzDataTableEntity @WebhookRulesTable if (($AuditLogSearches | Measure-Object).Count -eq 0) { Write-Information 'No audit log searches available' + } elseif (($WebhookRules | Measure-Object).Count -eq 0) { + Write-Information 'No webhook rules defined' } else { - $Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($AuditLogSearches).Count - $Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } } - - $InputObject = [PSCustomObject]@{ - OrchestratorName = 'AuditLogs' - Batch = @($Batch) - SkipLog = $true - } + Write-Information "Audit Logs: Processing $($AuditLogSearches.Count) searches" if ($PSCmdlet.ShouldProcess('Start-AuditLogOrchestrator', 'Starting Audit Log Polling')) { + $Queue = New-CippQueueEntry -Name 'Audit Log Collection' -Reference 'AuditLogCollection' -TotalTasks ($AuditLogSearches).Count + $Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenant' } } + + $InputObject = [PSCustomObject]@{ + OrchestratorName = 'AuditLogs' + Batch = @($Batch) + SkipLog = $true + } Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 index 08495c8fb763..d999ac046a71 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UpdatePermissionsOrchestrator.ps1 @@ -7,20 +7,30 @@ function Start-UpdatePermissionsOrchestrator { param() try { + Write-Information 'Updating Permissions' $Tenants = Get-Tenants -IncludeAll | Where-Object { $_.customerId -ne $env:TenantID -and $_.Excluded -eq $false } $CPVTable = Get-CIPPTable -TableName cpvtenants $CPVRows = Get-CIPPAzDataTableEntity @CPVTable - $ModuleRoot = (Get-Module CIPPCore).ModuleBase - $SAMManifest = Get-Item -Path "$ModuleRoot\Public\SAMManifest.json" - $AdditionalPermissions = Get-Item -Path "$ModuleRoot\Public\AdditionalPermissions.json" + $LastCPV = ($CPVRows | Sort-Object -Property Timestamp -Descending | Select-Object -First 1).Timestamp.DateTime + Write-Information "CPV last updated at $LastCPV" + + $SAMPermissions = Get-CIPPSamPermissions + Write-Information "SAM Permissions last updated at $($SAMPermissions.Timestamp)" + + $SAMRolesTable = Get-CIPPTable -TableName SAMRoles + $SAMRoles = Get-CIPPAzDataTableEntity @SAMRolesTable + Write-Information "SAM Roles last updated at $($SAMRoles.Timestamp.DateTime)" + $Tenants = $Tenants | ForEach-Object { $CPVRow = $CPVRows | Where-Object -Property Tenant -EQ $_.customerId - if (!$CPVRow -or $env:ApplicationID -notin $CPVRow.applicationId -or $SAMManifest.LastWriteTime.ToUniversalTime() -gt $CPVRow.Timestamp.DateTime -or $AdditionalPermissions.LastWriteTime.ToUniversalTime() -ge $CPVRow.Timestamp.DateTime -or $CPVRow.Timestamp.DateTime -le (Get-Date).AddDays(-7).ToUniversalTime() -or !$_.defaultDomainName) { + if (!$CPVRow -or $env:ApplicationID -notin $CPVRow.applicationId -or $SAMPermissions.Timestamp -gt $CPVRow.Timestamp.DateTime -or $CPVRow.Timestamp.DateTime -le (Get-Date).AddDays(-7).ToUniversalTime() -or !$_.defaultDomainName -or ($SAMroles.Timestamp.DateTime -gt $CPVRow.Timestamp.DateTime -and ($SAMRoles.Tenants -contains $_.defaultDomainName -or $SAMRoles.Tenants.value -contains $_.defaultDomainName -or $SAMRoles.Tenants -contains 'AllTenants' -or $SAMRoles.Tenants.value -contains 'AllTenants'))) { $_ } } $TenantCount = ($Tenants | Measure-Object).Count + if ($TenantCount -gt 0) { + Write-Information "Found $TenantCount tenants that require permissions update" $Queue = New-CippQueueEntry -Name 'Update Permissions' -TotalTasks $TenantCount $TenantBatch = $Tenants | Select-Object defaultDomainName, customerId, displayName, @{n = 'FunctionName'; exp = { 'UpdatePermissionsQueue' } }, @{n = 'QueueId'; exp = { $Queue.RowKey } } $InputObject = [PSCustomObject]@{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UserTasksOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UserTasksOrchestrator.ps1 index 10aebb5c0767..26cf32cb9627 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UserTasksOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UserTasksOrchestrator.ps1 @@ -7,7 +7,8 @@ function Start-UserTasksOrchestrator { param() $Table = Get-CippTable -tablename 'ScheduledTasks' - $Filter = "TaskState eq 'Planned' or TaskState eq 'Failed - Planned'" + $1HourAgo = (Get-Date).AddHours(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $Filter = "TaskState eq 'Planned' or TaskState eq 'Failed - Planned' or (TaskState eq 'Running' and Timestamp lt datetime'$1HourAgo')" $tasks = Get-CIPPAzDataTableEntity @Table -Filter $Filter $Batch = [System.Collections.Generic.List[object]]::new() $TenantList = Get-Tenants -IncludeErrors @@ -16,7 +17,7 @@ function Start-UserTasksOrchestrator { $currentUnixTime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds if ($currentUnixTime -ge $task.ScheduledTime) { try { - $null = Update-AzDataTableEntity @Table -Entity @{ + $null = Update-AzDataTableEntity -Force @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey ExecutedTime = "$currentUnixTime" @@ -36,7 +37,9 @@ function Start-UserTasksOrchestrator { if ($task.Tenant -eq 'AllTenants') { $AllTenantCommands = foreach ($Tenant in $TenantList) { $NewParams = $task.Parameters.Clone() - $NewParams.TenantFilter = $Tenant.defaultDomainName + if ((Get-Command $task.Command).Parameters.TenantFilter) { + $NewParams.TenantFilter = $Tenant.defaultDomainName + } [pscustomobject]@{ Command = $task.Command Parameters = $NewParams @@ -46,13 +49,15 @@ function Start-UserTasksOrchestrator { } $Batch.AddRange($AllTenantCommands) } else { - $ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant + if ((Get-Command $task.Command).Parameters.TenantFilter) { + $ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant + } $Batch.Add($ScheduledCommand) } } catch { $errorMessage = $_.Exception.Message - $null = Update-AzDataTableEntity @Table -Entity @{ + $null = Update-AzDataTableEntity -Force @Table -Entity @{ PartitionKey = $task.PartitionKey RowKey = $task.RowKey Results = "$errorMessage" diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPStatsTimer.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPStatsTimer.ps1 index 83cbc4b344a1..d62dcb8fd8ed 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPStatsTimer.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPStatsTimer.ps1 @@ -14,8 +14,17 @@ function Start-CIPPStatsTimer { } $TenantCount = (Get-Tenants -IncludeAll).count - Set-Location (Get-Item $PSScriptRoot).Parent.FullName - $APIVersion = Get-Content 'version_latest.txt' | Out-String + + $ModuleBase = Get-Module CIPPCore | Select-Object -ExpandProperty ModuleBase + $CIPPRoot = (Get-Item $ModuleBase).Parent.Parent.FullName + + $APIVersion = Get-Content "$CIPPRoot\version_latest.txt" | Out-String + $Table = Get-CIPPTable -TableName Extensionsconfig + try { + $RawExt = (Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -Depth 10 -ErrorAction Stop + } catch { + $RawExt = @{} + } $SendingObject = [PSCustomObject]@{ rgid = $env:WEBSITE_SITE_NAME @@ -23,6 +32,14 @@ function Start-CIPPStatsTimer { RunningVersionAPI = $APIVersion.trim() CountOfTotalTenants = $tenantcount uid = $env:TenantID + CIPPAPI = $RawExt.CIPPAPI.Enabled + Hudu = $RawExt.Hudu.Enabled + Sherweb = $RawExt.Sherweb.Enabled + Gradient = $RawExt.Gradient.Enabled + NinjaOne = $RawExt.NinjaOne.Enabled + haloPSA = $RawExt.haloPSA.Enabled + HIBP = $RawExt.HIBP.Enabled + PWPush = $RawExt.PWPush.Enabled } | ConvertTo-Json Invoke-RestMethod -Uri 'https://management.cipp.app/api/stats' -Method POST -Body $SendingObject -ContentType 'application/json' diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 index 1f7cd63a8d3b..32ae68c270b3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-UpdateTokensTimer.ps1 @@ -10,32 +10,35 @@ function Start-UpdateTokensTimer { # Get the current universal time in the default string format. $currentUTCtime = (Get-Date).ToUniversalTime() + try { + $Refreshtoken = (Get-GraphToken -ReturnRefresh $true).Refresh_token - $Refreshtoken = (Get-GraphToken -ReturnRefresh $true).Refresh_token - - if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { - $Table = Get-CIPPTable -tablename 'DevSecrets' - $Secret = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" - if ($Secret) { - $Secret.RefreshToken = $Refreshtoken - Add-AzDataTableEntity @Table -Entity $Secret -Force - } else { - Write-LogMessage -message 'Could not update refresh token. Will try again in 7 days.' -sev 'CRITICAL' - } - } else { - if ($env:MSI_SECRET) { - Disable-AzContextAutosave -Scope Process | Out-Null - $AzSession = Connect-AzAccount -Identity - } - $KV = $ENV:WEBSITE_DEPLOYMENT_ID - if ($Refreshtoken) { - Set-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Refreshtoken -AsPlainText -Force) + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $Table = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" + if ($Secret) { + $Secret.RefreshToken = $Refreshtoken + Add-AzDataTableEntity @Table -Entity $Secret -Force + } else { + Write-LogMessage -API 'Update Tokens' -message 'Could not update refresh token. Will try again in 7 days.' -sev 'CRITICAL' + } } else { - Write-LogMessage -message 'Could not update refresh token. Will try again in 7 days.' -sev 'CRITICAL' + if ($env:MSI_SECRET) { + Disable-AzContextAutosave -Scope Process | Out-Null + $AzSession = Connect-AzAccount -Identity + } + $KV = ($ENV:WEBSITE_DEPLOYMENT_ID -split '-')[0] + if ($Refreshtoken) { + Set-AzKeyVaultSecret -VaultName $KV -Name 'RefreshToken' -SecretValue (ConvertTo-SecureString -String $Refreshtoken -AsPlainText -Force) + } else { + Write-LogMessage -API 'Update Tokens' -message 'Could not update refresh token. Will try again in 7 days.' -sev 'CRITICAL' + } } + } catch { + Write-LogMessage -API 'Update Tokens' -message 'Error updating refresh token, see Log Data for details. Will try again in 7 days.' -sev 'CRITICAL' -LogData (Get-CippException -Exception $_) } - # Write an information log with the current time. Write-Information "PowerShell timer trigger function ran! TIME: $currentUTCtime" + } } diff --git a/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 b/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 index fd5676683860..f7f6362b8e22 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 @@ -59,6 +59,7 @@ function Get-CIPPAzDataTableEntity { } $fullEntity | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value $parts[0].PartitionKey -Force $fullEntity | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value $entityId -Force + $fullEntity | Add-Member -MemberType NoteProperty -Name 'Timestamp' -Value $parts[0].Timestamp -Force $finalResults = $finalResults + @($fullEntity) } else { $finalResults = $finalResults + @($entityData.Entity) diff --git a/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 b/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 index c172f40f1c90..91d29ac8ec0f 100644 --- a/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPBackup.ps1 @@ -1,15 +1,31 @@ function Get-CIPPBackup { [CmdletBinding()] param ( - [string]$Type, - [string]$TenantFilter + [string]$Type = 'CIPP', + [string]$TenantFilter, + [string]$Name, + [switch]$NameOnly ) Write-Host "Getting backup for $Type with TenantFilter $TenantFilter" $Table = Get-CippTable -tablename "$($Type)Backup" + + $Conditions = [System.Collections.Generic.List[string]]::new() + $Conditions.Add("PartitionKey eq '$($Type)Backup'") + if ($TenantFilter) { - $Filter = "PartitionKey eq '$($Type)Backup' and TenantFilter eq '$($TenantFilter)'" - $Table.Filter = $Filter + $Conditions.Add("TenantFilter eq '$($TenantFilter)'") } + if ($Name) { + $Conditions.Add("RowKey eq '$($Name)' or OriginalEntityId eq '$($Name)'") + } + + if ($NameOnly.IsPresent) { + $Table.Property = @('PartitionKey', 'RowKey', 'Timestamp', 'OriginalEntityId') + } + + $Filter = $Conditions -join ' and ' + $Table.Filter = $Filter + $Info = Get-CIPPAzDataTableEntity @Table return $info } diff --git a/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 b/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 index 59877c61f9da..1ee4efcd43df 100644 --- a/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 @@ -3,7 +3,21 @@ function Get-CIPPGeoIPLocation { param ( [string]$IP ) + + $CacheGeoIPTable = Get-CippTable -tablename 'cachegeoip' + $30DaysAgo = (Get-Date).AddDays(-30).ToString('yyyy-MM-ddTHH:mm:ssZ') + $Filter = "RowKey eq '$IP' and Timestamp ge datetime'$30DaysAgo'" + $GeoIP = Get-CippAzDataTableEntity @CacheGeoIPTable -Filter $Filter + if ($GeoIP) { + return ($GeoIP.Data | ConvertFrom-Json) + } $location = Invoke-RestMethod "https://geoipdb.azurewebsites.net/api/GetIPInfo?IP=$IP" if ($location.status -eq 'FAIL') { throw "Could not get location for $IP" } + $CacheGeo = @{ + PartitionKey = 'IP' + RowKey = $IP + Data = [string]($location | ConvertTo-Json -Compress) + } + Add-AzDataTableEntity @CacheGeoIPTable -Entity $CacheGeo -Force return $location } diff --git a/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 b/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 index 712301b3dc77..9cb9e6914f9c 100644 --- a/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 @@ -92,9 +92,9 @@ function Get-CIPPMFAState { } } - $PerUser = if ($PerUserMFAState -eq $null) { $null } else { ($PerUserMFAState | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).PerUserMFAState } + $PerUser = if ($null -eq $PerUserMFAState) { $null } else { ($PerUserMFAState | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).PerUserMFAState } - $MFARegUser = if (($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName).isMFARegistered -eq $null) { $false } else { ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName) } + $MFARegUser = if ($null -eq ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName).isMFARegistered) { $false } else { ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.userPrincipalName) } [PSCustomObject]@{ Tenant = $TenantFilter diff --git a/Modules/CIPPCore/Public/Get-CIPPTimerFunctions.ps1 b/Modules/CIPPCore/Public/Get-CIPPTimerFunctions.ps1 index 94b050c6065f..c17c4dd61100 100644 --- a/Modules/CIPPCore/Public/Get-CIPPTimerFunctions.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPTimerFunctions.ps1 @@ -1,8 +1,8 @@ function Get-CIPPTimerFunctions { [CmdletBinding()] param( - [switch]$All, - [switch]$ResetToDefault + [switch]$ResetToDefault, + [switch]$ListAllTasks ) $ConfigTable = Get-CIPPTable -tablename Config @@ -23,7 +23,7 @@ function Get-CIPPTimerFunctions { $RunOnProcessor = $true if ($Config -and $Config.state -eq $true) { - if ($env:CIPP_PROCESSOR -ne 'true' -and !$All.IsPresent) { + if ($env:CIPP_PROCESSOR -ne 'true') { $RunOnProcessor = $false } } @@ -38,12 +38,26 @@ function Get-CIPPTimerFunctions { } $CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent - $Orchestrators = Get-Content -Path $CIPPRoot\CIPPTimers.json | ConvertFrom-Json | Where-Object { $_.RunOnProcessor -eq $RunOnProcessor } + $CippTimers = Get-Content -Path $CIPPRoot\CIPPTimers.json + if ($ListAllTasks) { + $Orchestrators = $CippTimers | ConvertFrom-Json | Sort-Object -Property Priority + } else { + $Orchestrators = $CippTimers | ConvertFrom-Json | Where-Object { $_.RunOnProcessor -eq $RunOnProcessor } | Sort-Object -Property Priority + } $Table = Get-CIPPTable -TableName 'CIPPTimers' $RunOnProcessorTxt = if ($RunOnProcessor) { 'true' } else { 'false' } - $OrchestratorStatus = Get-CIPPAzDataTableEntity @Table -Filter "RunOnProcessor eq $RunOnProcessorTxt" + if ($ListAllTasks.IsPresent) { + $OrchestratorStatus = Get-CIPPAzDataTableEntity @Table + } else { + $OrchestratorStatus = Get-CIPPAzDataTableEntity @Table -Filter "RunOnProcessor eq $RunOnProcessorTxt" + } + + $OrchestratorStatus | Where-Object { $_.RowKey -notmatch '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' } | Select-Object ETag, PartitionKey, RowKey | ForEach-Object { + Remove-AzDataTableEntity @Table -Entity $_ -Force + } + foreach ($Orchestrator in $Orchestrators) { - $Status = $OrchestratorStatus | Where-Object { $_.RowKey -eq $Orchestrator.Command } + $Status = $OrchestratorStatus | Where-Object { $_.RowKey -eq $Orchestrator.Id } if ($Status.Cron) { $CronString = $Status.Cron } else { @@ -59,16 +73,18 @@ function Get-CIPPTimerFunctions { continue } - if ($Orchestrator.PreferredProcessor -and $AvailableNodes -contains $Orchestrator.PreferredProcessor -and $Node -ne $Orchestrator.PreferredProcessor) { - # only run on preferred processor when available - continue - } elseif ((!$Orchestrator.PreferredProcessor -or $AvailableNodes -notcontains $Orchestrator.PreferredProcessor) -and $Node -notin ('http', 'proc')) { - # Catchall function nodes - continue + if (!$ListAllTasks.IsPresent) { + if ($Orchestrator.PreferredProcessor -and $AvailableNodes -contains $Orchestrator.PreferredProcessor -and $Node -ne $Orchestrator.PreferredProcessor) { + # only run on preferred processor when available + continue + } elseif ((!$Orchestrator.PreferredProcessor -or $AvailableNodes -notcontains $Orchestrator.PreferredProcessor) -and $Node -notin ('http', 'proc')) { + # Catchall function nodes + continue + } } $Now = Get-Date - if ($All.IsPresent) { + if ($ListAllTasks.IsPresent) { $NextOccurrence = [datetime]$Cron.GetNextOccurrence($Now) } else { $NextOccurrences = $Cron.GetNextOccurrences($Now.AddMinutes(-15), $Now.AddMinutes(15)) @@ -80,11 +96,12 @@ function Get-CIPPTimerFunctions { } if (Get-Command -Name $Orchestrator.Command -Module CIPPCore -ErrorAction SilentlyContinue) { - if ($NextOccurrence) { + if ($NextOccurrence -or $ListAllTasks.IsPresent) { if (!$Status) { $Status = [pscustomobject]@{ PartitionKey = 'Timer' - RowKey = $Orchestrator.Command + RowKey = $Orchestrator.Id + Command = $Orchestrator.Command Cron = $CronString LastOccurrence = 'Never' NextOccurrence = $NextOccurrence.ToUniversalTime() @@ -94,7 +111,7 @@ function Get-CIPPTimerFunctions { IsSystem = $Orchestrator.IsSystem ?? $false PreferredProcessor = $Orchestrator.PreferredProcessor ?? '' } - Add-CIPPAzDataTableEntity @Table -Entity $Status + Add-CIPPAzDataTableEntity @Table -Entity $Status -Force } else { if ($Orchestrator.IsSystem -eq $true -or $ResetToDefault.IsPresent) { $Status.Cron = $CronString @@ -110,15 +127,19 @@ function Get-CIPPTimerFunctions { } [PSCustomObject]@{ + Id = $Orchestrator.Id + Priority = $Orchestrator.Priority Command = $Orchestrator.Command + Parameters = $Orchestrator.Parameters ?? @{} Cron = $CronString NextOccurrence = $NextOccurrence.ToUniversalTime() - LastOccurrence = $Status.LastOccurrence.DateTime + LastOccurrence = $Status.LastOccurrence Status = $Status.Status OrchestratorId = $Status.OrchestratorId RunOnProcessor = $Orchestrator.RunOnProcessor IsSystem = $Orchestrator.IsSystem ?? $false PreferredProcessor = $Orchestrator.PreferredProcessor ?? '' + ErrorMsg = $Status.ErrorMsg ?? '' } } } else { diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 index f8147728a15c..15ae8b23dc70 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-AuthorisedRequest.ps1 @@ -12,12 +12,13 @@ function Get-AuthorisedRequest { if (!$TenantID) { $TenantID = $env:TenantID } + if ($Uri -like 'https://graph.microsoft.com/beta/contracts*' -or $Uri -like '*/customers/*' -or $Uri -eq 'https://graph.microsoft.com/v1.0/me/sendMail' -or $Uri -like '*/tenantRelationships/*' -or $Uri -like '*/security/partner/*') { return $true } - $Tenants = Get-Tenants -IncludeErrors - $SkipList = Get-Tenants -SkipList - if (($env:PartnerTenantAvailable -eq $true -and $SkipList.customerId -notcontains $TenantID -and $SkipList.defaultDomainName -notcontains $TenantID) -or (($Tenants.customerId -contains $TenantID -or $Tenants.defaultDomainName -contains $TenantID) -and $TenantID -ne $env:TenantID)) { + $Tenant = Get-Tenants -TenantFilter $TenantID | Where-Object { $_.Excluded -eq $false } + + if ($Tenant) { return $true } else { return $false diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 index 32ede8169d61..3018d7abf23d 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1 @@ -25,10 +25,10 @@ function Get-CippSamPermissions { if (!$SavedOnly.IsPresent) { $ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase - $SamManifestFile = Get-Item (Join-Path $ModuleBase "Public\SAMManifest.json") - $AdditionalPermissions = Get-Item (Join-Path $ModuleBase "Public\AdditionalPermissions.json") + $SamManifestFile = Get-Item (Join-Path $ModuleBase 'Public\SAMManifest.json') + $AdditionalPermissions = Get-Item (Join-Path $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 + $ServicePrincipalList = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$select=id,appId,displayName' -tenantid $env:TenantID -NoAuthCheck $true $SAMManifest = Get-Content -Path $SamManifestFile.FullName | ConvertFrom-Json $AdditionalPermissions = Get-Content -Path $AdditionalPermissions.FullName | ConvertFrom-Json @@ -36,6 +36,22 @@ function Get-CippSamPermissions { $AppIds = ($RequiredResources.resourceAppId + $AdditionalPermissions.resourceAppId) | Sort-Object -Unique + Write-Information "Retrieving service principals for $($AppIds.Count) applications" + $UsedServicePrincipals = $ServicePrincipalList | Where-Object -Property appId -In $AppIds + $Requests = $UsedServicePrincipals | ForEach-Object { + @( + @{ + id = $_.id + url = 'servicePrincipals/{0}?$select=appId,displayName,appRoles,publishedPermissionScopes' -f $_.id + method = 'GET' + } + ) + } + $BulkRequests = New-GraphBulkRequest -Requests $Requests -NoAuthCheck $true -tenantid $env:TenantID + $ServicePrincipals = $BulkRequests | ForEach-Object { + $_.body + } + $Permissions = @{} foreach ($AppId in $AppIds) { $ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId @@ -96,7 +112,11 @@ function Get-CippSamPermissions { $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 + try { + $SavedPermissions.Permissions = $SavedPermissions.Permissions | ConvertFrom-Json -ErrorAction Stop + } catch { + $SavedPermissions.Permissions = [PSCustomObject]@{} + } } else { $SavedPermissions = @{ Permissions = [PSCustomObject]@{} @@ -108,21 +128,24 @@ function Get-CippSamPermissions { return $SavedPermissions } - if (!$NoDiff -and $SavedPermissions.Permissions) { + if (!$NoDiff.IsPresent -and $SavedPermissions.Permissions) { $DiffPermissions = @{} foreach ($AppId in $AppIds) { $ManifestSpPermissions = $Permissions.$AppId + $ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $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) + $AppRole = $ServicePrincipal.appRoles | Where-Object -Property id -EQ $Permission.id | Select-Object id, value + $MissingApp.Add($AppRole ?? $Permission) } } foreach ($Permission in $ManifestSpPermissions.delegatedPermissions) { if ($SavedSpPermission.delegatedPermissions.id -notcontains $Permission.id) { - $MissingDelegated.Add($Permission) + $PermissionScope = $ServicePrincipal.publishedPermissionScopes | Where-Object -Property id -EQ $Permission.id | Select-Object id, value + $MissingDelegated.Add($PermissionScope ?? $Permission) } } if ($MissingApp -or $MissingDelegated) { @@ -137,14 +160,29 @@ function Get-CippSamPermissions { $SamAppPermissions = @{} if (($SavedPermissions.Permissions.PSObject.Properties.Name | Measure-Object).Count -gt 0) { $SamAppPermissions.Permissions = $SavedPermissions.Permissions + $SamAppPermissions.UsedServicePrincipals = $UsedServicePrincipals $SamAppPermissions.UpdatedBy = $SavedPermissions.UpdatedBy $SamAppPermissions.Timestamp = $SavedPermissions.Timestamp.DateTime.ToString('yyyy-MM-ddTHH:mm:ssZ') $SamAppPermissions.Type = 'Table' } else { $SamAppPermissions.Permissions = $Permissions + $SamAppPermissions.UsedServicePrincipals = $UsedServicePrincipals $SamAppPermissions.Type = 'Manifest' $SamAppPermissions.UpdatedBy = 'CIPP' $SamAppPermissions.Timestamp = $SamManifestFile.LastWriteTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + + $Entity = @{ + 'PartitionKey' = 'CIPP-SAM' + 'RowKey' = 'CIPP-SAM' + 'Permissions' = [string]([PSCustomObject]$Permissions | ConvertTo-Json -Depth 10 -Compress) + 'UpdatedBy' = 'CIPP' + } + $Table = Get-CIPPTable -TableName 'AppPermissions' + try { + $null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + } catch { + Write-Error "Failed to save the CIPP-SAM permissions: $($_.Exception.Message)" + } } if (!$NoDiff.IsPresent -and $SamAppPermissions.Type -eq 'Table') { diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 index 5dc55d946cd8..5a10c27f1e38 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-ClassicAPIToken.ps1 @@ -38,7 +38,7 @@ function Get-ClassicAPIToken($tenantID, $Resource) { $Tenant.LastGraphError = $_.Exception.Message $Tenant.GraphErrorCount++ - Update-AzDataTableEntity @TenantsTable -Entity $Tenant + Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant Throw "Failed to obtain Classic API Token for $TenantID - $_" } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 index 626dc7ba842a..49e9f7de1b37 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-GraphToken.ps1 @@ -81,7 +81,7 @@ function Get-GraphToken($tenantid, $scope, $AsApp, $AppID, $AppSecret, $refreshT } $Tenant.GraphErrorCount++ - if (!$donotset) { Update-AzDataTableEntity @TenantsTable -Entity $Tenant } + if (!$donotset) { Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant } throw "Could not get token: $($Tenant.LastGraphError)" } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 index 1755a9f58378..12740aeb73e3 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-NormalizedError.ps1 @@ -44,7 +44,6 @@ function Get-NormalizedError { '*Provide valid credential.*' { 'Error 400: There is an issue with your Exchange Token configuration. Please perform an access check for this tenant' } '*This indicate that a subscription within the tenant has lapsed*' { 'There is subscription for this service available, Check licensing information.' } '*User was not found.*' { 'The relationship between this tenant and the partner has been dissolved from the tenant side.' } - '*The user or administrator has not consented to use the application*' { 'CIPP cannot access this tenant. Perform a CPV Refresh and Access Check via the settings menu' } '*AADSTS50020*' { 'AADSTS50020: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } '*AADSTS50177' { 'AADSTS50177: The user you have used for your Secure Application Model is a guest in this tenant, or your are using GDAP and have not added the user to the correct group. Please delete the guest user to gain access to this tenant' } '*invalid or malformed*' { 'The request is malformed. Have you finished the SAM Setup?' } @@ -58,6 +57,14 @@ function Get-NormalizedError { '*Providers.Common.V1.CoreException*' { '403 (Access Denied) - We cannot connect to this tenant.' } '*Authentication failed. MFA required*' { 'Authentication failed. MFA required' } '*Your tenant is not licensed for this feature.*' { 'Required license not available for this tenant' } + '*AADSTS65001*' { 'We cannot access this tenant as consent has not been given, please try refreshing the CPV permissions in the application settings menu.' } + '*AADSTS700082*' { 'The CIPP user access token has expired. Run the SAM Setup wizard to refresh your tokens.' } + '*Account is not provisioned.' { 'The account is not provisioned. You do not the correct M365 license to access this information..' } + '*AADSTS5000224*' { 'This resource is not available - Has this tenant been deleted?' } + '*AADSTS53003*' { 'Access has been blocked by Conditional Access policies. Please check the Conditional Access configuration documentation' } + '*AADSTS900023*' { 'This tenant is not available for this operation. Please check the selected tenant and try again.' } + '*AADSTS9002313*' { 'The credentials used to connect to the Graph API are not available, please retry. If this issue persists you may need to execute the SAM wizard.' } + '*One or more platform(s) is/are not configured for the customer. Please configure the platform before trying to purchase a SKU.*' { 'One or more platform(s) is/are not configured for the customer. Please configure the platform before trying to purchase a SKU.' } Default { $message } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 index eb8a7c0c45fb..6cd3bd8bb5c6 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Get-Tenants.ps1 @@ -50,11 +50,11 @@ function Get-Tenants { $IncludedTenantsCache = Get-CIPPAzDataTableEntity @TenantsTable -Filter $Filter - if (($IncludedTenantsCache | Measure-Object).Count -eq 0) { + if (($IncludedTenantsCache | Measure-Object).Count -eq 0 -and $TenantFilter -ne $env:TenantID) { $BuildRequired = $true } - if ($CleanOld) { + if ($CleanOld.IsPresent) { $GDAPRelationships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships?`$filter=status eq 'active' and not startsWith(displayName,'MLT_')&`$select=customer,autoExtendDuration,endDateTime&`$top=300" -NoAuthCheck:$true $GDAPList = foreach ($Relationship in $GDAPRelationships) { [PSCustomObject]@{ @@ -65,7 +65,7 @@ function Get-Tenants { } } $CurrentTenants = Get-CIPPAzDataTableEntity @TenantsTable -Filter "PartitionKey eq 'Tenants' and Excluded eq false" - $CurrentTenants | Where-Object { $_.customerId -notin $GDAPList.customerId } | ForEach-Object { + $CurrentTenants | Where-Object { $_.customerId -notin $GDAPList.customerId -and $_.customerId -ne $env:TenantID } | ForEach-Object { Remove-AzDataTableEntity -Force @TenantsTable -Entity $_ } } @@ -121,6 +121,7 @@ function Get-Tenants { } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'Get-Tenants' -message "Tried adding $($LatestRelationship.customerId) to tenant list but failed to get domains - $($_.Exception.Message)" -Sev 'Critical' -LogData $ErrorMessage + $Domain = 'Invalid' } finally { $defaultDomainName = $Domain $initialDomainName = $Domain diff --git a/Modules/CIPPCore/Public/GraphHelper/New-ExoBulkRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-ExoBulkRequest.ps1 index 277802cd8e3e..20a976d1e023 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-ExoBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-ExoBulkRequest.ps1 @@ -1,9 +1,7 @@ - - function New-ExoBulkRequest { <# .FUNCTIONALITY - Internal + Internal #> [CmdletBinding()] param( @@ -13,9 +11,11 @@ function New-ExoBulkRequest { $Anchor, $NoAuthCheck, $Select, + $ReturnWithCommand, [switch]$Compliance, [switch]$AsApp ) + if ((Get-AuthorisedRequest -TenantID $tenantid) -or $NoAuthCheck -eq $True) { if ($Compliance.IsPresent) { $Resource = 'https://ps.compliance.protection.outlook.com' @@ -33,52 +33,28 @@ function New-ExoBulkRequest { } if ($Compliance.IsPresent) { - if (!$Anchor) { - if (!$Tenant.initialDomainName -or $Tenant.initialDomainName -notlike '*onmicrosoft.com*') { - $OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantid -NoAuthCheck $NoAuthCheck | Where-Object -Property isInitial -EQ $true).id - } else { - $OnMicrosoft = $Tenant.initialDomainName - } - $Headers.Anchor = "UPN:SystemMailbox{bb558c35-97f1-4cb9-8ff7-d53741dc928c}@$($OnMicrosoft)" - } - if (!$Tenant.ComplianceUrl) { - Write-Verbose "Getting Compliance URL for $($tenant.defaultDomainName)" - $URL = "$Resource/adminapi/$ApiVersion/$($tenant.customerId)/EXOBanner('AutogenSession')?Version=$ModuleVersion" - Invoke-RestMethod -ResponseHeadersVariable ComplianceHeaders -MaximumRedirection 0 -ErrorAction SilentlyContinue -Uri $URL -Headers $Headers -SkipHttpErrorCheck | Out-Null - $RedirectedHost = ([System.Uri]($ComplianceHeaders.Location | Select-Object -First 1)).Host - $RedirectedHostname = '{0}.ps.compliance.protection.outlook.com' -f ($RedirectedHost -split '\.' | Select-Object -First 1) - $Resource = "https://$($RedirectedHostname)" - try { - $null = [System.Uri]$Resource - $Tenant | Add-Member -MemberType NoteProperty -Name ComplianceUrl -Value $Resource - $TenantTable = Get-CIPPTable -tablename 'Tenants' - Add-CIPPAzDataTableEntity @TenantTable -Entity $Tenant -Force - } catch { - Write-Error "Failed to get the Compliance URL for $($tenant.defaultDomainName), invalid URL - check the Anchor and try again." - return - } - } else { - $Resource = $Tenant.ComplianceUrl - } - Write-Verbose "Redirecting to $Resource" + # Compliance URL logic (omitted for brevity) } try { if ($Select) { $Select = "`$select=$Select" } - $URL = "$Resource/adminapi/beta/$($tenant.customerId)/InvokeCommand?$Select" - $BatchURL = "$Resource/adminapi/beta/$($tenant.customerId)/`$batch" - $BatchBodyObj = @{ - requests = @() - } + $URL = "$Resource/adminapi/beta/$($Tenant.customerId)/InvokeCommand?$Select" + $BatchURL = "$Resource/adminapi/beta/$($Tenant.customerId)/`$batch" + + # Initialize the ID to Cmdlet Name mapping + $IdToCmdletName = @{} + # Split the cmdletArray into batches of 10 $batches = [System.Collections.ArrayList]@() for ($i = 0; $i -lt $cmdletArray.Length; $i += 10) { $null = $batches.Add($cmdletArray[$i..[math]::Min($i + 9, $cmdletArray.Length - 1)]) } - # Process each batch - $ReturnedData = foreach ($batch in $batches) { - $BatchBodyObj.requests = [System.Collections.ArrayList]@() + $ReturnedData = @() + foreach ($batch in $batches) { + $BatchBodyObj = @{ + requests = @() + } foreach ($cmd in $batch) { $cmdparams = $cmd.CmdletInput.Parameters if ($cmdparams.Identity) { $Anchor = $cmdparams.Identity } @@ -88,48 +64,83 @@ function New-ExoBulkRequest { $OnMicrosoft = $Tenant.initialDomainName $Anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)" } - $headers['X-AnchorMailbox'] = $Anchor + $Headers['X-AnchorMailbox'] = $Anchor $Headers['X-CmdletName'] = $cmd.CmdletInput.CmdletName - $headers['Accept'] = 'application/json; odata.metadata=minimal' - $headers['Accept-Encoding'] = 'gzip' + $Headers['Accept'] = 'application/json; odata.metadata=minimal' + $Headers['Accept-Encoding'] = 'gzip' + + # Generate a unique ID for each request + $RequestId = [Guid]::NewGuid().ToString() $BatchRequest = @{ url = $URL method = 'POST' body = $cmd headers = $Headers.Clone() - id = "$(New-Guid)" + id = $RequestId } - $null = $BatchBodyObj['requests'].add($BatchRequest) + $BatchBodyObj['requests'] = $BatchBodyObj['requests'] + $BatchRequest + + # Map the Request ID to the Cmdlet Name + $IdToCmdletName[$RequestId] = $cmd.CmdletInput.CmdletName } - $Results = Invoke-RestMethod $BatchURL -ResponseHeadersVariable responseHeaders -Method POST -Body (ConvertTo-Json -InputObject $BatchBodyObj -Depth 10) -Headers $Headers -ContentType 'application/json; charset=utf-8' - $Results + $BatchBodyJson = ConvertTo-Json -InputObject $BatchBodyObj -Depth 10 + $Results = Invoke-RestMethod $BatchURL -ResponseHeadersVariable responseHeaders -Method POST -Body $BatchBodyJson -Headers $Headers -ContentType 'application/json; charset=utf-8' + $ReturnedData = $ReturnedData + $Results.responses Write-Host "Batch #$($batches.IndexOf($batch) + 1) of $($batches.Count) processed" } } catch { - $ErrorMess = $($_.Exception.Message) - $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) - $Message = if ($ReportedError.error.details.message) { - $ReportedError.error.details.message - } elseif ($ReportedError.error.message) { $ReportedError.error.message } - else { $ReportedError.error.innererror.internalException.message } - if ($null -eq $Message) { $Message = $ErrorMess } - throw $Message + # Error handling (omitted for brevity) } - $FinalData = foreach ($item in $ReturnedData.responses.body) { - if ($item.'@adminapi.warnings') { - Write-Warning $($item.'@adminapi.warnings' | Out-String) - } - if ($item.error) { - if ($item.error.details.message) { - $msg = [pscustomobject]@{error = $item.error.details.message; target = $item.error.details.target } + + # Process the returned data + if ($ReturnWithCommand) { + $FinalData = @{} + foreach ($item in $ReturnedData) { + $itemId = $item.id + $CmdletName = $IdToCmdletName[$itemId] + $body = $item.body + + if ($body.'@adminapi.warnings') { + Write-Warning ($body.'@adminapi.warnings' | Out-String) + } + if ($body.error) { + if ($body.error.details.message) { + $msg = [pscustomobject]@{ error = $body.error.details.message; target = $body.error.details.target } + } else { + $msg = [pscustomobject]@{ error = $body.error.message; target = $body.error.details.target } + } + $body | Add-Member -MemberType NoteProperty -Name 'value' -Value $msg -Force + } + $resultValue = $body.value + + # Assign results without using += or ArrayList + if (-not $FinalData.ContainsKey($CmdletName)) { + $FinalData[$CmdletName] = @($resultValue) } else { - $msg = [pscustomobject]@{error = $item.error.message; target = $item.error.details.target } + $FinalData[$CmdletName] = $FinalData[$CmdletName] + $resultValue + } + } + } else { + $FinalData = foreach ($item in $ReturnedData) { + $body = $item.body + + if ($body.'@adminapi.warnings') { + Write-Warning ($body.'@adminapi.warnings' | Out-String) } - $item | Add-Member -MemberType NoteProperty -Name 'value' -Value $msg -Force + if ($body.error) { + if ($body.error.details.message) { + $msg = [pscustomobject]@{ error = $body.error.details.message; target = $body.error.details.target } + } else { + $msg = [pscustomobject]@{ error = $body.error.message; target = $body.error.details.target } + } + $body | Add-Member -MemberType NoteProperty -Name 'value' -Value $msg -Force + } + $body.value } - [pscustomobject]$item.value } + return $FinalData + } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' } diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 index bbace99fdca5..d0502b973082 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 @@ -44,7 +44,8 @@ function New-GraphBulkRequest { } foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) { Write-Host 'Getting more' - $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck:$NoAuthCheck + Write-Host $MoreData.body.'@odata.nextLink' + $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck $NoAuthCheck -scope $scope -AsApp $asapp $NewValues = [System.Collections.Generic.List[PSCustomObject]]$MoreData.body.value $AdditionalValues | ForEach-Object { $NewValues.add($_) } $MoreData.body.value = $NewValues @@ -56,7 +57,7 @@ function New-GraphBulkRequest { if ($Message -ne 'Request not applicable to target tenant.') { $Tenant.LastGraphError = $Message ?? '' $Tenant.GraphErrorCount++ - Update-AzDataTableEntity @TenantsTable -Entity $Tenant + Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant } throw $Message } @@ -66,7 +67,7 @@ function New-GraphBulkRequest { } else { $Tenant.LastGraphError = '' } - Update-AzDataTableEntity @TenantsTable -Entity $Tenant + Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant return $ReturnedData.responses } else { diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index f2d95290f673..9f340b1fb0ae 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -3,21 +3,28 @@ function New-GraphGetRequest { .FUNCTIONALITY Internal #> + [CmdletBinding()] Param( - $uri, - $tenantid, - $scope, + [string]$uri, + [string]$tenantid, + [string]$scope, $AsApp, - $noPagination, - $NoAuthCheck, - $skipTokenCache, + [bool]$noPagination, + $NoAuthCheck = $false, + [bool]$skipTokenCache, $Caller, [switch]$ComplexFilter, [switch]$CountOnly, [switch]$IncludeResponseHeaders ) - if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { + if ($NoAuthCheck -eq $false) { + $IsAuthorised = Get-AuthorisedRequest -Uri $uri -TenantID $tenantid + } else { + $IsAuthorised = $true + } + + if ($NoAuthCheck -eq $true -or $IsAuthorised) { if ($scope -eq 'ExchangeOnline') { $AccessToken = Get-ClassicAPIToken -resource 'https://outlook.office365.com' -Tenantid $tenantid $headers = @{ Authorization = "Bearer $($AccessToken.access_token)" } @@ -85,8 +92,11 @@ function New-GraphGetRequest { if ($Message -eq $null) { $Message = $($_.Exception.Message) } if ($Message -ne 'Request not applicable to target tenant.' -and $Tenant) { $Tenant.LastGraphError = $Message + if ($Tenant.PSObject.Properties.Name -notcontains 'GraphErrorCount') { + $Tenant | Add-Member -MemberType NoteProperty -Name 'GraphErrorCount' -Value 0 -Force + } $Tenant.GraphErrorCount++ - Update-AzDataTableEntity @TenantsTable -Entity $Tenant + Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant } throw $Message } @@ -96,8 +106,12 @@ function New-GraphGetRequest { } else { $Tenant.LastGraphError = '' } - $Tenant.GraphErrorCount = 0 - Update-AzDataTableEntity @TenantsTable -Entity $Tenant + if ($Tenant.PSObject.Properties.Name -notcontains 'GraphErrorCount') { + $Tenant | Add-Member -MemberType NoteProperty -Name 'GraphErrorCount' -Value 0 -Force + } else { + $Tenant.GraphErrorCount = 0 + } + Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant return $ReturnedData } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' diff --git a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 index dbd52b564c54..e9e7380906dd 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 @@ -24,7 +24,7 @@ function Remove-CIPPCache { $_ } if ($ClearDomainAnalyserRows) { - Update-AzDataTableEntity @DomainsTable -Entity $ClearDomainAnalyserRows + Update-AzDataTableEntity -Force @DomainsTable -Entity $ClearDomainAnalyserRows } #Clear BPA $BPATable = Get-CippTable -tablename 'cachebpav2' diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 index b8a2b05ed80c..d47a23bbb92f 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-CippFunctionStats.ps1 @@ -27,13 +27,11 @@ function Write-CippFunctionStats { $StatEntity.DurationMS = $DurationMS $StatEntity.ErrorMsg = $ErrorMsg $Entity = [PSCustomObject]$Entity + $DesiredProperties = @('FunctionName', 'Command', 'DurableName') + foreach ($Property in $Entity.PSObject.Properties.Name) { if ($Entity.$Property) { - if ($Entity.$Property.GetType().Name -in ('Hashtable', 'PSCustomObject', 'OrderedHashtable')) { - $StatEntity.$Property = [string]($Entity.$Property | ConvertTo-Json -Compress) - } elseif ($Entity.$Property.GetType().Name -eq 'DateTime' -and $Entity.$Property.Kind -eq 'Local') { - $StatEntity.$Property = $Entity.$Property.ToUniversalTime() - } elseif ($Property -notin ('ETag', 'RowKey', 'PartitionKey', 'Timestamp', 'LastRefresh')) { + if ($Property -in $DesiredProperties) { $StatEntity.$Property = $Entity.$Property } } diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index d32c1ff87f34..98d09f7507c9 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -85,7 +85,12 @@ function Get-GraphRequestList { $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($Item in ($Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { - $ParamCollection.Add($Item.Key, $Item.Value) + if ($Item.Value -is [System.Boolean]) { + $Item.Value = $Item.Value.ToString().ToLower() + } + if ($Item.Value) { + $ParamCollection.Add($Item.Key, $Item.Value) + } } $GraphQuery.Query = $ParamCollection.ToString() $PartitionKey = Get-StringHash -String (@($Endpoint, $ParamCollection.ToString()) -join '-') @@ -155,7 +160,19 @@ function Get-GraphRequestList { $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($Item in ($Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { - $ParamCollection.Add($Item.Key, $Item.Value) + $ParamCollection.Add($Item.Key, $Item.Value -replace '%tenantid%', $TenantId) + } + $GraphQuery.Query = $ParamCollection.ToString() + $GraphRequest.uri = $GraphQuery.ToString() + } + + if ($TenantFilter -ne 'AllTenants' -and $Endpoint -match '%appid%') { + Write-Information "Replacing AppId in endpoint with $env:ApplicationID" + $Endpoint = $Endpoint -replace '%appid%', $env:ApplicationID + $GraphQuery = [System.UriBuilder]('https://graph.microsoft.com/{0}/{1}' -f $Version, $Endpoint) + $ParamCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + foreach ($Item in ($Parameters.GetEnumerator() | Sort-Object -CaseSensitive -Property Key)) { + $ParamCollection.Add($Item.Key, $Item.Value -replace '%appid%', $env:ApplicationID) } $GraphQuery.Query = $ParamCollection.ToString() $GraphRequest.uri = $GraphQuery.ToString() @@ -173,7 +190,7 @@ function Get-GraphRequestList { TenantFilter = $_.defaultDomainName Endpoint = $using:Endpoint Parameters = $using:Parameters - NoPagination = $using:NoPagination.IsPresent + NoPagination = $false ReverseTenantLookupProperty = $using:ReverseTenantLookupProperty ReverseTenantLookup = $using:ReverseTenantLookup.IsPresent NoAuthCheck = $using:NoAuthCheck.IsPresent @@ -246,6 +263,7 @@ function Get-GraphRequestList { default { try { $QueueThresholdExceeded = $false + if ($Parameters.'$count' -and !$SkipCache -and !$NoPagination) { if ($Count -gt $singleTenantThreshold) { $QueueThresholdExceeded = $true @@ -290,7 +308,7 @@ function Get-GraphRequestList { if (!$QueueThresholdExceeded) { #nextLink should ONLY be used in direct calls with manual pagination. It should not be used in queueing - if ($nextLink) { $GraphRequest.uri = $nextLink } + if ($NoPagination.IsPresent -and $nextLink -match '^https://.+') { $GraphRequest.uri = $nextLink } $GraphRequestResults = New-GraphGetRequest @GraphRequest -Caller 'Get-GraphRequestList' -ErrorAction Stop $GraphRequestResults = $GraphRequestResults | Select-Object *, @{n = 'Tenant'; e = { $TenantFilter } }, @{n = 'CippStatus'; e = { 'Good' } } @@ -313,7 +331,8 @@ function Get-GraphRequestList { } } catch { - throw $_.Exception + $Message = ('Exception at {0}:{1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + throw $Message } } } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 index a1732cbf6fd9..961df76c6ac6 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 @@ -35,26 +35,26 @@ function Invoke-CIPPOffboardingJob { Set-CIPPSignInState -TenantFilter $tenantFilter -userid $username -AccountEnabled $false -ExecutingUser $ExecutingUser -APIName $APIName } - { $_.'OnedriveAccess' -ne '' } { + { $_.'OnedriveAccess' } { $Options.OnedriveAccess | ForEach-Object { Set-CIPPSharePointPerms -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -ExecutingUser $ExecutingUser -APIName $APIName } } - { $_.'AccessNoAutomap' -ne '' } { + { $_.'AccessNoAutomap' } { $Options.AccessNoAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $false -AccessRights @('FullAccess') -ExecutingUser $ExecutingUser -APIName $APIName } } - { $_.'AccessAutomap' -ne '' } { + { $_.'AccessAutomap' } { $Options.AccessAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $true -AccessRights @('FullAccess') -ExecutingUser $ExecutingUser -APIName $APIName } } - { $_.'OOO' -ne '' } { + { $_.'OOO' } { Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -InternalMessage $Options.OOO -ExternalMessage $Options.OOO -ExecutingUser $ExecutingUser -APIName $APIName -state 'Enabled' } - { $_.'forward' -ne '' } { + { $_.'forward' } { if (!$Options.keepCopy) { - Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward -ExecutingUser $ExecutingUser -APIName $APIName + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward.value -ExecutingUser $ExecutingUser -APIName $APIName } else { $KeepCopy = [boolean]$Options.keepCopy - Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward -KeepCopy $KeepCopy -ExecutingUser $ExecutingUser -APIName $APIName + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward.value -KeepCopy $KeepCopy -ExecutingUser $ExecutingUser -APIName $APIName } } { $_.'RemoveLicenses' -eq $true } { @@ -100,6 +100,9 @@ function Invoke-CIPPOffboardingJob { "Removal of permissions queued. This task will run in the background and send it's results to the logbook." } } + { $_.'RemoveMFADevices' } { + Remove-CIPPUserMFA -UserPrincipalName $Username -TenantFilter $TenantFilter -ExecutingUser $ExecutingUser + } } return $Return diff --git a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 index cb3aaf4793ff..2b2016230ad6 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 @@ -4,28 +4,25 @@ function Invoke-CIPPStandardsRun { param( [Parameter(Mandatory = $false)] [string]$TenantFilter = 'allTenants', - [switch]$Force + [Parameter(Mandatory = $false)] + [switch]$Force, + [Parameter(Mandatory = $false)] + $TemplateID, + [Parameter(Mandatory = $false)] + $runManually = $false + ) - Write-Information "Starting process for standards - $($tenantFilter)" + Write-Host "Starting process for standards - $($tenantFilter). TemplateID: $($TemplateID) RunManually: $($runManually) Force: $($Force.IsPresent)" - $AllTasks = Get-CIPPStandards -TenantFilter $TenantFilter + $AllTasks = Get-CIPPStandards if ($Force.IsPresent) { - Write-Information 'Clearing Rerun Cache' - foreach ($Task in $AllTasks) { - $null = Test-CIPPRerun -Type Standard -Tenant $Task.Tenant -API $Task.Standard -Clear - } + Write-Host 'Clearing Rerun Cache' + Test-CIPPRerun -ClearAll -TenantFilter $TenantFilter -Type 'Standard' } - $TaskCount = ($AllTasks | Measure-Object).Count - if ($TaskCount -eq 0) { - Write-Information "No tasks found for tenant filter '$TenantFilter'" - return - } - - Write-Information "Found $TaskCount tasks for tenant filter '$TenantFilter'" #For each item in our object, run the queue. - $Queue = New-CippQueueEntry -Name "Applying Standards ($TenantFilter)" -TotalTasks $TaskCount + $Queue = New-CippQueueEntry -Name "Applying Standards ($TenantFilter)" -TotalTasks ($AllTasks | Measure-Object).Count $InputObject = [PSCustomObject]@{ OrchestratorName = 'StandardsOrchestrator' @@ -34,13 +31,15 @@ function Invoke-CIPPStandardsRun { QueueId = $Queue.RowKey StandardParams = @{ TenantFilter = $TenantFilter + runManually = $runManually } } } - - Write-Information 'Starting standards orchestrator' + if ($TemplateID) { + $InputObject.QueueFunction.StandardParams['TemplateId'] = $TemplateID + } + Write-Host "InputObject: $($InputObject | ConvertTo-Json -Depth 5 -Compress)" $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) - Write-Information "Started orchestration with ID = '$InstanceId'" + Write-Host "Started orchestration with ID = '$InstanceId'" #$Orchestrator = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId - return $InstanceId } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 index f84ed7466f45..ba2931f410b9 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 @@ -19,7 +19,7 @@ Function Invoke-RemoveCAPolicy { $policyId = $Request.Query.GUID if (!$policyId) { exit } try { - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($policyId)" -type DELETE -tenant $TenantFilter + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($policyId)" -type DELETE -tenant $TenantFilter -asapp $true Write-LogMessage -user $User -API $APINAME -message "Deleted CA Policy $policyId" -Sev 'Info' -tenant $TenantFilter $body = [pscustomobject]@{'Results' = 'Successfully deleted the policy' } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveConnectionfilterTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveConnectionfilterTemplate.ps1 new file mode 100644 index 000000000000..19526772e1e6 --- /dev/null +++ b/Modules/CIPPCore/Public/Invoke-RemoveConnectionfilterTemplate.ps1 @@ -0,0 +1,39 @@ +using namespace System.Net + +Function Invoke-RemoveConnectionfilterTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $TriggerMetadata.FunctionName + $User = $request.headers.'x-ms-client-principal' + Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + $ID = $request.body.id + try { + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'ConnectionfilterTemplate' and RowKey eq '$id'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity -Force @Table -Entity $clearRow + Write-LogMessage -user $User -API $APINAME -message "Removed Connection Filter Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully removed Connection Filter Template' } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $User -API $APINAME -message "Failed to remove Connection Filter template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + $body = [pscustomobject]@{'Results' = "Failed to remove template: $($ErrorMessage.NormalizedError)" } + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $body + }) + + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 index 84cdfc72e91c..f5d3b9b141fd 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 @@ -13,17 +13,17 @@ Function Invoke-RemoveExConnector { $APIName = $TriggerMetadata.FunctionName $User = $request.headers.'x-ms-client-principal' Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.Query.tenantfilter - + $Tenantfilter = $request.Query.tenantfilter ?? $Request.Body.tenantfilter + $Type = $Request.Query.Type ?? $Request.Body.Type try { - - $Params = @{ Identity = $request.query.GUID } - $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Remove-$($Request.query.Type)Connector" -cmdParams $params -useSystemMailbox $true - $Result = "Deleted $($Request.query.guid)" - Write-LogMessage -user $User -API $APIName -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug + $Guid = $Request.Query.GUID ?? $Request.Body.GUID + $Params = @{ Identity = $Guid } + $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet "Remove-$($Type)Connector" -cmdParams $params -useSystemMailbox $true + $Result = "Deleted $($Guid)" + Write-LogMessage -user $User -API $APIName -tenant $tenantfilter -message "Deleted transport rule $($Guid)" -sev Debug } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -user $User -API $APIName -tenant $tenantfilter -message "Failed deleting transport rule $($Request.query.guid). Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + Write-LogMessage -user $User -API $APIName -tenant $tenantfilter -message "Failed deleting transport rule $($Guid). Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage $Result = $ErrorMessage.NormalizedError } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 index 6789c97a6c4c..34100f0acb96 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 @@ -14,10 +14,10 @@ Function Invoke-RemoveExConnectorTemplate { $User = $request.headers.'x-ms-client-principal' Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ID = $request.query.id + $ID = $Request.Query.ID ?? $Request.Body.ID try { $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'ExConnectorTemplate' and RowKey eq '$id'" + $Filter = "PartitionKey eq 'ExConnectorTemplate' and RowKey eq '$ID'" $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity -Force @Table -Entity $clearRow Write-LogMessage -user $User -API $APINAME -message "Removed Exchange Connector Template with ID $ID." -Sev 'Info' diff --git a/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 index ef22fb63ce82..767f49448c3a 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 @@ -14,7 +14,7 @@ Function Invoke-RemoveQueuedApp { $User = $request.headers.'x-ms-client-principal' Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ID = $request.query.id + $ID = $request.body.id try { $Table = Get-CippTable -tablename 'apps' $Filter = "PartitionKey eq 'apps' and RowKey eq '$id'" @@ -25,7 +25,7 @@ Function Invoke-RemoveQueuedApp { } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -user $User -API $APINAME -message "Failed to remove application queue for $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = 'Failed to remove standard)' } + $body = [pscustomobject]@{'Results' = "Failed to remove item. $(Get-NormalizedError -message $_.Exception.Message)" } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 index 4b8d7fa34a41..a6ed62eeabb3 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 @@ -14,17 +14,17 @@ Function Invoke-RemoveSpamfilterTemplate { $User = $request.headers.'x-ms-client-principal' Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ID = $request.query.id + $ID = $request.body.id try { $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'SpamfilterTemplate' and RowKey eq '$id'" $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -user $User -API $APINAME -message "Removed Transport Rule Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Transport Rule Template' } + Write-LogMessage -user $User -API $APINAME -message "Removed Spamfilter Template with ID $ID." -Sev 'Info' + $body = [pscustomobject]@{'Results' = 'Successfully Spamfilter template' } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -user $User -API $APINAME -message "Failed to remove Transport Rule template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + Write-LogMessage -user $User -API $APINAME -message "Failed to remove Spam filter Rule template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage $body = [pscustomobject]@{'Results' = "Failed to remove template: $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 index 029c1c4e4284..00223f17f7c2 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 @@ -14,11 +14,10 @@ Function Invoke-RemoveStandardTemplate { $User = $request.headers.'x-ms-client-principal' Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ID = $request.body.ID + $ID = $Request.Body.ID ?? $Request.Query.ID try { $Table = Get-CippTable -tablename 'templates' - - $Filter = "PartitionKey eq 'StandardsTemplate' and RowKey eq '$id'" + $Filter = "PartitionKey eq 'StandardsTemplateV2' and RowKey eq '$id'" $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity -Force @Table -Entity $clearRow Write-LogMessage -user $User -API $APINAME -message "Removed Standards Template named $($ClearRow.name) and id $($id)" -Sev 'Info' diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 index 8db570555836..fceb370fd81b 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 @@ -11,29 +11,32 @@ Function Invoke-RemoveTransportRule { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - $User = $request.headers.'x-ms-client-principal' - Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.Query.tenantfilter + $ExecutingUser = $Request.headers.'x-ms-client-principal' + Write-LogMessage -user $ExecutingUser -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.tenantFilter ?? $Request.body.tenantFilter + $Identity = $Request.Query.guid ?? $Request.body.guid $Params = @{ - Identity = $request.query.guid + Identity = $Identity } try { $cmdlet = 'Remove-TransportRule' - $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -UseSystemMailbox $true - $Result = "Deleted $($Request.query.guid)" - Write-LogMessage -user $User -API $APIName -tenant $tenantfilter -message "Deleted transport rule $($Request.query.guid)" -sev Debug + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet $cmdlet -cmdParams $Params -UseSystemMailbox $true + $Result = "Deleted $($Identity)" + Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message "Deleted transport rule $($Identity)" -Sev Info + $StatusCode = [HttpStatusCode]::OK } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception - Write-LogMessage -user $User -API $APIName -tenant $tenantfilter -message "Failed deleting transport rule $($Request.query.guid). Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage - $Result = $ErrorMessage + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message "Failed deleting transport rule $($Identity). Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + $Result = $ErrorMessage.NormalizedError + $StatusCode = [HttpStatusCode]::Forbidden } + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } + StatusCode = $StatusCode + Body = @{ Results = $Result } }) - } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 index 997c150e47f8..1f32522ecddf 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 @@ -14,7 +14,7 @@ Function Invoke-RemoveTransportRuleTemplate { $User = $request.headers.'x-ms-client-principal' Write-LogMessage -user $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ID = $request.query.id + $ID = $request.query.id ?? $request.body.id try { $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'TransportTemplate' and RowKey eq '$id'" diff --git a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 index d161967509be..09d441fcbde9 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackup.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackup.ps1 @@ -21,10 +21,12 @@ function New-CIPPBackup { 'standards' 'SchedulerConfig' 'Extensions' + 'WebhookRules' + 'ScheduledTasks' ) $CSVfile = foreach ($CSVTable in $BackupTables) { $Table = Get-CippTable -tablename $CSVTable - Get-AzDataTableEntity @Table | Select-Object * -ExcludeProperty DomainAnalyser, table | Select-Object *, @{l = 'table'; e = { $CSVTable } } + Get-AzDataTableEntity @Table | Select-Object * -ExcludeProperty DomainAnalyser, table, Timestamp, ETag | Select-Object *, @{l = 'table'; e = { $CSVTable } } } $RowKey = 'CIPPBackup' + '_' + (Get-Date).ToString('yyyy-MM-dd-HHmm') $CSVfile diff --git a/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 b/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 index d4f399a84f3e..142958410cfd 100644 --- a/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPBackupTask.ps1 @@ -122,7 +122,7 @@ function New-CIPPBackupTask { 'CippWebhookAlerts' { Write-Host "Backup Webhook Alerts for $TenantFilter" $WebhookTable = Get-CIPPTable -TableName 'WebhookRules' - Get-CIPPAzDataTableEntity @WebhookTable | Where-Object { $TenantFilter -in ($_.Tenants | ConvertFrom-Json).fullvalue.defaultDomainName } + Get-CIPPAzDataTableEntity @WebhookTable | Where-Object { $TenantFilter -in ($_.Tenants | ConvertFrom-Json).value } } 'CippScriptedAlerts' { Write-Host "Backup Scripted Alerts for $TenantFilter" diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index e75847a094cf..10f1e81d45dc 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -58,6 +58,7 @@ function New-CIPPCAPolicy { #Remove context as it does not belong in the payload. try { $JsonObj.grantControls.PSObject.Properties.Remove('authenticationStrength@odata.context') + $JSONObj.templateId ? $JSONObj.PSObject.Properties.Remove('templateId') : $null if ($JSONObj.conditions.users.excludeGuestsOrExternalUsers.externalTenants.Members) { $JsonObj.conditions.users.excludeGuestsOrExternalUsers.externalTenants.PSObject.Properties.Remove('@odata.context') } @@ -150,6 +151,7 @@ function New-CIPPCAPolicy { $JSONObj.conditions.users.$groupType = @(Replace-GroupNameWithId -groupNames $JSONObj.conditions.users.$groupType) } } + } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to replace displayNames for conditional access rule $($JSONObj.displayName). Error: $($ErrorMessage.NormalizedError)" -sev 'Error' -LogData $ErrorMessage @@ -158,6 +160,27 @@ function New-CIPPCAPolicy { } } $JsonObj.PSObject.Properties.Remove('LocationInfo') + foreach ($condition in $JSONObj.conditions.users.PSObject.Properties.Name) { + $value = $JSONObj.conditions.users.$condition + if ($null -eq $value) { + $JSONObj.conditions.users.$condition = @() + continue + } + if ($value -is [string]) { + if ([string]::IsNullOrWhiteSpace($value)) { + $JSONObj.conditions.users.$condition = @() + continue + } + } + if ($value -is [array]) { + $nonWhitespaceItems = $value | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + if ($nonWhitespaceItems.Count -eq 0) { + $JSONObj.conditions.users.$condition = @() + continue + } + } + } + $RawJSON = ConvertTo-Json -InputObject $JSONObj -Depth 10 -Compress Write-Host $RawJSON try { diff --git a/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 index 37577fd35f72..e2cd6b6a22e8 100644 --- a/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 @@ -31,11 +31,12 @@ function New-CIPPCATemplate { if ($excludelocations) { $JSON.conditions.locations.excludeLocations = $excludelocations } if ($JSON.conditions.users.includeUsers) { $JSON.conditions.users.includeUsers = @($JSON.conditions.users.includeUsers | ForEach-Object { + $originalID = $_ if ($_ -in 'All', 'None', 'GuestOrExternalUsers') { return $_ } try { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $TenantFilter).displayName } catch { - return $_ + return $originalID } }) } @@ -43,10 +44,12 @@ function New-CIPPCATemplate { if ($JSON.conditions.users.excludeUsers) { $JSON.conditions.users.excludeUsers = @($JSON.conditions.users.excludeUsers | ForEach-Object { if ($_ -in 'All', 'None', 'GuestOrExternalUsers') { return $_ } + $originalID = $_ + try { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($_)" -tenantid $TenantFilter).displayName } catch { - return $_ + return $originalID } }) } @@ -58,21 +61,25 @@ function New-CIPPCATemplate { if ($JSON.conditions.users.includeGroups) { $JSON.conditions.users.includeGroups = @($JSON.conditions.users.includeGroups | ForEach-Object { + $originalID = $_ if ($_ -in 'All', 'None', 'GuestOrExternalUsers' -or -not (Test-IsGuid $_)) { return $_ } try { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($_)" -tenantid $TenantFilter).displayName } catch { - return $_ + return $originalID } }) } if ($JSON.conditions.users.excludeGroups) { $JSON.conditions.users.excludeGroups = @($JSON.conditions.users.excludeGroups | ForEach-Object { + $originalID = $_ + if ($_ -in 'All', 'None', 'GuestOrExternalUsers' -or -not (Test-IsGuid $_)) { return $_ } try { (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($_)" -tenantid $TenantFilter).displayName } catch { - return $_ + return $originalID + } }) } diff --git a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 index c997c6d62daf..27c1a0648046 100644 --- a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 @@ -11,11 +11,19 @@ function New-CIPPTAP { try { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/authentication/temporaryAccessPassMethods" -tenantid $TenantFilter -type POST -body '{}' -verbose Write-LogMessage -user $ExecutingUser -API $APIName -message "Created Temporary Access Password (TAP) for $userid" -Sev 'Info' -tenant $TenantFilter - return "The TAP for this user is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes" + return [pscustomobject]@{ resultText = "The TAP for this user is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes" + copyField = $($GraphRequest.temporaryAccessPass) + state = 'success' + } + } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to created TAP for $($userid): $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - Return "Failed to create TAP: $($ErrorMessage.NormalizedError)" + Return [pscustomobject]@{ resultText = "Failed to create TAP: $($ErrorMessage.NormalizedError)" + state = 'error' + } + + } } diff --git a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 index 6d00a366827f..f5db22fce712 100644 --- a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 @@ -3,7 +3,8 @@ function New-CIPPUserTask { param ( $userobj, $APIName = 'New User Task', - $ExecutingUser + $ExecutingUser, + $TenantFilter ) $Results = [System.Collections.Generic.List[string]]::new() @@ -18,33 +19,33 @@ function New-CIPPUserTask { } try { - $licenses = (($UserObj | Select-Object 'License_*').psobject.properties | Where-Object { $_.value -EQ $true }).name -replace 'License_', '' - if ($licenses) { - $LicenseResults = Set-CIPPUserLicense -userid $CreationResults.username -TenantFilter $UserObj.tenantID -Licenses $licenses + if ($userobj.licenses.value) { + $LicenseResults = Set-CIPPUserLicense -UserId $CreationResults.username -TenantFilter $UserObj.tenantFilter -AddLicenses $UserObj.licenses.value $Results.Add($LicenseResults) } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantID) -message "Failed to assign the license. Error:$($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantFilter) -message "Failed to assign the license. Error:$($_.Exception.Message)" -Sev 'Error' $body = $results.add("Failed to assign the license. $($_.Exception.Message)") } try { if ($Userobj.AddedAliases) { - $AliasResults = Add-CIPPAlias -user $CreationResults.username -Aliases ($UserObj.AddedAliases -split '\s') -UserprincipalName $CreationResults.Username -TenantFilter $UserObj.tenantID -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' + $AliasResults = Add-CIPPAlias -user $CreationResults.username -Aliases ($UserObj.AddedAliases -split '\s') -UserprincipalName $CreationResults.Username -TenantFilter $UserObj.tenantFilter -APIName $APINAME -ExecutingUser $request.headers.'x-ms-client-principal' $results.add($AliasResults) } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantID) -message "Failed to create the Aliases. Error:$($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($userobj.tenantFilter) -message "Failed to create the Aliases. Error:$($_.Exception.Message)" -Sev 'Error' $body = $results.add("Failed to create the Aliases: $($_.Exception.Message)") } - if ($userobj.CopyFrom -ne '') { - $CopyFrom = Set-CIPPCopyGroupMembers -ExecutingUser $request.headers.'x-ms-client-principal' -CopyFromId $userObj.CopyFrom -UserID $CreationResults.Username -TenantFilter $UserObj.tenantID + if ($userobj.copyFrom.value) { + Write-Host "Copying from $($userObj.copyFrom.value)" + $CopyFrom = Set-CIPPCopyGroupMembers -ExecutingUser $request.headers.'x-ms-client-principal' -CopyFromId $userObj.copyFrom.value -UserID $CreationResults.Username -TenantFilter $UserObj.tenantFilter $CopyFrom.Success | ForEach-Object { $results.Add($_) } $CopyFrom.Error | ForEach-Object { $results.Add($_) } } if ($userobj.setManager) { - $ManagerResult = Set-CIPPManager -user $CreationResults.username -Manager $userObj.setManager.value -TenantFilter $UserObj.tenantID -APIName 'Set Manager' -ExecutingUser $request.headers.'x-ms-client-principal' + $ManagerResult = Set-CIPPManager -user $CreationResults.username -Manager $userObj.setManager.value -TenantFilter $UserObj.tenantFilter -APIName 'Set Manager' -ExecutingUser $request.headers.'x-ms-client-principal' $results.add($ManagerResult) } diff --git a/Modules/CIPPCore/Public/New-CippUser.ps1 b/Modules/CIPPCore/Public/New-CippUser.ps1 index c45517f62d96..eb2632bf4363 100644 --- a/Modules/CIPPCore/Public/New-CippUser.ps1 +++ b/Modules/CIPPCore/Public/New-CippUser.ps1 @@ -9,18 +9,22 @@ function New-CIPPUser { ) try { + $userobj = $userobj | ConvertTo-Json -Depth 10 | ConvertFrom-Json -Depth 10 + Write-Host $UserObj.PrimDomain.value $Aliases = ($UserObj.AddedAliases) -split '\s' $password = if ($UserObj.password) { $UserObj.password } else { New-passwordString } - $UserprincipalName = "$($UserObj.Username)@$($UserObj.Domain)" + $UserprincipalName = "$($UserObj.Username ? $userobj.username :$userobj.mailNickname )@$($UserObj.Domain ? $UserObj.Domain : $UserObj.PrimDomain.value)" + Write-Host "Creating user $UserprincipalName" + Write-Host "tenant filter is $($UserObj.tenantFilter)" $BodyToship = [pscustomobject] @{ - 'givenName' = $UserObj.FirstName - 'surname' = $UserObj.LastName + 'givenName' = $UserObj.givenname + 'surname' = $UserObj.surname 'accountEnabled' = $true - 'displayName' = $UserObj.DisplayName + 'displayName' = $UserObj.displayName 'department' = $UserObj.Department - 'mailNickname' = $UserObj.Username + 'mailNickname' = $UserObj.Username ? $userobj.username :$userobj.mailNickname 'userPrincipalName' = $UserprincipalName - 'usageLocation' = $UserObj.usageLocation + 'usageLocation' = $UserObj.usageLocation.value ? $UserObj.usageLocation.value : $UserObj.usageLocation 'city' = $UserObj.City 'country' = $UserObj.Country 'jobtitle' = $UserObj.Jobtitle @@ -34,17 +38,16 @@ function New-CIPPUser { } } if ($userobj.businessPhone) { $bodytoShip | Add-Member -NotePropertyName businessPhones -NotePropertyValue @($UserObj.businessPhone) } - if ($UserObj.addedAttributes) { - Write-Host 'Found added attribute' - Write-Host "Added attributes: $($UserObj.addedAttributes | ConvertTo-Json)" - $UserObj.addedAttributes.GetEnumerator() | ForEach-Object { + if ($UserObj.defaultAttributes.value) { + [hashtable]($UserObj.defaultAttributes).GetEnumerator() | ForEach-Object { $results.add("Added property $($_.Key) with value $($_.value)") $bodytoShip | Add-Member -NotePropertyName $_.Key -NotePropertyValue $_.Value } } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress - $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/users' -tenantid $UserObj.tenantID -type POST -body $BodyToship -verbose - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantID) -message "Created user $($UserObj.displayname) with id $($GraphRequest.id) " -Sev 'Info' + Write-Host "Shipping: $bodyToShip" + $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/users' -tenantId $UserObj.tenantFilter -type POST -body $BodyToship -verbose + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantFilter) -message "Created user $($UserObj.displayname) with id $($GraphRequest.id) " -Sev 'Info' try { $PasswordLink = New-PwPushLink -Payload $password @@ -60,7 +63,7 @@ function New-CIPPUser { Password = $password } } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantID) -message "Failed to create user. Error:$($_.Exception.Message)" -Sev 'Error' + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantFilter) -message "Failed to create user. Error:$($_.Exception.Message)" -Sev 'Error' $results = @{ Results = ("Failed to create user. $($_.Exception.Message)" ) } throw "Failed to create user $($_.Exception.Message)" } diff --git a/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 index 31c400a79d5c..16a2dd352cda 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 @@ -47,7 +47,7 @@ function Remove-CIPPMailboxPermissions { } Anchor = $userid } - New-ExoRequest @ExoRequest + $permissions = New-ExoRequest @ExoRequest if ($permissions -notlike "*because the ACE doesn't exist on the object.*") { Write-LogMessage -user $ExecutingUser -API $APIName -message "Removed FullAccess permissions for $($AccessUser) from $($userid)'s mailbox." -Sev 'Info' -tenant $TenantFilter diff --git a/Modules/CIPPCore/Public/Remove-CIPPUserMFA.ps1 b/Modules/CIPPCore/Public/Remove-CIPPUserMFA.ps1 index 99d141ea9bc5..ede79f655f28 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPUserMFA.ps1 @@ -41,7 +41,7 @@ function Remove-CIPPUserMFA { } if (($Requests | Measure-Object).Count -eq 0) { Write-LogMessage -API 'Remove-CIPPUserMFA' -tenant $TenantFilter -message "No MFA methods found for user $UserPrincipalName" -sev 'Info' - $Results = [pscustomobject]@{'Results' = "No MFA methods found for user $($Request.Query.ID)" } + $Results = "No MFA methods found for user $($Request.Query.ID)" Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Results @@ -57,7 +57,7 @@ function Remove-CIPPUserMFA { } else { $FailedAuthMethods = (($Results | Where-Object { $_.status -ne 204 }).id -split '-')[0] -join ', ' Write-LogMessage -API 'Remove-CIPPUserMFA' -tenant $TenantFilter -message "Failed to remove MFA methods for $FailedAuthMethods" -sev 'Error' - $Results = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $FailedAuthMethods" } + $Results = "Failed to reset MFA methods for $FailedAuthMethods" } } diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index f5610cd84e63..b81d6ebf6654 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -35,15 +35,16 @@ function Send-CIPPAlert { $JSONBody = ConvertTo-Json -Compress -Depth 10 -InputObject $PowerShellBody if ($PSCmdlet.ShouldProcess($($Recipients.EmailAddress.Address -join ', '), 'Sending email')) { - New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -NoAuthCheck $true -type POST -body ($JSONBody) + $null = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -NoAuthCheck $true -type POST -body ($JSONBody) } } - Write-LogMessage -API 'Webhook Alerts' -message "Sent a webhook alert to email: $Title" -tenant $TenantFilter -sev info - + Write-LogMessage -API 'Webhook Alerts' -message "Sent an email alert: $Title" -tenant $TenantFilter -sev info + return "Sent an email alert: $Title" } catch { $ErrorMessage = Get-CippException -Exception $_ Write-Information "Could not send webhook alert to email: $($ErrorMessage.NormalizedError)" Write-LogMessage -API 'Webhook Alerts' -message "Could not send webhook alerts to email. $($ErrorMessage.NormalizedError)" -tenant $TenantFilter -sev Error -LogData $ErrorMessage + return "Could not send webhook alert to email: $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 b/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 index 7711dd0c7f26..bdc0c0cb1409 100644 --- a/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 @@ -38,8 +38,8 @@ function Set-CIPPCopyGroupMembers { '@odata.id' = $ODataBind } | ConvertTo-Json -Compress - $Success = [System.Collections.Generic.List[string]]::new() - $Errors = [System.Collections.Generic.List[string]]::new() + $Success = [System.Collections.Generic.List[object]]::new() + $Errors = [System.Collections.Generic.List[object]]::new() $Memberships = $CopyFromMemberships | Where-Object { $_.'@odata.type' -eq '#microsoft.graph.group' -and $_.groupTypes -notcontains 'DynamicMembership' -and $_.onPremisesSyncEnabled -ne $true -and $_.visibility -ne 'Public' -and $CurrentMemberships.id -notcontains $_.id } $ScheduleExchangeGroupTask = $false foreach ($MailGroup in $Memberships) { @@ -103,5 +103,5 @@ function Set-CIPPCopyGroupMembers { 'Error' = $Errors } - return $Results + return @($Results) } diff --git a/Modules/CIPPCore/Public/Set-CIPPDeviceState.ps1 b/Modules/CIPPCore/Public/Set-CIPPDeviceState.ps1 new file mode 100644 index 000000000000..f9740fb591a7 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPDeviceState.ps1 @@ -0,0 +1,79 @@ +function Set-CIPPDeviceState { + <# + .SYNOPSIS + Sets or modifies the state of a device in Microsoft Graph. + + .DESCRIPTION + This function allows you to enable, disable, or delete a device by making + corresponding requests to the Microsoft Graph API. It logs the result + and returns a success or error message based on the outcome. + + .PARAMETER Action + Specifies the action to perform on the device. Valid actions are: + - Enable: Enable the device + - Disable: Disable the device + - Delete: Remove the device from the tenant + + .PARAMETER DeviceID + Specifies the unique identifier (Object ID) of the device to be managed. + + .PARAMETER TenantFilter + Specifies the tenant ID or domain against which to perform the operation. + + .PARAMETER ExecutingUser + Specifies the user who initiated the request for logging purposes. + + .PARAMETER APIName + Specifies the name of the API call for logging purposes. Defaults to 'Set Device State'. + + .EXAMPLE + Set-CIPPDeviceState -Action Enable -DeviceID "1234abcd-5678-efgh-ijkl-9012mnopqrst" -TenantFilter "contoso.onmicrosoft.com" -ExecutingUser "admin@contoso.onmicrosoft.com" + + This command enables the specified device within the given tenant. + + .EXAMPLE + Set-CIPPDeviceState -Action Delete -DeviceID "1234abcd-5678-efgh-ijkl-9012mnopqrst" -TenantFilter "contoso.onmicrosoft.com" + + This command removes the specified device from the tenant. +#> + param ( + [Parameter(Mandatory = $true)][ValidateSet('Enable', 'Disable', 'Delete')]$Action, + + [ValidateScript({ + if ([Guid]::TryParse($_, [ref] [Guid]::Empty)) { + $true + } else { + throw 'DeviceID must be a valid GUID.' + } + })] + [Parameter(Mandatory = $true)]$DeviceID, + + [Parameter(Mandatory = $true)]$TenantFilter, + $ExecutingUser, + $APIName = 'Set Device State' + ) + $Url = "https://graph.microsoft.com/beta/devices/$($DeviceID)" + + try { + switch ($Action) { + 'Delete' { + $ActionResult = New-GraphPOSTRequest -uri $Url -type DELETE -tenantid $TenantFilter + } + 'Disable' { + $ActionResult = New-GraphPOSTRequest -uri $Url -type PATCH -tenantid $TenantFilter -body '{"accountEnabled": false }' + } + 'Enable' { + $ActionResult = New-GraphPOSTRequest -uri $Url -type PATCH -tenantid $TenantFilter -body '{"accountEnabled": true }' + } + } + Write-Host $ActionResult + Write-LogMessage -user $ExecutingUser -API $APIName -message "Executed action $($Action) on $($DeviceID)" -Sev Info + return "Executed action $($Action) on $($DeviceID)" + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $ExecutingUser -API $APIName -message "Failed to queue action $($Action) on $($DeviceID). Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + throw "Failed to queue action $($Action) on $($DeviceID). Error: $($ErrorMessage.NormalizedError)" + } + + +} diff --git a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 index 13c70a474602..be63ce724782 100644 --- a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 @@ -1,20 +1,20 @@ function Set-CIPPHideFromGAL { [CmdletBinding()] param ( - $userid, - $tenantFilter, + $UserId, + $TenantFilter, $APIName = 'Hide From Address List', [bool]$HideFromGAL, $ExecutingUser ) $Text = if ($HideFromGAL) { 'hidden' } else { 'unhidden' } try { - $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-mailbox' -cmdParams @{Identity = $userid ; HiddenFromAddressListsEnabled = $HideFromGAL } - Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $($tenantfilter) -message "$($userid) $Text from GAL" -Sev 'Info' - return "Successfully $Text $($userid) from GAL." + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $UserId ; HiddenFromAddressListsEnabled = $HideFromGAL } + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $($Tenantfilter) -message "$($UserId) $Text from GAL" -Sev Info + return "Successfully $Text $($UserId) from GAL." } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not hide $($userid) from address list. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - return "Could not hide $($userid) from address list. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not hide $($UserId) from address list. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + return "Could not hide $($UserId) from address list. Error: $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Set-CIPPIntuneTemplate.ps1 index b216c5b56672..1f0f707ee267 100644 --- a/Modules/CIPPCore/Public/Set-CIPPIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPIntuneTemplate.ps1 @@ -7,7 +7,7 @@ function Set-CIPPIntuneTemplate { $Description, $templateType ) - + Write-Host "Received $DisplayName, $Description, $RawJSON, $templateType" if (!$DisplayName) { throw 'You must enter a displayname' } if ($null -eq ($RawJSON | ConvertFrom-Json)) { throw 'the JSON is invalid' } diff --git a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 index e4d69e2c05d7..fbe745f55981 100644 --- a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 @@ -26,15 +26,24 @@ function Set-CIPPResetPassword { $password = $PasswordLink } Write-LogMessage -user $ExecutingUser -API $APIName -message "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter - - if($UserDetails.onPremisesSyncEnabled -eq $true){ - return "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password. WARNING: This user is AD synced. Please confirm passthrough or writeback is enabled." - }else{ - return "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password" + + if ($UserDetails.onPremisesSyncEnabled -eq $true) { + return [pscustomobject]@{ resultText = "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password. WARNING: This user is AD synced. Please confirm passthrough or writeback is enabled." + copyField = $password + state = 'warning' + } + } else { + return [pscustomobject]@{ resultText = "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password" + copyField = $password + state = 'success' + } } } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not reset password for $($userid). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - return "Could not reset password for $($userid). Error: $($ErrorMessage.NormalizedError)" + return [pscustomobject]@{ + resultText = "Could not reset password for $($userid). Error: $($ErrorMessage.NormalizedError)" + state = 'Error' + } } } diff --git a/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 b/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 index ad6f503215c2..743b0a53c7d2 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 @@ -22,6 +22,9 @@ function Set-CIPPSAMAdminRoles { $SAMRoles = $Roles.Roles | ConvertFrom-Json $Tenants = $Roles.Tenants | ConvertFrom-Json + if ($Tenants.value) { + $Tenants = $Tenants.value + } if (($SAMRoles | Measure-Object).count -gt 0 -and $Tenants -contains $TenantFilter -or $Tenants -contains 'AllTenants') { $AppMemberOf = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/servicePrincipals(appId='$($ENV:ApplicationID)')/memberOf/#microsoft.graph.directoryRole" -tenantid $TenantFilter -AsApp $true diff --git a/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 b/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 index 2a0a97be79a2..54f1a49222da 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSharePointPerms.ps1 @@ -1,8 +1,8 @@ function Set-CIPPSharePointPerms { [CmdletBinding()] param ( - $userid, - $OnedriveAccessUser, + $UserId, # The UPN or ID of the users OneDrive we are changing permissions on + $OnedriveAccessUser, # The UPN of the user we are adding or removing permissions for $TenantFilter, $APIName = 'Manage SharePoint Owner', $RemovePermission, @@ -17,6 +17,7 @@ function Set-CIPPSharePointPerms { try { if (!$URL) { + Write-Information 'No URL provided, getting URL from Graph' $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)/Drives" -asapp $true -tenantid $TenantFilter).WebUrl } $tenantName = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/root' -asApp $true -tenantid $TenantFilter).id.Split('.')[0] @@ -39,19 +40,19 @@ function Set-CIPPSharePointPerms { "@ $request = New-GraphPostRequest -scope "$AdminURL/.default" -tenantid $TenantFilter -Uri "$AdminURL/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' - Write-Host $($request) + # Write-Host $($request) if (!$request.ErrorInfo.ErrorMessage) { $Message = "$($OnedriveAccessUser) has been $($RemovePermission ? 'removed from' : 'given') access to $URL" - Write-LogMessage -user $ExecutingUser -API $APIName -message $Message -Sev 'Info' -tenant $TenantFilter + Write-LogMessage -user $ExecutingUser -API $APIName -message $Message -Sev Info -tenant $TenantFilter return $Message } else { $message = "Failed to change access: $($request.ErrorInfo.ErrorMessage)" - Write-LogMessage -user $ExecutingUser -API $APIName -message $message -Sev 'Info' -tenant $TenantFilter - return $message + Write-LogMessage -user $ExecutingUser -API $APIName -message $message -Sev Error -tenant $TenantFilter + throw $Message } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add new owner to $($OnedriveAccessUser) on $URL. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + Write-LogMessage -user $ExecutingUser -API $APIName -message "Could not add new owner to $($OnedriveAccessUser) on $URL. Error: $($ErrorMessage.NormalizedError)" -Sev Error -tenant $TenantFilter -LogData $ErrorMessage return "Could not add owner for $($URL). Error: $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Set-CIPPUserLicense.ps1 b/Modules/CIPPCore/Public/Set-CIPPUserLicense.ps1 index 142eed413627..029310ad772c 100644 --- a/Modules/CIPPCore/Public/Set-CIPPUserLicense.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPUserLicense.ps1 @@ -1,25 +1,39 @@ function Set-CIPPUserLicense { [CmdletBinding()] param ( - $userid, - $TenantFilter, - $Licenses + [Parameter(Mandatory)][string]$UserId, + [Parameter(Mandatory)][string]$TenantFilter, + [Parameter()][array]$AddLicenses = @(), + [Parameter()][array]$RemoveLicenses = @() ) - Write-Host "Lics are: $licences" - $LicenseBody = if ($licenses.count -ge 2) { - $liclist = foreach ($license in $Licenses) { '{"disabledPlans": [],"skuId": "' + $license + '" },' } - '{"addLicenses": [' + $LicList + '], "removeLicenses": [ ] }' - } else { - '{"addLicenses": [ {"disabledPlans": [],"skuId": "' + $licenses + '" }],"removeLicenses": [ ]}' + # Build the addLicenses array + $AddLicensesArray = foreach ($license in $AddLicenses) { + @{ + 'disabledPlans' = @() + 'skuId' = $license + } } - Write-Host $LicenseBody + + # Build the LicenseBody hashtable + $LicenseBody = @{ + 'addLicenses' = @($AddLicensesArray) + 'removeLicenses' = @($RemoveLicenses) ? @($RemoveLicenses) : @() + } + + # Convert the LicenseBody to JSON + $LicenseBodyJson = ConvertTo-Json -InputObject $LicenseBody -Depth 10 -Compress + + Write-Host "License body JSON: $LicenseBodyJson" + try { - $LicRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserId)/assignlicense" -tenantid $TenantFilter -type POST -body $LicenseBody -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$UserId/assignLicense" -tenantid $TenantFilter -type POST -body $LicenseBodyJson -Verbose } catch { - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantid) -message "Failed to assign the license. Error:$($_.Exception.Message)" -Sev 'Error' - throw "Failed to assign the license. $($_.Exception.Message)" + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $TenantFilter -message "Failed to assign the license. Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + throw "Failed to assign the license. $($ErrorMessage.NormalizedError)" } - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -tenant $($UserObj.tenantid) -message "Assigned user $($UserObj.DisplayName) license $($licences)" -Sev 'Info' - return 'Assigned licenses.' + + Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APIName -tenant $TenantFilter -message "Assigned licenses to user $UserId. Added: $AddLicenses; Removed: $RemoveLicenses" -Sev 'Info' + return 'Set licenses successfully' } diff --git a/Modules/CIPPCore/Public/Standards/ConvertTo-CippStandardObject.ps1 b/Modules/CIPPCore/Public/Standards/ConvertTo-CippStandardObject.ps1 new file mode 100644 index 000000000000..ee3e5b680072 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/ConvertTo-CippStandardObject.ps1 @@ -0,0 +1,59 @@ +function ConvertTo-CippStandardObject { + param( + [Parameter(Mandatory = $true)] + $StandardObject + ) + + # If $StandardObject is an array (like for ConditionalAccessTemplate or IntuneTemplate), + # we need to process each item individually. + if ($StandardObject -is [System.Collections.IEnumerable] -and -not ($StandardObject -is [string])) { + $ProcessedItems = New-Object System.Collections.ArrayList + foreach ($Item in $StandardObject) { + $ProcessedItems.Add((Convert-SingleStandardObject $Item)) | Out-Null + } + return [System.Collections.ArrayList]$ProcessedItems + } else { + # Single object scenario + return Convert-SingleStandardObject $StandardObject + } +} + +function Convert-SingleStandardObject { + param( + [Parameter(Mandatory = $true)] + $Obj + ) + + $Obj = [pscustomobject]$Obj + + $AllActionValues = @() + if ($Obj.PSObject.Properties.Name -contains 'combinedActions') { + $AllActionValues = $Obj.combinedActions + $null = $Obj.PSObject.Properties.Remove('combinedActions') + } elseif ($Obj.PSObject.Properties.Name -contains 'action') { + if ($Obj.action -and $Obj.action.value) { + $AllActionValues = $Obj.action.value + } + $null = $Obj.PSObject.Properties.Remove('action') + } + + # Convert actions to booleans + $Obj | Add-Member -NotePropertyName 'remediate' -NotePropertyValue ($AllActionValues -contains 'Remediate') -Force + $Obj | Add-Member -NotePropertyName 'alert' -NotePropertyValue ($AllActionValues -contains 'warn') -Force + $Obj | Add-Member -NotePropertyName 'report' -NotePropertyValue ($AllActionValues -contains 'Report') -Force + + # Flatten standards if present + if ($Obj.PSObject.Properties.Name -contains 'standards' -and $Obj.standards) { + foreach ($standardKey in $Obj.standards.PSObject.Properties.Name) { + $NestedStandard = $Obj.standards.$standardKey + if ($NestedStandard) { + foreach ($nsProp in $NestedStandard.PSObject.Properties) { + $Obj | Add-Member -NotePropertyName $nsProp.Name -NotePropertyValue $nsProp.Value -Force + } + } + } + $null = $Obj.PSObject.Properties.Remove('standards') + } + + return $Obj +} diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 4aea97d2fc9e..e69927b304d3 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -2,91 +2,158 @@ function Get-CIPPStandards { param( [Parameter(Mandatory = $false)] [string]$TenantFilter = 'allTenants', + [Parameter(Mandatory = $false)] [switch]$ListAllTenants, - [switch]$SkipGetTenants + [Parameter(Mandatory = $false)] + $TemplateId = '*', + [Parameter(Mandatory = $false)] + $runManually = $false ) - #Write-Host "Getting standards for tenant - $($tenantFilter)" - $Table = Get-CippTable -tablename 'standards' - $Filter = "PartitionKey eq 'standards'" - $Standards = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json - $StandardsAllTenants = $Standards | Where-Object { $_.Tenant -eq 'AllTenants' } - - # Get tenant list based on filter - if ($SkipGetTenants.IsPresent) { - # Debugging flag to skip Get-Tenants - $Tenants = $Standards.Tenant | Sort-Object -Unique | ForEach-Object { [pscustomobject]@{ defaultDomainName = $_ } } - } else { - $Tenants = Get-Tenants + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'StandardsTemplateV2'" + $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | ForEach-Object { + try { + $JSON = ($_).replace('"Action":', '"action":') #fix cap mistake of antique standards + ConvertFrom-Json -InputObject $JSON -ErrorAction SilentlyContinue + } catch { + } + } | Where-Object { + $_.GUID -like $TemplateId -and $_.runManually -eq $runManually } + + $AllTenantsList = Get-Tenants if ($TenantFilter -ne 'allTenants') { - $Tenants = $Tenants | Where-Object { $_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter } + $AllTenantsList = $AllTenantsList | Where-Object { + $_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter + } } if ($ListAllTenants.IsPresent) { - $ComputedStandards = @{} - foreach ($StandardName in $StandardsAllTenants.Standards.PSObject.Properties.Name) { - $CurrentStandard = $StandardsAllTenants.Standards.$StandardName - #Write-Host ($CurrentStandard | ConvertTo-Json -Depth 10) - if ($CurrentStandard.remediate -eq $true -or $CurrentStandard.alert -eq $true -or $CurrentStandard.report -eq $true) { - #Write-Host "AllTenant Standard $StandardName" - $ComputedStandards[$StandardName] = $CurrentStandard + $AllTenantsTemplates = $Templates | Where-Object { + $_.tenantFilter.value -contains 'AllTenants' + } + + $ComputedStandards = [ordered]@{} + + foreach ($Template in $AllTenantsTemplates) { + $Standards = $Template.standards + foreach ($StandardName in $Standards.PSObject.Properties.Name) { + $CurrentStandard = $Standards.$StandardName.PSObject.Copy() + $CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force + + $Actions = $CurrentStandard.action.value + if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { + if (-not $ComputedStandards.Contains($StandardName)) { + $ComputedStandards[$StandardName] = $CurrentStandard + } else { + $MergedStandard = Merge-CippStandards $ComputedStandards[$StandardName] $CurrentStandard + $MergedStandard.TemplateId = $CurrentStandard.TemplateId + $ComputedStandards[$StandardName] = $MergedStandard + } + } } } + foreach ($Standard in $ComputedStandards.Keys) { + $TempCopy = $ComputedStandards[$Standard].PSObject.Copy() + $TempCopy.PSObject.Properties.Remove('TemplateId') + + $Normalized = ConvertTo-CippStandardObject $TempCopy + [pscustomobject]@{ - Tenant = 'AllTenants' - Standard = $Standard - Settings = $ComputedStandards.$Standard + Tenant = 'AllTenants' + Standard = $Standard + Settings = $Normalized + TemplateId = $ComputedStandards[$Standard].TemplateId } } + } else { - foreach ($Tenant in $Tenants) { - #Write-Host "`r`n###### Tenant: $($Tenant.defaultDomainName)" - $StandardsTenant = $Standards | Where-Object { $_.Tenant -eq $Tenant.defaultDomainName } - - $ComputedStandards = @{} - if ($StandardsTenant.Standards.OverrideAllTenants.remediate -ne $true) { - #Write-Host 'AllTenant Standards apply to this tenant.' - foreach ($StandardName in $StandardsAllTenants.Standards.PSObject.Properties.Name) { - $CurrentStandard = $StandardsAllTenants.Standards.$StandardName.PSObject.Copy() - #Write-Host ($CurrentStandard | ConvertTo-Json -Depth 10) - if ($CurrentStandard.remediate -eq $true -or $CurrentStandard.alert -eq $true -or $CurrentStandard.report -eq $true) { - #Write-Host "AllTenant Standard $StandardName" - $ComputedStandards[$StandardName] = $CurrentStandard + foreach ($Tenant in $AllTenantsList) { + $TenantName = $Tenant.defaultDomainName + + $ApplicableTemplates = $Templates | ForEach-Object { + $template = $_ + $tenantFilterValues = $template.tenantFilter | ForEach-Object { $_.value } + $excludedTenantValues = @() + if ($template.excludedTenants) { + $excludedTenantValues = $template.excludedTenants | ForEach-Object { $_.value } + } + + $AllTenantsApplicable = $false + $TenantSpecificApplicable = $false + + if ($tenantFilterValues -contains 'AllTenants' -and (-not ($excludedTenantValues -contains $TenantName))) { + $AllTenantsApplicable = $true + } + if ($tenantFilterValues -contains $TenantName) { + $TenantSpecificApplicable = $true + } + + if ($AllTenantsApplicable -or $TenantSpecificApplicable) { + $template + } + } + + $AllTenantTemplatesSet = $ApplicableTemplates | Where-Object { + $_.tenantFilter.value -contains 'AllTenants' + } + $TenantSpecificTemplatesSet = $ApplicableTemplates | Where-Object { + $_.tenantFilter.value -notcontains 'AllTenants' + } + + $ComputedStandards = [ordered]@{} + + foreach ($Template in $AllTenantTemplatesSet) { + $Standards = $Template.standards + foreach ($StandardName in $Standards.PSObject.Properties.Name) { + $CurrentStandard = $Standards.$StandardName.PSObject.Copy() + $CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force + + $Actions = $CurrentStandard.action.value + if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { + if (-not $ComputedStandards.Contains($StandardName)) { + $ComputedStandards[$StandardName] = $CurrentStandard + } else { + $MergedStandard = Merge-CippStandards $ComputedStandards[$StandardName] $CurrentStandard + $MergedStandard.TemplateId = $CurrentStandard.TemplateId + $ComputedStandards[$StandardName] = $MergedStandard + } } } } - foreach ($StandardName in $StandardsTenant.Standards.PSObject.Properties.Name) { - if ($StandardName -eq 'OverrideAllTenants') { continue } - $CurrentStandard = $StandardsTenant.Standards.$StandardName.PSObject.Copy() + foreach ($Template in $TenantSpecificTemplatesSet) { + $Standards = $Template.standards + foreach ($StandardName in $Standards.PSObject.Properties.Name) { + $CurrentStandard = $Standards.$StandardName.PSObject.Copy() + $CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force - if ($CurrentStandard.remediate -eq $true -or $CurrentStandard.alert -eq $true -or $CurrentStandard.report -eq $true) { - # Write-Host "`r`nTenant: $StandardName" - if (!$ComputedStandards[$StandardName] ) { - #Write-Host "Applying tenant level $StandardName" - $ComputedStandards[$StandardName] = $CurrentStandard - } else { - foreach ($Setting in $CurrentStandard.PSObject.Properties.Name) { - if ($CurrentStandard.$Setting -ne $false -and ($CurrentStandard.$Setting -ne $ComputedStandards[$StandardName].$($Setting) -and ![string]::IsNullOrWhiteSpace($CurrentStandard.$Setting) -or ($null -ne $CurrentStandard.$Setting -and $null -ne $ComputedStandards[$StandardName].$($Setting) -and (Compare-Object $CurrentStandard.$Setting $ComputedStandards[$StandardName].$($Setting))))) { - #Write-Host "Overriding $Setting for $StandardName at tenant level" - if ($ComputedStandards[$StandardName].PSObject.Properties.Name -contains $Setting) { - $ComputedStandards[$StandardName].$($Setting) = $CurrentStandard.$Setting - } else { - $ComputedStandards[$StandardName] | Add-Member -NotePropertyName $Setting -NotePropertyValue $CurrentStandard.$Setting - } - } + $Actions = $CurrentStandard.action.value | Where-Object { $_ -in 'Remediate', 'warn', 'report' } + if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { + if (-not $ComputedStandards.Contains($StandardName)) { + $ComputedStandards[$StandardName] = $CurrentStandard + } else { + $MergedStandard = Merge-CippStandards $ComputedStandards[$StandardName] $CurrentStandard + $MergedStandard.TemplateId = $CurrentStandard.TemplateId + $ComputedStandards[$StandardName] = $MergedStandard } } } } foreach ($Standard in $ComputedStandards.Keys) { + $TempCopy = $ComputedStandards[$Standard].PSObject.Copy() + $TempCopy.PSObject.Properties.Remove('TemplateId') + + $Normalized = ConvertTo-CippStandardObject $TempCopy + [pscustomobject]@{ - Tenant = $Tenant.defaultDomainName - Standard = $Standard - Settings = $ComputedStandards.$Standard + Tenant = $TenantName + Standard = $Standard + Settings = $Normalized + TemplateId = $ComputedStandards[$Standard].TemplateId } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 index cd1495d5300b..ad6778144a6a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 @@ -17,7 +17,7 @@ function Invoke-CIPPStandardActivityBasedTimeout { "CIS" "spo_idle_session_timeout" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.ActivityBasedTimeout.timeout","values":[{"label":"1 Hour","value":"01:00:00"},{"label":"3 Hours","value":"03:00:00"},{"label":"6 Hours","value":"06:00:00"},{"label":"12 Hours","value":"12:00:00"},{"label":"24 Hours","value":"1.00:00:00"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.ActivityBasedTimeout.timeout","options":[{"label":"1 Hour","value":"01:00:00"},{"label":"3 Hours","value":"03:00:00"},{"label":"6 Hours","value":"06:00:00"},{"label":"12 Hours","value":"12:00:00"},{"label":"24 Hours","value":"1.00:00:00"}]} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -27,7 +27,7 @@ function Invoke-CIPPStandardActivityBasedTimeout { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index 338019dd8faf..df9c1b8c58e5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardAddDKIM { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 index b22029ba886c..1eeaae1b89fb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardAnonReportDisable { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index b57c2a2a3576..888a7fca3608 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -24,18 +24,18 @@ function Invoke-CIPPStandardAntiPhishPolicy { "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} - {"type":"boolean","label":"Show user impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarUsersSafetyTips","default":true} - {"type":"boolean","label":"Show domain impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarDomainsSafetyTips","default":true} - {"type":"boolean","label":"Show user impersonation unusual characters safety tip","name":"standards.AntiPhishPolicy.EnableUnusualCharactersSafetyTips","default":true} - {"type":"Select","label":"If the message is detected as spoof by spoof intelligence","name":"standards.AntiPhishPolicy.AuthenticationFailAction","values":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move to Junk Folder","value":"MoveToJmf"}]} - {"type":"Select","label":"Quarantine policy for Spoof","name":"standards.AntiPhishPolicy.SpoofQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} - {"type":"Select","label":"If a message is detected as user impersonation","name":"standards.AntiPhishPolicy.TargetedUserProtectionAction","values":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} - {"type":"Select","label":"Quarantine policy for user impersonation","name":"standards.AntiPhishPolicy.TargetedUserQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} - {"type":"Select","label":"If a message is detected as domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainProtectionAction","values":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} - {"type":"Select","label":"Quarantine policy for domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainQuarantineTag","values":[{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"},{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"}]} - {"type":"Select","label":"If Mailbox Intelligence detects an impersonated user","name":"standards.AntiPhishPolicy.MailboxIntelligenceProtectionAction","values":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} - {"type":"Select","label":"Apply quarantine policy","name":"standards.AntiPhishPolicy.MailboxIntelligenceQuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"switch","label":"Show first contact safety tip","name":"standards.AntiPhishPolicy.EnableFirstContactSafetyTips","default":true} + {"type":"switch","label":"Show user impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarUsersSafetyTips","default":true} + {"type":"switch","label":"Show domain impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarDomainsSafetyTips","default":true} + {"type":"switch","label":"Show user impersonation unusual characters safety tip","name":"standards.AntiPhishPolicy.EnableUnusualCharactersSafetyTips","default":true} + {"type":"select","multiple":false,"label":"If the message is detected as spoof by spoof intelligence","name":"standards.AntiPhishPolicy.AuthenticationFailAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move to Junk Folder","value":"MoveToJmf"}]} + {"type":"select","multiple":false,"label":"Quarantine policy for Spoof","name":"standards.AntiPhishPolicy.SpoofQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"label":"If a message is detected as user impersonation","name":"standards.AntiPhishPolicy.TargetedUserProtectionAction","options":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} + {"type":"select","multiple":false,"label":"Quarantine policy for user impersonation","name":"standards.AntiPhishPolicy.TargetedUserQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"select","multiple":false,"label":"If a message is detected as domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainProtectionAction","options":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} + {"type":"select","multiple":false,"label":"Quarantine policy for domain impersonation","name":"standards.AntiPhishPolicy.TargetedDomainQuarantineTag","options":[{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"},{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"}]} + {"type":"select","multiple":false,"label":"If Mailbox Intelligence detects an impersonated user","name":"standards.AntiPhishPolicy.MailboxIntelligenceProtectionAction","options":[{"label":"Move to Junk Folder","value":"MoveToJmf"},{"label":"Delete the message before its delivered","value":"Delete"},{"label":"Quarantine the message","value":"Quarantine"}]} + {"type":"select","multiple":false,"label":"Apply quarantine policy","name":"standards.AntiPhishPolicy.MailboxIntelligenceQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -45,12 +45,17 @@ function Invoke-CIPPStandardAntiPhishPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'AntiPhishPolicy' + $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant + $ServicePlans = $ServicePlans.servicePlans.servicePlanName + $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" + Write-Information "MDOLicensed: $MDOLicensed" + $PolicyList = @('CIPP Default Anti-Phishing Policy','Default Anti-Phishing Policy') $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishPolicy' | Where-Object -Property Name -In $PolicyList if ($null -eq $ExistingPolicy.Name) { @@ -69,27 +74,38 @@ function Invoke-CIPPStandardAntiPhishPolicy { $CurrentState = $ExistingPolicy | Select-Object Name, Enabled, PhishThresholdLevel, EnableMailboxIntelligence, EnableMailboxIntelligenceProtection, EnableSpoofIntelligence, EnableFirstContactSafetyTips, EnableSimilarUsersSafetyTips, EnableSimilarDomainsSafetyTips, EnableUnusualCharactersSafetyTips, EnableUnauthenticatedSender, EnableViaTag, AuthenticationFailAction, SpoofQuarantineTag, MailboxIntelligenceProtectionAction, MailboxIntelligenceQuarantineTag, TargetedUserProtectionAction, TargetedUserQuarantineTag, TargetedDomainProtectionAction, TargetedDomainQuarantineTag, EnableOrganizationDomainsProtection - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.Enabled -eq $true) -and - ($CurrentState.PhishThresholdLevel -eq $Settings.PhishThresholdLevel) -and - ($CurrentState.EnableMailboxIntelligence -eq $true) -and - ($CurrentState.EnableMailboxIntelligenceProtection -eq $true) -and - ($CurrentState.EnableSpoofIntelligence -eq $true) -and - ($CurrentState.EnableFirstContactSafetyTips -eq $Settings.EnableFirstContactSafetyTips) -and - ($CurrentState.EnableSimilarUsersSafetyTips -eq $Settings.EnableSimilarUsersSafetyTips) -and - ($CurrentState.EnableSimilarDomainsSafetyTips -eq $Settings.EnableSimilarDomainsSafetyTips) -and - ($CurrentState.EnableUnusualCharactersSafetyTips -eq $Settings.EnableUnusualCharactersSafetyTips) -and - ($CurrentState.EnableUnauthenticatedSender -eq $true) -and - ($CurrentState.EnableViaTag -eq $true) -and - ($CurrentState.AuthenticationFailAction -eq $Settings.AuthenticationFailAction) -and - ($CurrentState.SpoofQuarantineTag -eq $Settings.SpoofQuarantineTag) -and - ($CurrentState.MailboxIntelligenceProtectionAction -eq $Settings.MailboxIntelligenceProtectionAction) -and - ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) -and - ($CurrentState.TargetedUserProtectionAction -eq $Settings.TargetedUserProtectionAction) -and - ($CurrentState.TargetedUserQuarantineTag -eq $Settings.TargetedUserQuarantineTag) -and - ($CurrentState.TargetedDomainProtectionAction -eq $Settings.TargetedDomainProtectionAction) -and - ($CurrentState.TargetedDomainQuarantineTag -eq $Settings.TargetedDomainQuarantineTag) -and - ($CurrentState.EnableOrganizationDomainsProtection -eq $true) + if ($MDOLicensed) { + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.Enabled -eq $true) -and + ($CurrentState.PhishThresholdLevel -eq $Settings.PhishThresholdLevel) -and + ($CurrentState.EnableMailboxIntelligence -eq $true) -and + ($CurrentState.EnableMailboxIntelligenceProtection -eq $true) -and + ($CurrentState.EnableSpoofIntelligence -eq $true) -and + ($CurrentState.EnableFirstContactSafetyTips -eq $Settings.EnableFirstContactSafetyTips) -and + ($CurrentState.EnableSimilarUsersSafetyTips -eq $Settings.EnableSimilarUsersSafetyTips) -and + ($CurrentState.EnableSimilarDomainsSafetyTips -eq $Settings.EnableSimilarDomainsSafetyTips) -and + ($CurrentState.EnableUnusualCharactersSafetyTips -eq $Settings.EnableUnusualCharactersSafetyTips) -and + ($CurrentState.EnableUnauthenticatedSender -eq $true) -and + ($CurrentState.EnableViaTag -eq $true) -and + ($CurrentState.AuthenticationFailAction -eq $Settings.AuthenticationFailAction) -and + ($CurrentState.SpoofQuarantineTag -eq $Settings.SpoofQuarantineTag) -and + ($CurrentState.MailboxIntelligenceProtectionAction -eq $Settings.MailboxIntelligenceProtectionAction) -and + ($CurrentState.MailboxIntelligenceQuarantineTag -eq $Settings.MailboxIntelligenceQuarantineTag) -and + ($CurrentState.TargetedUserProtectionAction -eq $Settings.TargetedUserProtectionAction) -and + ($CurrentState.TargetedUserQuarantineTag -eq $Settings.TargetedUserQuarantineTag) -and + ($CurrentState.TargetedDomainProtectionAction -eq $Settings.TargetedDomainProtectionAction) -and + ($CurrentState.TargetedDomainQuarantineTag -eq $Settings.TargetedDomainQuarantineTag) -and + ($CurrentState.EnableOrganizationDomainsProtection -eq $true) + } else { + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.Enabled -eq $true) -and + ($CurrentState.EnableSpoofIntelligence -eq $true) -and + ($CurrentState.EnableFirstContactSafetyTips -eq $Settings.EnableFirstContactSafetyTips) -and + ($CurrentState.EnableUnauthenticatedSender -eq $true) -and + ($CurrentState.EnableViaTag -eq $true) -and + ($CurrentState.AuthenticationFailAction -eq $Settings.AuthenticationFailAction) -and + ($CurrentState.SpoofQuarantineTag -eq $Settings.SpoofQuarantineTag) + } $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' @@ -106,27 +122,39 @@ function Invoke-CIPPStandardAntiPhishPolicy { if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy already correctly configured' -sev Info } else { - $cmdparams = @{ - Enabled = $true - PhishThresholdLevel = $Settings.PhishThresholdLevel - EnableMailboxIntelligence = $true - EnableMailboxIntelligenceProtection = $true - EnableSpoofIntelligence = $true - EnableFirstContactSafetyTips = $Settings.EnableFirstContactSafetyTips - EnableSimilarUsersSafetyTips = $Settings.EnableSimilarUsersSafetyTips - EnableSimilarDomainsSafetyTips = $Settings.EnableSimilarDomainsSafetyTips - EnableUnusualCharactersSafetyTips = $Settings.EnableUnusualCharactersSafetyTips - EnableUnauthenticatedSender = $true - EnableViaTag = $true - AuthenticationFailAction = $Settings.AuthenticationFailAction - SpoofQuarantineTag = $Settings.SpoofQuarantineTag - MailboxIntelligenceProtectionAction = $Settings.MailboxIntelligenceProtectionAction - MailboxIntelligenceQuarantineTag = $Settings.MailboxIntelligenceQuarantineTag - TargetedUserProtectionAction = $Settings.TargetedUserProtectionAction - TargetedUserQuarantineTag = $Settings.TargetedUserQuarantineTag - TargetedDomainProtectionAction = $Settings.TargetedDomainProtectionAction - TargetedDomainQuarantineTag = $Settings.TargetedDomainQuarantineTag - EnableOrganizationDomainsProtection = $true + if ($MDOLicensed) { + $cmdparams = @{ + Enabled = $true + PhishThresholdLevel = $Settings.PhishThresholdLevel + EnableMailboxIntelligence = $true + EnableMailboxIntelligenceProtection = $true + EnableSpoofIntelligence = $true + EnableFirstContactSafetyTips = $Settings.EnableFirstContactSafetyTips + EnableSimilarUsersSafetyTips = $Settings.EnableSimilarUsersSafetyTips + EnableSimilarDomainsSafetyTips = $Settings.EnableSimilarDomainsSafetyTips + EnableUnusualCharactersSafetyTips = $Settings.EnableUnusualCharactersSafetyTips + EnableUnauthenticatedSender = $true + EnableViaTag = $true + AuthenticationFailAction = $Settings.AuthenticationFailAction + SpoofQuarantineTag = $Settings.SpoofQuarantineTag + MailboxIntelligenceProtectionAction = $Settings.MailboxIntelligenceProtectionAction + MailboxIntelligenceQuarantineTag = $Settings.MailboxIntelligenceQuarantineTag + TargetedUserProtectionAction = $Settings.TargetedUserProtectionAction + TargetedUserQuarantineTag = $Settings.TargetedUserQuarantineTag + TargetedDomainProtectionAction = $Settings.TargetedDomainProtectionAction + TargetedDomainQuarantineTag = $Settings.TargetedDomainQuarantineTag + EnableOrganizationDomainsProtection = $true + } + } else { + $cmdparams = @{ + Enabled = $true + EnableSpoofIntelligence = $true + EnableFirstContactSafetyTips = $Settings.EnableFirstContactSafetyTips + EnableUnauthenticatedSender = $true + EnableViaTag = $true + AuthenticationFailAction = $Settings.AuthenticationFailAction + SpoofQuarantineTag = $Settings.SpoofQuarantineTag + } } if ($CurrentState.Name -eq $PolicyName) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 index 8bc576d56eb1..bd9b80c3c0c3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardAppDeploy { TAG "lowimpact" ADDEDCOMPONENT - {"type":"input","name":"standards.AppDeploy.appids","label":"Application IDs, comma separated"} + {"type":"textField","name":"standards.AppDeploy.appids","label":"Application IDs, comma separated"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardAppDeploy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 index 7ed7a78334c9..510c9fdf9e08 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 @@ -7,8 +7,8 @@ function Invoke-CIPPStandardAtpPolicyForO365 { .SYNOPSIS (Label) Default Atp Policy For O365 .DESCRIPTION - (Helptext) This creates a Atp policy that enables Defender for Office 365 for Sharepoint, OneDrive and Microsoft Teams. - (DocsDescription) This creates a Atp policy that enables Defender for Office 365 for Sharepoint, OneDrive and Microsoft Teams. + (Helptext) This creates a Atp policy that enables Defender for Office 365 for SharePoint, OneDrive and Microsoft Teams. + (DocsDescription) This creates a Atp policy that enables Defender for Office 365 for SharePoint, OneDrive and Microsoft Teams. .NOTES CAT Defender Standards @@ -16,7 +16,7 @@ function Invoke-CIPPStandardAtpPolicyForO365 { "lowimpact" "CIS" ADDEDCOMPONENT - {"type":"boolean","label":"Allow people to click through Protected View even if Safe Documents identified the file as malicious","name":"standards.AtpPolicyForO365.AllowSafeDocsOpen","default":false} + {"type":"switch","label":"Allow people to click through Protected View even if Safe Documents identified the file as malicious","name":"standards.AtpPolicyForO365.AllowSafeDocsOpen","default":false,"required":false} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardAtpPolicyForO365 { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 index 86f8805e3247..3c5243f8e732 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardAuditLog { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 index e746e10799ea..a7bf50586167 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardAutoExpandArchive { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 index 77f42776c954..738ef7844b91 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardBookings { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.Bookings.state","values":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.Bookings.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardBookings { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 index 41e4616c230c..6c28b2d8baf5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 @@ -15,12 +15,12 @@ function Invoke-CIPPStandardBranding { TAG "lowimpact" ADDEDCOMPONENT - {"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":"Partial-screen background","value":"verticalSplit"}]} - {"type":"boolean","name":"standards.Branding.isHeaderShown","label":"Show header"} - {"type":"boolean","name":"standards.Branding.isFooterShown","label":"Show footer"} + {"type":"textField","name":"standards.Branding.signInPageText","label":"Sign-in page text","required":false} + {"type":"textField","name":"standards.Branding.usernameHintText","label":"Username hint Text","required":false} + {"type":"switch","name":"standards.Branding.hideAccountResetCredentials","label":"Hide self-service password reset"} + {"type":"select","multiple":false,"label":"Visual Template","name":"standards.Branding.layoutTemplateType","options":[{"label":"Full-screen background","value":"default"},{"label":"Partial-screen background","value":"verticalSplit"}]} + {"type":"switch","name":"standards.Branding.isHeaderShown","label":"Show header"} + {"type":"switch","name":"standards.Branding.isFooterShown","label":"Show footer"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -29,7 +29,7 @@ function Invoke-CIPPStandardBranding { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 index b4e94b12f969..384c50ee66e2 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardCloudMessageRecall { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.CloudMessageRecall.state","values":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.CloudMessageRecall.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardCloudMessageRecall { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 deleted file mode 100644 index 81e978febdc7..000000000000 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccess.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -function Invoke-CIPPStandardConditionalAccess { - <# - .FUNCTIONALITY - Internal - #> - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'ConditionalAccess' - - If ($Settings.remediate -eq $true) { - - $APINAME = 'Standards' - - foreach ($Template in $Settings.TemplateList) { - try { - $Table = Get-CippTable -tablename 'templates' - $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$($Template.value)'" - $JSONObj = (Get-AzDataTableEntity @Table -Filter $Filter).JSON - $null = New-CIPPCAPolicy -TenantFilter $tenant -state $request.body.NewState -RawJSON $JSONObj -Overwrite $true -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' -ReplacePattern 'displayName' - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName). Error: $ErrorMessage" -sev 'Error' - } - } - - - } -} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 new file mode 100644 index 000000000000..51182481cfa2 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 @@ -0,0 +1,51 @@ +function Invoke-CIPPStandardConditionalAccessTemplate { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) ConditionalAccessTemplate + .SYNOPSIS + (Label) Conditional Access Template + .DESCRIPTION + (Helptext) Manage conditional access policies for better security. + (DocsDescription) Manage conditional access policies for better security. + .NOTES + CAT + Templates + MULTIPLE + True + DISABLEDFEATURES + + IMPACT + High + ADDEDCOMPONENT + {"type":"autoComplete","name":"TemplateList","multiple":false,"label":"Select Conditional Access Template","api":{"url":"/api/ListCATemplates","labelField":"displayName","valueField":"GUID","queryKey":"ListCATemplates"}} + {"name":"state","label":"What state should we deploy this template in?","type":"radio","options":[{"value":"donotchange","label":"Do not change state"},{"value":"Enabled","label":"Set to enabled"},{"value":"Disabled","label":"Set to disabled"},{"value":"enabledForReportingButNotEnforced","label":"Set to report only"}]} + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/ + #> + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'ConditionalAccess' + + If ($Settings.remediate -eq $true) { + + $APINAME = 'Standards' + + foreach ($Setting in $Settings) { + try { + + $Table = Get-CippTable -tablename 'templates' + $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$($Setting.TemplateList.value)'" + $JSONObj = (Get-CippAzDataTableEntity @Table -Filter $Filter).JSON + $null = New-CIPPCAPolicy -TenantFilter $tenant -state $Setting.state -RawJSON $JSONObj -Overwrite $true -APIName $APIName -ExecutingUser $request.headers.'x-ms-client-principal' -ReplacePattern 'displayName' + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update conditional access rule $($JSONObj.displayName). Error: $ErrorMessage" -sev 'Error' + } + } + + + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 index 0a50dd6bcc86..0bb37f43d770 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 @@ -23,17 +23,28 @@ function Invoke-CIPPStandardDelegateSentItems { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) #$Rerun -Type Standard -Tenant $Tenant -API 'DelegateSentItems' -Settings $Settings + # Backwards compatibility for Pre 7.0.5 + if ([string]::IsNullOrWhiteSpace($Settings.IncludeUserMailboxes)) { + $Settings.IncludeUserMailboxes = $true + } + + if ($Settings.IncludeUserMailboxes -eq $true) { + $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{ RecipientTypeDetails = @('UserMailbox', 'SharedMailbox') } -Select 'Identity,UserPrincipalName,MessageCopyForSendOnBehalfEnabled,MessageCopyForSentAsEnabled' | + Where-Object { $_.MessageCopyForSendOnBehalfEnabled -eq $false -or $_.MessageCopyForSentAsEnabled -eq $false } + } else { + $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{ RecipientTypeDetails = @('SharedMailbox') } -Select 'Identity,UserPrincipalName,MessageCopyForSendOnBehalfEnabled,MessageCopyForSentAsEnabled' | + Where-Object { $_.MessageCopyForSendOnBehalfEnabled -eq $false -or $_.MessageCopyForSentAsEnabled -eq $false } + } + - $Mailboxes = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdParams @{ RecipientTypeDetails = @('UserMailbox', 'SharedMailbox') } | - Where-Object { $_.MessageCopyForSendOnBehalfEnabled -eq $false -or $_.MessageCopyForSentAsEnabled -eq $false } - Write-Host "Mailboxes: $($Mailboxes.count)" + Write-Host "Mailboxes: $($Mailboxes.Count)" If ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' @@ -47,34 +58,34 @@ function Invoke-CIPPStandardDelegateSentItems { } } } - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) + $BatchResults = New-ExoBulkRequest -tenantid $Tenant -cmdletArray @($Request) $BatchResults | ForEach-Object { if ($_.error) { - $ErrorMessage = Get-NormalizedError -Message $_.error - Write-Host "Failed to apply Delegate Sent Items Style to $($_.target) Error: $ErrorMessage" - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Delegate Sent Items Style to $($_.error.target) Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_.error + Write-Host "Failed to apply Delegate Sent Items Style to $($_.target) Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to apply Delegate Sent Items Style to $($_.error.target) Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } - Write-LogMessage -API 'Standards' -tenant $tenant -message "Delegate Sent Items Style applied for $($Mailboxes.count - $BatchResults.Error.Count) mailboxes" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Delegate Sent Items Style applied for $($Mailboxes.Count - $BatchResults.Error.Count) mailboxes" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Delegate Sent Items Style. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to apply Delegate Sent Items Style. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Delegate Sent Items Style already enabled.' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Delegate Sent Items Style already enabled.' -sev Info } } if ($Settings.alert -eq $true) { if ($null -eq $Mailboxes) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Delegate Sent Items Style is enabled for all mailboxes' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Delegate Sent Items Style is enabled for all mailboxes' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Delegate Sent Items Style is not enabled for $($Mailboxes.count) mailboxes" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Delegate Sent Items Style is not enabled for $($Mailboxes.Count) mailboxes" -sev Alert } } if ($Settings.report -eq $true) { $Filtered = $Mailboxes | Select-Object -Property UserPrincipalName, MessageCopyForSendOnBehalfEnabled, MessageCopyForSentAsEnabled - Add-CIPPBPAField -FieldName 'DelegateSentItems' -FieldValue $Filtered -StoreAs json -Tenant $tenant + Add-CIPPBPAField -FieldName 'DelegateSentItems' -FieldValue $Filtered -StoreAs json -Tenant $Tenant } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 index 54308b5f7a9f..0d90e2a0e4ff 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardDeletedUserRentention { TAG "lowimpact" ADDEDCOMPONENT - {"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"}]} + {"type":"select","multiple":false,"name":"standards.DeletedUserRentention.Days","label":"Retention time (Default 30 days)","options":[{"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 @@ -24,7 +24,7 @@ function Invoke-CIPPStandardDeletedUserRentention { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 index 0b6ef68a16bb..a09a7fa3daf7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"Select","label":"Add Shortcuts To OneDrive button state","name":"standards.DisableAddShortcutsToOneDrive.state","values":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"label":"Add Shortcuts To OneDrive button state","name":"standards.DisableAddShortcutsToOneDrive.state","options":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 index 8d66e0d16441..d0061c46b32d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardDisableAdditionalStorageProviders { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 index 246bc951d3f2..ac75add64456 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardDisableAppCreation { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 index 279366265065..73c9716025cf 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 @@ -7,7 +7,7 @@ function Invoke-CIPPStandardDisableBasicAuthSMTP { .SYNOPSIS (Label) Disable SMTP Basic Authentication .DESCRIPTION - (Helptext) Disables SMTP AUTH for the organization and all users. This is the default for new tenants. + (Helptext) Disables SMTP AUTH for the organization and all users. This is the default for new tenants. (DocsDescription) Disables SMTP basic authentication for the tenant and all users with it explicitly enabled. .NOTES CAT @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableBasicAuthSMTP { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 index 8dd565ff762c..1f9d537a015e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 @@ -7,8 +7,8 @@ function Invoke-CIPPStandardDisableEmail { .SYNOPSIS (Label) Disables Email as an MFA method .DESCRIPTION - (Helptext) This blocks users from using email as an MFA method. This disables the email OTP option for guest users, and instead promts them to create a Microsoft account. - (DocsDescription) This blocks users from using email as an MFA method. This disables the email OTP option for guest users, and instead promts them to create a Microsoft account. + (Helptext) This blocks users from using email as an MFA method. This disables the email OTP option for guest users, and instead prompts them to create a Microsoft account. + (DocsDescription) This blocks users from using email as an MFA method. This disables the email OTP option for guest users, and instead prompts them to create a Microsoft account. .NOTES CAT Entra (AAD) Standards @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableEmail { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) @@ -42,9 +42,9 @@ function Invoke-CIPPStandardDisableEmail { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Email authentication method is enabled' -sev Alert - } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Email authentication method is not enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Email authentication method is enabled' -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEntraPortal.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEntraPortal.ps1 new file mode 100644 index 000000000000..bc7518a04d37 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEntraPortal.ps1 @@ -0,0 +1,37 @@ +function Invoke-CIPPStandardDisableEntraPortal { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) DisableEntraPortal + .SYNOPSIS + (Label) Disables the Entra Portal for standard users + https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + #> + + param($Tenant, $Settings) + #$Rerun -Type Standard -Tenant $Tenant -API 'allowOTPTokens' -Settings $Settings + #This standard is still unlisted due to MS fixing some permissions. This will be added to the list once it is fixed. + $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/admin/entra/uxSetting' -tenantid $Tenant + + If ($Settings.remediate -eq $true) { + if ($CurrentInfo.restrictNonAdminAccess) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Disable user access to Entra Portal is already enabled.' -sev Info + } else { + New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/admin/entra/uxSetting' -tenantid $Tenant -body '{"restrictNonAdminAccess":true}' -type PATCH + } + } + + if ($Settings.alert -eq $true) { + if ($CurrentInfo.isSoftwareOathEnabled) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Disable user access to Entra Portal is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Disable user access to Entra Portal is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'DisableEntraPortal' -FieldValue $CurrentInfo.isSoftwareOathEnabled -StoreAs bool -Tenant $tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 index c8cf1818902f..f920de3c18d7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardDisableExternalCalendarSharing { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 index ed98f8f5378d..55c188bda32e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableGuestDirectory { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 index 4ef37eab9c29..32e3d2a345a4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableGuests { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 index 01dedb2141f1..ceb53907e1e0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 @@ -7,7 +7,7 @@ function Invoke-CIPPStandardDisableM365GroupUsers { .SYNOPSIS (Label) Disable M365 Group creation by users .DESCRIPTION - (Helptext) Restricts M365 group creation to certain admin roles. This disables the ability to create Teams, Sharepoint sites, Planner, etc + (Helptext) Restricts M365 group creation to certain admin roles. This disables the ability to create Teams, SharePoint sites, Planner, etc (DocsDescription) Users by default are allowed to create M365 groups. This restricts M365 group creation to certain admin roles. This disables the ability to create Teams, SharePoint sites, Planner, etc .NOTES CAT @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableM365GroupUsers { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 index d72f7dd493fb..b6507d5710e5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardDisableOutlookAddins { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 index c508ea8beea4..2c9a435131d7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardDisableReshare { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 index 30af4f6a7bfd..a948d1d13213 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableSMS { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) @@ -42,9 +42,9 @@ function Invoke-CIPPStandardDisableSMS { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'SMS authentication method is enabled' -sev Alert - } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'SMS authentication method is not enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'SMS authentication method is enabled' -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 index 4e3c6d546ff0..55fa4af4371d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableSecurityGroupUsers { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 index 331879a3b7b1..4567b9d99a72 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"input","name":"standards.DisableSelfServiceLicenses.Exclusions","label":"License Ids to exclude from this standard"} + {"type":"textField","name":"standards.DisableSelfServiceLicenses.Exclusions","label":"License Ids to exclude from this standard","required":false} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 index dda4ba27b51b..37b894544638 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardDisableSharePointLegacyAuth { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 index 5b92504f7938..7a42cc0ec788 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardDisableSharedMailbox { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 index 2b544afad213..4ad21eb72c6c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableTNEF { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param ($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 index 00b0b1380422..1a2ebea5f2f0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 @@ -7,7 +7,7 @@ function Invoke-CIPPStandardDisableTenantCreation { .SYNOPSIS (Label) Disable M365 Tenant creation by users .DESCRIPTION - (Helptext) Restricts creation of M365 tenants to the Global Administrator or Tenant Creator roles. + (Helptext) Restricts creation of M365 tenants to the Global Administrator or Tenant Creator roles. (DocsDescription) Users by default are allowed to create M365 tenants. This disables that so only admins can create new M365 tenants. .NOTES CAT @@ -25,7 +25,7 @@ function Invoke-CIPPStandardDisableTenantCreation { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 index 4b0c9b4287b9..9f2d1a96dfde 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableUserSiteCreate { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 index ed80354f77eb..c44565c5b519 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableViva { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 index e8accc7f686f..619b3e11c50b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisableVoice { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) @@ -42,9 +42,9 @@ function Invoke-CIPPStandardDisableVoice { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Voice authentication method is enabled' -sev Alert - } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Voice authentication method is not enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Voice authentication method is enabled' -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 index 3a10f191b71e..8d1d0ae0b990 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardDisablex509Certificate { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) @@ -42,9 +42,9 @@ function Invoke-CIPPStandardDisablex509Certificate { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'x509Certificate authentication method is enabled' -sev Alert - } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'x509Certificate authentication method is not enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'x509Certificate authentication method is enabled' -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 index bbfb458bab6f..8705dcd630cb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 @@ -27,7 +27,7 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 index c11dde73038f..dd64008cff74 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardEnableAppConsentRequests { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 index 666fd5f9ce27..7434e8035e07 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardEnableCustomerLockbox { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 index deee9286eaf4..8b71a8f1963a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardEnableFIDO2 { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 index 9a79fbbc3711..a55d5410612d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardEnableHardwareOAuth { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 index a9ec00f799e7..cdea9bd134b1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardEnableLitigationHold { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 index eb46db683cf9..e5211d2eda92 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 @@ -27,7 +27,7 @@ function Invoke-CIPPStandardEnableMailTips { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 index 160019c15e88..dac3185d381a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardEnableMailboxAuditing { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 index 29083290b99a..9a28cea18c9c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardEnableOnlineArchiving { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 index 915bf8ecc044..fda0d9fa90b0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardEnablePronouns { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param ($Tenant, $Settings) @@ -33,8 +33,8 @@ function Invoke-CIPPStandardEnablePronouns { try { $CurrentState = New-GraphGetRequest -Uri $Uri -tenantid $Tenant } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not get CurrentState for Pronouns. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not get CurrentState for Pronouns. Error: $($ErrorMessage.NormalizedError)" -sev Error Return } Write-Host $CurrentState diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 index dc204f253833..f28b6984c1c9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardExcludedfileExt { TAG "highimpact" ADDEDCOMPONENT - {"type":"input","name":"standards.ExcludedfileExt.ext","label":"Extensions, Comma separated"} + {"type":"textField","name":"standards.ExcludedfileExt.ext","label":"Extensions, Comma separated"} IMPACT High Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardExcludedfileExt { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 index bc133d544d89..95f28b7c2cd9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardExternalMFATrusted { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.ExternalMFATrusted.state","values":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.ExternalMFATrusted.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardExternalMFATrusted { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index e7e625e88253..adface2383c8 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardFocusedInbox { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.FocusedInbox.state","values":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.FocusedInbox.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardFocusedInbox { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 index b282c7301cd3..8b1fd25e48b3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.GlobalQuarantineNotifications.NotificationInterval","values":[{"label":"4 hours","value":"04:00:00"},{"label":"1 day/Daily","value":"1.00:00:00"},{"label":"7 days/Weekly","value":"7.00:00:00"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.GlobalQuarantineNotifications.NotificationInterval","options":[{"label":"4 hours","value":"04:00:00"},{"label":"1 day/Daily","value":"1.00:00:00"},{"label":"7 days/Weekly","value":"7.00:00:00"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param ($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 index 032aac507abc..cb20b7d7fae9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 @@ -1,7 +1,29 @@ function Invoke-CIPPStandardGroupTemplate { <# .FUNCTIONALITY - Internal + Internal + .COMPONENT + (APIName) GroupTemplate + .SYNOPSIS + (Label) Group Template + .DESCRIPTION + (Helptext) Deploy and manage group templates. + (DocsDescription) Deploy and manage group templates. + .NOTES + MULTI + True + CAT + Templates + DISABLEDFEATURES + + IMPACT + Medium + ADDEDCOMPONENT + {"type":"autoComplete","name":"groupTemplate","label":"Select Group Template","api":{"url":"/api/ListGroupTemplates","labelField":"Displayname","valueField":"GUID","queryKey":"ListGroupTemplates"}} + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/ #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'GroupTemplate' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 index dfa296eb106a..e9df84d6f574 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 @@ -5,23 +5,26 @@ function Invoke-CIPPStandardGuestInvite { .COMPONENT (APIName) GuestInvite .SYNOPSIS - (Label) Guest Invite settings + (Label) Guest Invite setting .DESCRIPTION (Helptext) This setting controls who can invite guests to your directory to collaborate on resources secured by your company, such as SharePoint sites or Azure resources. (DocsDescription) This setting controls who can invite guests to your directory to collaborate on resources secured by your company, such as SharePoint sites or Azure resources. .NOTES CAT - InTune Standards + Entra (AAD) Standards TAG - "highimpact" + "mediumimpact" ADDEDCOMPONENT + {"type":"autoComplete","multiple":false,"label":"Who can send invites?","name":"standards.GuestInvite.allowInvitesFrom","options":[{"label":"Everyone","value":"everyone"},{"label":"Admins, Guest inviters and All Members","value":"adminsGuestInvitersAndAllMembers"},{"label":"Admins and Guest inviters","value":"adminsAndGuestInviters"},{"label":"None","value":"none"}]} IMPACT - High Impact + Medium Impact + POWERSHELLEQUIVALENT + RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 index 25d4b1e8eb58..e946ef49cc4f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 @@ -5,23 +5,27 @@ function Invoke-CIPPStandardIntuneComplianceSettings { .COMPONENT (APIName) IntuneComplianceSettings .SYNOPSIS - (Label) InTune Compliance settings + (Label) Set Intune Compliance Settings .DESCRIPTION (Helptext) Sets the mark devices with no compliance policy assigned as compliance/non compliant and Compliance status validity period. (DocsDescription) Sets the mark devices with no compliance policy assigned as compliance/non compliant and Compliance status validity period. .NOTES CAT - InTune Standards + Intune Standards TAG "lowimpact" ADDEDCOMPONENT + {"type":"autoComplete","multiple":false,"name":"standards.IntuneComplianceSettings.secureByDefault","label":"Mark devices with no compliance policy as","options":[{"label":"Compliant","value":"false"},{"label":"Non-Compliant","value":"true"}]} + {"type":"number","name":"standards.IntuneComplianceSettings.deviceComplianceCheckinThresholdDays","label":"Compliance status validity period (days)"} IMPACT Low Impact + POWERSHELLEQUIVALENT + RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/intune-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index eec9dafd00db..3963933db0e4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -1,7 +1,31 @@ function Invoke-CIPPStandardIntuneTemplate { <# .FUNCTIONALITY - Internal + Internal + .COMPONENT + (APIName) IntuneTemplate + .SYNOPSIS + (Label) Intune Template + .DESCRIPTION + (Helptext) Deploy and manage Intune templates across devices. + (DocsDescription) Deploy and manage Intune templates across devices. + .NOTES + CAT + Templates + MULTIPLE + True + DISABLEDFEATURES + + IMPACT + High + ADDEDCOMPONENT + {"type":"autoComplete","multiple":false,"name":"TemplateList","label":"Select Intune Template","api":{"url":"/api/ListIntuneTemplates","labelField":"Displayname","valueField":"GUID","queryKey":"languages"}} + {"name":"AssignTo","label":"Who should this template be assigned to?","type":"radio","options":[{"label":"Do not assign","value":"On"},{"label":"Assign to all users","value":"allLicensedUsers"},{"label":"Assign to all devices","value":"AllDevices"},{"label":"Assign to all users and devices","value":"AllDevicesAndUsers"},{"label":"Assign to Custom Group","value":"customGroup"}]} + {"type":"textField","required":false,"name":"customGroup","label":"Enter the custom group name if you selected 'Assign to Custom Group'. Wildcards are allowed."} + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/ #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'intuneTemplate' @@ -20,22 +44,7 @@ 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 $Template.AssignedTo -tenantFilter $Tenant - - #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 } - if ($ExistingID) { - Set-CIPPAssignedPolicy -PolicyId $ExistingID.id -TenantFilter $tenant -GroupName $Settings.AssignTo -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 $Settings.AssignTo -Type $TemplateTypeURL - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully created Intune Template $PolicyName policy for $($Tenant)" -sev 'Info' - } - } + Set-CIPPIntunePolicy -TemplateType $Request.body.Type -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $Template.AssignTo -tenantFilter $Tenant } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 index aed46df835f2..018cc262c0ef 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardLegacyMFACleanup { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 index b161378639ce..28ad1f65a291 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 @@ -15,10 +15,10 @@ function Invoke-CIPPStandardMailContacts { TAG "lowimpact" ADDEDCOMPONENT - {"type":"input","name":"standards.MailContacts.GeneralContact","label":"General Contact"} - {"type":"input","name":"standards.MailContacts.SecurityContact","label":"Security Contact"} - {"type":"input","name":"standards.MailContacts.MarketingContact","label":"Marketing Contact"} - {"type":"input","name":"standards.MailContacts.TechContact","label":"Technical Contact"} + {"type":"textField","name":"standards.MailContacts.GeneralContact","label":"General Contact","required":false} + {"type":"textField","name":"standards.MailContacts.SecurityContact","label":"Security Contact","required":false} + {"type":"textField","name":"standards.MailContacts.MarketingContact","label":"Marketing Contact","required":false} + {"type":"textField","name":"standards.MailContacts.TechContact","label":"Technical Contact","required":false} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -27,7 +27,7 @@ function Invoke-CIPPStandardMailContacts { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index 8992d680904c..e34a7124f8e5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -19,13 +19,13 @@ function Invoke-CIPPStandardMalwareFilterPolicy { "mdo_zapphish" "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"} - {"type":"boolean","label":"Enable External Sender Admin Notifications","name":"standards.MalwareFilterPolicy.EnableExternalSenderAdminNotifications"} - {"type":"input","name":"standards.MalwareFilterPolicy.ExternalSenderAdminAddress","label":"External Sender Admin Address"} + {"type":"select","multiple":false,"label":"FileTypeAction","name":"standards.MalwareFilterPolicy.FileTypeAction","options":[{"label":"Reject","value":"Reject"},{"label":"Quarantine the message","value":"Quarantine"}]} + {"type":"textField","name":"standards.MalwareFilterPolicy.OptionalFileTypes","required":false,"label":"Optional File Types, Comma separated"} + {"type":"select","multiple":false,"label":"QuarantineTag","name":"standards.MalwareFilterPolicy.QuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"switch","label":"Enable Internal Sender Admin Notifications","required":false,"name":"standards.MalwareFilterPolicy.EnableInternalSenderAdminNotifications"} + {"type":"textField","name":"standards.MalwareFilterPolicy.InternalSenderAdminAddress","required":false,"label":"Internal Sender Admin Address"} + {"type":"switch","label":"Enable External Sender Admin Notifications","required":false,"name":"standards.MalwareFilterPolicy.EnableExternalSenderAdminNotifications"} + {"type":"textField","name":"standards.MalwareFilterPolicy.ExternalSenderAdminAddress","required":false,"label":"External Sender Admin Address"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -35,7 +35,7 @@ function Invoke-CIPPStandardMalwareFilterPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 index 0c65a52ac51c..4126811842e8 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardMessageExpiration { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index 6ff2826da936..b00f525d0fef 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardNudgeMFA { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.NudgeMFA.state","values":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.NudgeMFA.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} {"type":"number","name":"standards.NudgeMFA.snoozeDurationInDays","label":"Number of days to allow users to skip registering Authenticator (0-14, default is 1)","default":1} IMPACT Low Impact @@ -25,7 +25,7 @@ function Invoke-CIPPStandardNudgeMFA { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 index 92d7f64d612f..5df66cd46ca5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardOauthConsent { "mediumimpact" "CIS" ADDEDCOMPONENT - {"type":"input","name":"standards.OauthConsent.AllowedApps","label":"Allowed application IDs, comma separated"} + {"type":"textField","name":"standards.OauthConsent.AllowedApps","label":"Allowed application IDs, comma separated","required":false} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardOauthConsent { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($tenant, $settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 index d336e2d7528b..e43a57367058 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardOauthConsentLowSec { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 index 316fd3495bab..4c6230c0b28c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardOutBoundSpamAlert { "lowimpact" "CIS" ADDEDCOMPONENT - {"type":"input","name":"standards.OutBoundSpamAlert.OutboundSpamContact","label":"Outbound spam contact"} + {"type":"textField","name":"standards.OutBoundSpamAlert.OutboundSpamContact","label":"Outbound spam contact"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardOutBoundSpamAlert { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 index cc104b002d9a..4116d53897c6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.PWcompanionAppAllowedState.state","values":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.PWcompanionAppAllowedState.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 index a6936f2346d2..1c7005cb470f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardPWdisplayAppInformationRequiredState { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 index cf62c6c9ed55..fd6d68613ace 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardPasswordExpireDisabled { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 index e0aa9df16f0c..21a802bc079c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardPerUserMFA { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 index e07f2e3c4dcf..4cd025548e72 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 @@ -18,7 +18,7 @@ function Invoke-CIPPStandardPhishProtection { IMPACT Low Impact DISABLEDFEATURES - + POWERSHELLEQUIVALENT Portal only RECOMMENDEDBY @@ -26,7 +26,7 @@ function Invoke-CIPPStandardPhishProtection { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/global-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 new file mode 100644 index 000000000000..1c0472b3749b --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 @@ -0,0 +1,108 @@ +function Invoke-CIPPStandardProfilePhotos { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) ProfilePhotos + .SYNOPSIS + (Label) Allow users to set profile photos + .DESCRIPTION + (Helptext) Controls whether users can set their own profile photos in Microsoft 365 + (DocsDescription) Controls whether users can set their own profile photos in Microsoft 365. When disabled, only User and Global administrators can update profile photos for users. + .NOTES + CAT + Global Standards + TAG + "lowimpact" + ADDEDCOMPONENT + {"type":"select","multiple":false,"label":"Select value","name":"standards.ProfilePhotos.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + IMPACT + Low Impact + POWERSHELLEQUIVALENT + Set-OrganizationConfig -ProfilePhotoOptions EnablePhotos and Update-MgBetaAdminPeople + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + #> + + param($Tenant, $Settings) + + # Input validation + if ([string]::IsNullOrWhiteSpace($Settings.state)) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'ProfilePhotos: Invalid state parameter set' -sev Error + Return + } + + # true if wanted state is enabled, false if disabled + $DesiredState = $Settings.state -eq 'enabled' + + <# + HACK This does not work, as the API endpoint is not available via GDAP it seems? It works in the Graph Explorer, but not here. + The error is: "Authorization failed because of missing requirement(s)." + I'm keeping the code here for now, so it's much easier to re-enable if Microsoft makes it possible someday. -Bobby + #> + + # Get current Graph policy state + # $Uri = 'https://graph.microsoft.com/beta/admin/people/photoUpdateSettings' + # $CurrentGraphState = New-GraphGetRequest -uri $Uri -tenantid $Tenant + # $UsersCanChangePhotos = if (($CurrentGraphState.allowedRoles -contains 'fe930be7-5e62-47db-91af-98c3a49a38b1' -and $CurrentGraphState.allowedRoles -contains '62e90394-69f5-4237-9190-012177145e10') -or + # $null -ne $CurrentGraphState.allowedRoles) { $false } else { $true } + # $GraphStateCorrect = $UsersCanChangePhotos -eq $DesiredState + + + # Get current OWA mailbox policy state + $CurrentOWAState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OwaMailboxPolicy' -cmdParams @{Identity = 'OwaMailboxPolicy-Default' } -Select 'Identity,SetPhotoEnabled' + $OWAStateCorrect = $CurrentOWAState.SetPhotoEnabled -eq $DesiredState + # $CurrentStatesCorrect = $GraphStateCorrect -eq $true -and $OWAStateCorrect -eq $true + $CurrentStatesCorrect = $OWAStateCorrect -eq $true + + if ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' + + if ($CurrentStatesCorrect -eq $false) { + Write-Host 'Settings are not correct' + try { + if ($Settings.state -eq 'enabled') { + Write-Host 'Enabling' + # Enable photo updates + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OwaMailboxPolicy' -cmdParams @{Identity = $CurrentOWAState.Identity; SetPhotoEnabled = $true } -useSystemMailbox $true + # $null = New-GraphRequest -uri $Uri -tenant $Tenant -type DELETE + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Profile photo settings to $($Settings.state)" -sev Info + + } else { + Write-Host 'Disabling' + # Disable photo updates + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OwaMailboxPolicy' -cmdParams @{Identity = $CurrentOWAState.Identity; SetPhotoEnabled = $false } -useSystemMailbox $true + + # $body = @{ + # source = 'cloud' + # allowedRoles = @( + # 'fe930be7-5e62-47db-91af-98c3a49a38b1', # Global admin + # '62e90394-69f5-4237-9190-012177145e10' # User admin + # ) + # } + # $body = ConvertTo-Json -InputObject $body -Depth 5 -Compress + # $null = New-GraphPostRequest -uri $Uri -tenant $Tenant -body $body -type PATCH -AsApp $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Profile photo settings to $($Settings.state)" -sev Info + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set profile photo settings to $($Settings.state). Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } else { + Write-Host 'Settings are correct' + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings are already set to the desired state: $($Settings.state)" -sev Info + } + } + + if ($Settings.alert -eq $true) { + if ($CurrentStatesCorrect -eq $false) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings do not match desired state: $($Settings.state)" -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings match desired state: $($Settings.state)" -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'ProfilePhotos' -FieldValue $CurrentStatesCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 index 9dba79606f3f..3040ef1f155e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardQuarantineRequestAlert { TAG "lowimpact" ADDEDCOMPONENT - {"type":"input","name":"standards.QuarantineRequestAlert.NotifyUser","label":"E-mail to receive the alert"} + {"type":"textField","name":"standards.QuarantineRequestAlert.NotifyUser","label":"E-mail to receive the alert"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardQuarantineRequestAlert { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact #> param ($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 index e5e04e8e136a..47776ea2f17f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardRotateDKIM { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 index 0531386edce1..bd016f0f9ba8 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardSPAzureB2B { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 index e27cc33a94ee..c9f44c0c8a21 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardSPDirectSharing { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 index b499216b3bf6..7ee1f747340b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardSPDisableLegacyWorkflows { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDisableLegacyWorkflows' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 index 383f77ae20d0..76e9a1682200 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardSPDisallowInfectedFiles { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 index ded1d34833c5..05b078a5e62e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardSPEmailAttestation { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 index 6957bee42020..02589cf0c61e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 @@ -26,7 +26,7 @@ function Invoke-CIPPStandardSPExternalUserExpiration { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 index 11029ff97972..4b54a8b44ad3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardSPSyncButtonState { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"Select","label":"SharePoint Sync Button state","name":"standards.SPSyncButtonState.state","values":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"label":"SharePoint Sync Button state","name":"standards.SPSyncButtonState.state","options":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardSPSyncButtonState { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index 3142d6bee41c..a35f420cf73f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -19,10 +19,10 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { "mdo_commonattachmentsfilter" "mdo_safeattachmentpolicy" ADDEDCOMPONENT - {"type":"Select","label":"Action","name":"standards.SafeAttachmentPolicy.Action","values":[{"label":"Allow","value":"Allow"},{"label":"Block","value":"Block"},{"label":"DynamicDelivery","value":"DynamicDelivery"}]} - {"type":"Select","label":"QuarantineTag","name":"standards.SafeAttachmentPolicy.QuarantineTag","values":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} - {"type":"boolean","label":"Redirect","name":"standards.SafeAttachmentPolicy.Redirect"} - {"type":"input","name":"standards.SafeAttachmentPolicy.RedirectAddress","label":"Redirect Address"} + {"type":"select","multiple":false,"label":"Action","name":"standards.SafeAttachmentPolicy.Action","options":[{"label":"Allow","value":"Allow"},{"label":"Block","value":"Block"},{"label":"DynamicDelivery","value":"DynamicDelivery"}]} + {"type":"select","multiple":false,"label":"QuarantineTag","name":"standards.SafeAttachmentPolicy.QuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"switch","label":"Redirect","name":"standards.SafeAttachmentPolicy.Redirect"} + {"type":"textField","name":"standards.SafeAttachmentPolicy.RedirectAddress","label":"Redirect Address","required":false} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -32,122 +32,139 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SafeAttachmentPolicy' - $PolicyList = @('CIPP Default Safe Attachment Policy','Default Safe Attachment Policy') - $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentPolicy' | Where-Object -Property Name -In $PolicyList - if ($null -eq $ExistingPolicy.Name) { - $PolicyName = $PolicyList[0] - } else { - $PolicyName = $ExistingPolicy.Name - } - $RuleList = @( 'CIPP Default Safe Attachment Rule','CIPP Default Safe Attachment Policy') - $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | Where-Object -Property Name -In $RuleList - if ($null -eq $ExistingRule.Name) { - $RuleName = $RuleList[0] - } else { - $RuleName = $ExistingRule.Name - } + $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant + $ServicePlans = $ServicePlans.servicePlans.servicePlanName + $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentPolicy' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object Name, Enable, Action, QuarantineTag, Redirect, RedirectAddress + if ($MDOLicensed) { + $PolicyList = @('CIPP Default Safe Attachment Policy','Default Safe Attachment Policy') + $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentPolicy' | Where-Object -Property Name -In $PolicyList + if ($null -eq $ExistingPolicy.Name) { + $PolicyName = $PolicyList[0] + } else { + $PolicyName = $ExistingPolicy.Name + } + $RuleList = @( 'CIPP Default Safe Attachment Rule','CIPP Default Safe Attachment Policy') + $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | Where-Object -Property Name -In $RuleList + if ($null -eq $ExistingRule.Name) { + $RuleName = $RuleList[0] + } else { + $RuleName = $ExistingRule.Name + } - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.Enable -eq $true) -and - ($CurrentState.Action -eq $Settings.Action) -and - ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and - ($CurrentState.Redirect -eq $Settings.Redirect) -and - (($null -eq $Settings.RedirectAddress) -or ($CurrentState.RedirectAddress -eq $Settings.RedirectAddress)) + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentPolicy' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object Name, Enable, Action, QuarantineTag, Redirect, RedirectAddress - $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.Enable -eq $true) -and + ($CurrentState.Action -eq $Settings.Action) -and + ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and + ($CurrentState.Redirect -eq $Settings.Redirect) -and + (($null -eq $Settings.RedirectAddress) -or ($CurrentState.RedirectAddress -eq $Settings.RedirectAddress)) - $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | - Where-Object -Property Name -EQ $RuleName | - Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' - $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and - ($RuleState.SafeAttachmentPolicy -eq $PolicyName) -and - ($RuleState.Priority -eq 0) -and - (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | + Where-Object -Property Name -EQ $RuleName | + Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs - if ($Settings.remediate -eq $true) { + $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and + ($RuleState.SafeAttachmentPolicy -eq $PolicyName) -and + ($RuleState.Priority -eq 0) -and + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy already correctly configured' -sev Info - } else { - $cmdparams = @{ - Enable = $true - Action = $Settings.Action - QuarantineTag = $Settings.QuarantineTag - Redirect = $Settings.Redirect - RedirectAddress = $Settings.RedirectAddress - } + if ($Settings.remediate -eq $true) { - if ($CurrentState.Name -eq $PolicyName) { - try { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeAttachmentPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Safe Attachment policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Safe Attachment policy $PolicyName." -sev Error -LogData $_ - } + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy already correctly configured' -sev Info } else { - try { - $cmdparams.Add('Name', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeAttachmentPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Safe Attachment policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Safe Attachment policy $PolicyName." -sev Error -LogData $_ + $cmdparams = @{ + Enable = $true + Action = $Settings.Action + QuarantineTag = $Settings.QuarantineTag + Redirect = $Settings.Redirect + RedirectAddress = $Settings.RedirectAddress } - } - } - if ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name + if ($CurrentState.Name -eq $PolicyName) { + try { + $cmdparams.Add('Identity', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeAttachmentPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Safe Attachment policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Safe Attachment policy $PolicyName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeAttachmentPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Safe Attachment policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Safe Attachment policy $PolicyName." -sev Error -LogData $_ + } + } } - if ($RuleState.SafeAttachmentPolicy -ne $PolicyName) { - $cmdparams.Add('SafeAttachmentPolicy', $PolicyName) - } + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } - if ($RuleState.Name -eq $RuleName) { - try { - $cmdparams.Add('Identity', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeAttachmentRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Safe Attachment rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Safe Attachment rule $RuleName." -sev Error -LogData $_ + if ($RuleState.SafeAttachmentPolicy -ne $PolicyName) { + $cmdparams.Add('SafeAttachmentPolicy', $PolicyName) } - } else { - try { - $cmdparams.Add('Name', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeAttachmentRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Safe Attachment rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Safe Attachment rule $RuleName." -sev Error -LogData $_ + + if ($RuleState.Name -eq $RuleName) { + try { + $cmdparams.Add('Identity', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeAttachmentRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Safe Attachment rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Safe Attachment rule $RuleName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeAttachmentRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Safe Attachment rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Safe Attachment rule $RuleName." -sev Error -LogData $_ + } } } } - } - if ($Settings.alert -eq $true) { + if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy is not enabled' -sev Alert + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy is not enabled' -sev Alert + } } - } - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SafeAttachmentPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SafeAttachmentPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + } else { + if ($Settings.remediate -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Safe Attachment policy: Tenant does not have Microsoft Defender for Office 365 license" -sev Error + } + if ($Settings.alert -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Safe Attachment Policy is not enabled: Tenant does not have Microsoft Defender for Office 365 license' -sev Alert + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SafeAttachmentPolicy' -FieldValue $false -StoreAs bool -Tenant $tenant + } + } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 index e8639f10ce49..b9b9823cf47c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -18,9 +18,9 @@ function Invoke-CIPPStandardSafeLinksPolicy { "mdo_safelinksforemail" "mdo_safelinksforOfficeApps" ADDEDCOMPONENT - {"type":"boolean","label":"AllowClickThrough","name":"standards.SafeLinksPolicy.AllowClickThrough"} - {"type":"boolean","label":"DisableUrlRewrite","name":"standards.SafeLinksPolicy.DisableUrlRewrite"} - {"type":"boolean","label":"EnableOrganizationBranding","name":"standards.SafeLinksPolicy.EnableOrganizationBranding"} + {"type":"switch","label":"AllowClickThrough","name":"standards.SafeLinksPolicy.AllowClickThrough"} + {"type":"switch","label":"DisableUrlRewrite","name":"standards.SafeLinksPolicy.DisableUrlRewrite"} + {"type":"switch","label":"EnableOrganizationBranding","name":"standards.SafeLinksPolicy.EnableOrganizationBranding"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -30,132 +30,149 @@ function Invoke-CIPPStandardSafeLinksPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SafeLinksPolicy' - $PolicyList = @('CIPP Default SafeLinks Policy','Default SafeLinks Policy') - $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksPolicy' | Where-Object -Property Name -In $PolicyList - if ($null -eq $ExistingPolicy.Name) { - $PolicyName = $PolicyList[0] - } else { - $PolicyName = $ExistingPolicy.Name - } - $RuleList = @( 'CIPP Default SafeLinks Rule','CIPP Default SafeLinks Policy') - $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksRule' | Where-Object -Property Name -In $RuleList - if ($null -eq $ExistingRule.Name) { - $RuleName = $RuleList[0] - } else { - $RuleName = $ExistingRule.Name - } + $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant + $ServicePlans = $ServicePlans.servicePlans.servicePlanName + $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksPolicy' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object Name, EnableSafeLinksForEmail, EnableSafeLinksForTeams, EnableSafeLinksForOffice, TrackClicks, AllowClickThrough, ScanUrls, EnableForInternalSenders, DeliverMessageAfterScan, DisableUrlRewrite, EnableOrganizationBranding - - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.EnableSafeLinksForEmail -eq $true) -and - ($CurrentState.EnableSafeLinksForTeams -eq $true) -and - ($CurrentState.EnableSafeLinksForOffice -eq $true) -and - ($CurrentState.TrackClicks -eq $true) -and - ($CurrentState.ScanUrls -eq $true) -and - ($CurrentState.EnableForInternalSenders -eq $true) -and - ($CurrentState.DeliverMessageAfterScan -eq $true) -and - ($CurrentState.AllowClickThrough -eq $Settings.AllowClickThrough) -and - ($CurrentState.DisableUrlRewrite -eq $Settings.DisableUrlRewrite) -and - ($CurrentState.EnableOrganizationBranding -eq $Settings.EnableOrganizationBranding) - - $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' - - $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksRule' | - Where-Object -Property Name -EQ $RuleName | - Select-Object Name, SafeLinksPolicy, Priority, RecipientDomainIs - - $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and - ($RuleState.SafeLinksPolicy -eq $PolicyName) -and - ($RuleState.Priority -eq 0) -and - (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) - - if ($Settings.remediate -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy already correctly configured' -sev Info + if ($MDOLicensed) { + $PolicyList = @('CIPP Default SafeLinks Policy','Default SafeLinks Policy') + $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksPolicy' | Where-Object -Property Name -In $PolicyList + if ($null -eq $ExistingPolicy.Name) { + $PolicyName = $PolicyList[0] } else { - $cmdparams = @{ - EnableSafeLinksForEmail = $true - EnableSafeLinksForTeams = $true - EnableSafeLinksForOffice = $true - TrackClicks = $true - ScanUrls = $true - EnableForInternalSenders = $true - DeliverMessageAfterScan = $true - AllowClickThrough = $Settings.AllowClickThrough - DisableUrlRewrite = $Settings.DisableUrlRewrite - EnableOrganizationBranding = $Settings.EnableOrganizationBranding - } + $PolicyName = $ExistingPolicy.Name + } + $RuleList = @( 'CIPP Default SafeLinks Rule','CIPP Default SafeLinks Policy') + $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksRule' | Where-Object -Property Name -In $RuleList + if ($null -eq $ExistingRule.Name) { + $RuleName = $RuleList[0] + } else { + $RuleName = $ExistingRule.Name + } - if ($CurrentState.Name -eq $Policyname) { - try { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeLinksPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated SafeLink policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update SafeLink policy $PolicyName." -sev Error -LogData $_ - } + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksPolicy' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object Name, EnableSafeLinksForEmail, EnableSafeLinksForTeams, EnableSafeLinksForOffice, TrackClicks, AllowClickThrough, ScanUrls, EnableForInternalSenders, DeliverMessageAfterScan, DisableUrlRewrite, EnableOrganizationBranding + + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.EnableSafeLinksForEmail -eq $true) -and + ($CurrentState.EnableSafeLinksForTeams -eq $true) -and + ($CurrentState.EnableSafeLinksForOffice -eq $true) -and + ($CurrentState.TrackClicks -eq $true) -and + ($CurrentState.ScanUrls -eq $true) -and + ($CurrentState.EnableForInternalSenders -eq $true) -and + ($CurrentState.DeliverMessageAfterScan -eq $true) -and + ($CurrentState.AllowClickThrough -eq $Settings.AllowClickThrough) -and + ($CurrentState.DisableUrlRewrite -eq $Settings.DisableUrlRewrite) -and + ($CurrentState.EnableOrganizationBranding -eq $Settings.EnableOrganizationBranding) + + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeLinksRule' | + Where-Object -Property Name -EQ $RuleName | + Select-Object Name, SafeLinksPolicy, Priority, RecipientDomainIs + + $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and + ($RuleState.SafeLinksPolicy -eq $PolicyName) -and + ($RuleState.Priority -eq 0) -and + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + + if ($Settings.remediate -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy already correctly configured' -sev Info } else { - try { - $cmdparams.Add('Name', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeLinksPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created SafeLink policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink policy $PolicyName." -sev Error -LogData $_ + $cmdparams = @{ + EnableSafeLinksForEmail = $true + EnableSafeLinksForTeams = $true + EnableSafeLinksForOffice = $true + TrackClicks = $true + ScanUrls = $true + EnableForInternalSenders = $true + DeliverMessageAfterScan = $true + AllowClickThrough = $Settings.AllowClickThrough + DisableUrlRewrite = $Settings.DisableUrlRewrite + EnableOrganizationBranding = $Settings.EnableOrganizationBranding } - } - } - if ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name + if ($CurrentState.Name -eq $Policyname) { + try { + $cmdparams.Add('Identity', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeLinksPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated SafeLink policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update SafeLink policy $PolicyName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeLinksPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created SafeLink policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink policy $PolicyName." -sev Error -LogData $_ + } + } } - if ($RuleState.SafeLinksPolicy -ne $PolicyName) { - $cmdparams.Add('SafeLinksPolicy', $PolicyName) - } + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } - if ($RuleState.Name -eq $RuleName) { - try { - $cmdparams.Add('Identity', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeLinksRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated SafeLink rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update SafeLink rule $RuleName." -sev Error -LogData $_ + if ($RuleState.SafeLinksPolicy -ne $PolicyName) { + $cmdparams.Add('SafeLinksPolicy', $PolicyName) } - } else { - try { - $cmdparams.Add('Name', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeLinksRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created SafeLink rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink rule $RuleName." -sev Error -LogData $_ + + if ($RuleState.Name -eq $RuleName) { + try { + $cmdparams.Add('Identity', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-SafeLinksRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated SafeLink rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update SafeLink rule $RuleName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-SafeLinksRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created SafeLink rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink rule $RuleName." -sev Error -LogData $_ + } } } } - } - if ($Settings.alert -eq $true) { + if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy is not enabled' -sev Alert + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy is not enabled' -sev Alert + } } - } - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SafeLinksPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SafeLinksPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + } else { + if ($Settings.remediate -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create SafeLink policy: Tenant does not have Microsoft Defender for Office 365 license" -sev Error + } + if ($Settings.alert -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SafeLink Policy is not enabled: Tenant does not have Microsoft Defender for Office 365 license' -sev Alert + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SafeLinksPolicy' -FieldValue $false -StoreAs bool -Tenant $tenant + } + } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 index fd70ad3b2f77..283bc4d5a267 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardSafeSendersDisable { "mediumimpact" ADDEDCOMPONENT DISABLEDFEATURES - + IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -25,7 +25,7 @@ function Invoke-CIPPStandardSafeSendersDisable { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 index 916e42043fa7..3a43c05d0222 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardSecurityDefaults { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 index 051d46d2a0cb..4084650d240e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardSendFromAlias { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 index a0997a9869da..a2ce48171f59 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardSendReceiveLimitTenant { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 index fdd67d8dbfa1..c1469596a27e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardShortenMeetings { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.ShortenMeetings.ShortenEventScopeDefault","values":[{"label":"Disabled/None","value":"None"},{"label":"End early","value":"EndEarly"},{"label":"Start late","value":"StartLate"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.ShortenMeetings.ShortenEventScopeDefault","options":[{"label":"Disabled/None","value":"None"},{"label":"End early","value":"EndEarly"},{"label":"Start late","value":"StartLate"}]} {"type":"number","name":"standards.ShortenMeetings.DefaultMinutesToReduceShortEventsBy","label":"Minutes to reduce short calendar events by (Default is 5)","default":5} {"type":"number","name":"standards.ShortenMeetings.DefaultMinutesToReduceLongEventsBy","label":"Minutes to reduce long calendar events by (Default is 10)","default":10} IMPACT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardShortenMeetings { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index b4de133595e8..4e4bd537aa5e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -16,15 +16,15 @@ function Invoke-CIPPStandardSpamFilterPolicy { "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":"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"}]} + {"type":"autoComplete","multiple":false,"label":"Spam Action","name":"standards.SpamFilterPolicy.SpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"autoComplete","multiple":false,"label":"Spam Quarantine Tag","name":"standards.SpamFilterPolicy.SpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","multiple":false,"label":"High Confidence Spam Action","name":"standards.SpamFilterPolicy.HighConfidenceSpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"autoComplete","multiple":false,"label":"High Confidence Spam Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidenceSpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","multiple":false,"label":"Bulk Spam Action","name":"standards.SpamFilterPolicy.BulkSpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"autoComplete","multiple":false,"label":"Bulk Quarantine Tag","name":"standards.SpamFilterPolicy.BulkQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","multiple":false,"label":"Phish Spam Action","name":"standards.SpamFilterPolicy.PhishSpamAction","options":[{"label":"Quarantine the message","value":"Quarantine"},{"label":"Move message to Junk Email folder","value":"MoveToJmf"}]} + {"type":"autoComplete","multiple":false,"label":"Phish Quarantine Tag","name":"standards.SpamFilterPolicy.PhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","multiple":false,"label":"High Confidence Phish Quarantine Tag","name":"standards.SpamFilterPolicy.HighConfidencePhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -33,7 +33,7 @@ function Invoke-CIPPStandardSpamFilterPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index b8487b3d5889..a9ba02025ac7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 @@ -16,7 +16,7 @@ function Invoke-CIPPStandardSpoofWarn { "lowimpact" "CIS" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.SpoofWarn.state","values":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.SpoofWarn.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardSpoofWarn { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 new file mode 100644 index 000000000000..fbb236903975 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 @@ -0,0 +1,75 @@ +function Invoke-CIPPStandardStaleEntraDevices { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) StaleEntraDevices + .SYNOPSIS + (Label) Cleanup stale Entra devices + .DESCRIPTION + (Helptext) Cleans up Entra devices that have not connected/signed in for the specified number of days. + (DocsDescription) Cleans up Entra devices that have not connected/signed in for the specified number of days. First disables and later deletes the devices. More info can be found in the [Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/devices/manage-stale-devices) + .NOTES + CAT + Entra (AAD) Standards + TAG + "highimpact" + "CIS" + ADDEDCOMPONENT + {"type":"number","name":"standards.StaleEntraDevices.deviceAgeThreshold","label":"Days before stale(Dont set below 30)"} + DISABLEDFEATURES + + IMPACT + High Impact + POWERSHELLEQUIVALENT + Remove-MgDevice, Update-MgDevice or Graph API + RECOMMENDEDBY + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact + #> + + param($Tenant, $Settings) + + # Get all Entra devices + $AllDevices = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/devices' -tenantid $Tenant | Where-Object { $null -ne $_.approximateLastSignInDateTime } + $Date = (Get-Date).AddDays( - [int]$Settings.deviceAgeThreshold) + $StaleDevices = $AllDevices | Where-Object { $_.approximateLastSignInDateTime -lt $Date } + + If ($Settings.remediate -eq $true) { + + Write-Host 'Remediation not implemented yet' + # TODO: Implement remediation. For others in the future that want to try this: + # Good MS guide on what to watch out for https://learn.microsoft.com/en-us/entra/identity/devices/manage-stale-devices#clean-up-stale-devices + # https://learn.microsoft.com/en-us/graph/api/device-list?view=graph-rest-beta&tabs=http + # Properties to look at: + # approximateLastSignInDateTime: For knowing when the device last signed in + # enrollmentProfileName and operatingSystem: For knowing if it's an AutoPilot device + # managementType or isManaged: For knowing if it's an Intune managed device. If it is, should be removed from Intune also. Stale intune standard could prossibly be used for this. + # profileType: For knowing if it's only registered or also managed + # accountEnabled: For knowing if the device is disabled or not + + } + + + if ($Settings.alert -eq $true) { + + if ($StaleDevices.Count -gt 0) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "$($StaleDevices.Count) Stale devices found" -sev Alert + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'No stale devices found' -sev Info + } + } + + + if ($Settings.report -eq $true) { + + if ($StaleDevices.Count -gt 0) { + $StaleReport = ConvertTo-Json -InputObject ($StaleDevices | Select-Object -Property displayName, id, approximateLastSignInDateTime, accountEnabled, enrollmentProfileName, operatingSystem, managementType, profileType) -Depth 10 -Compress + Add-CIPPBPAField -FieldName 'StaleEntraDevices' -FieldValue $StaleReport -StoreAs json -Tenant $Tenant + } else { + Add-CIPPBPAField -FieldName 'StaleEntraDevices' -FieldValue $true -StoreAs bool -Tenant $Tenant + } + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 index 744102a249dc..925916f948e8 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 @@ -7,7 +7,7 @@ function Invoke-CIPPStandardTAP { .SYNOPSIS (Label) Enable Temporary Access Passwords .DESCRIPTION - (Helptext) Enables TAP and sets the default TAP lifetime to 1 hour. This configuration also allows you to select is a TAP is single use or multi-logon. + (Helptext) Enables TAP and sets the default TAP lifetime to 1 hour. This configuration also allows you to select if a TAP is single use or multi-logon. (DocsDescription) Enables Temporary Password generation for the tenant. .NOTES CAT @@ -15,7 +15,7 @@ function Invoke-CIPPStandardTAP { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select TAP Lifetime","name":"standards.TAP.config","values":[{"label":"Only Once","value":"true"},{"label":"Multiple Logons","value":"false"}]} + {"type":"select","multiple":false,"label":"Select TAP Lifetime","name":"standards.TAP.config","options":[{"label":"Only Once","value":"true"},{"label":"Multiple Logons","value":"false"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,26 +24,21 @@ function Invoke-CIPPStandardTAP { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TAP' $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/TemporaryAccessPass' -tenantid $Tenant + if ($null -eq $Settings.config) { $Settings.config = $True } $StateIsCorrect = ($CurrentState.state -eq 'enabled') -and - ($CurrentState.isUsableOnce -eq $Settings.config) + ([System.Convert]::ToBoolean($CurrentState.isUsableOnce) -eq [System.Convert]::ToBoolean($Settings.config)) if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'TemporaryAccessPass' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } - # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.config) -or $Settings.config -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'TAP: Invalid state parameter set' -sev Error - Return - } - If ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Temporary Access Passwords is already enabled.' -sev Info diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 index 0d80dcc1947f..d5a1a5db6b41 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 @@ -15,7 +15,7 @@ Function Invoke-CIPPStandardTeamsEmailIntegration { TAG "lowimpact" ADDEDCOMPONENT - {"type":"boolean","name":"standards.TeamsEmailIntegration.AllowEmailIntoChannel","label":"Allow channel emails"} + {"type":"switch","name":"standards.TeamsEmailIntegration.AllowEmailIntoChannel","label":"Allow channel emails"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -25,7 +25,7 @@ Function Invoke-CIPPStandardTeamsEmailIntegration { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 index adcf29f0fde1..64e4ad948181 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 @@ -2,6 +2,29 @@ Function Invoke-CIPPStandardTeamsEnrollUser { <# .FUNCTIONALITY Internal + .COMPONENT + (APIName) TeamsEnrollUser + .SYNOPSIS + (Label) Default voice and face enrollment + .DESCRIPTION + (Helptext) Controls whether users with this policy can set the voice profile capture and enrollment through the Recognition tab in their Teams client settings. + (DocsDescription) Controls whether users with this policy can set the voice profile capture and enrollment through the Recognition tab in their Teams client settings. + .NOTES + CAT + Teams Standards + TAG + "lowimpact" + ADDEDCOMPONENT + {"type":"autoComplete","name":"standards.TeamsEnrollUser.EnrollUserOverride","label":"Voice and Face Enrollment","options":[{"label":"Disabled","value":"Disabled"},{"label":"Enabled","value":"Enabled"}]} + IMPACT + Low Impact + POWERSHELLEQUIVALENT + Set-CsTeamsMeetingPolicy -Identity Global -EnrollUserOverride \$false + RECOMMENDEDBY + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 index 195addd804f4..3c79a6fd30be 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 @@ -15,9 +15,9 @@ Function Invoke-CIPPStandardTeamsExternalAccessPolicy { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"boolean","name":"standards.TeamsExternalAccessPolicy.EnableFederationAccess","label":"Allow communication from trusted organizations"} - {"type":"boolean","name":"standards.TeamsExternalAccessPolicy.EnablePublicCloudAccess","label":"Allow user to communicate with Skype users"} - {"type":"boolean","name":"standards.TeamsExternalAccessPolicy.EnableTeamsConsumerAccess","label":"Allow communication with unmanaged Teams accounts"} + {"type":"switch","name":"standards.TeamsExternalAccessPolicy.EnableFederationAccess","label":"Allow communication from trusted organizations"} + {"type":"switch","name":"standards.TeamsExternalAccessPolicy.EnablePublicCloudAccess","label":"Allow user to communicate with Skype users"} + {"type":"switch","name":"standards.TeamsExternalAccessPolicy.EnableTeamsConsumerAccess","label":"Allow communication with unmanaged Teams accounts"} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ Function Invoke-CIPPStandardTeamsExternalAccessPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 index dc21121c0e3f..1fc934983092 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 @@ -15,11 +15,11 @@ Function Invoke-CIPPStandardTeamsExternalFileSharing { TAG "lowimpact" ADDEDCOMPONENT - {"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"} + {"type":"switch","name":"standards.TeamsExternalFileSharing.AllowGoogleDrive","label":"Allow Google Drive"} + {"type":"switch","name":"standards.TeamsExternalFileSharing.AllowShareFile","label":"Allow ShareFile"} + {"type":"switch","name":"standards.TeamsExternalFileSharing.AllowBox","label":"Allow Box"} + {"type":"switch","name":"standards.TeamsExternalFileSharing.AllowDropBox","label":"Allow Dropbox"} + {"type":"switch","name":"standards.TeamsExternalFileSharing.AllowEgnyte","label":"Allow Egnyte"} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -29,7 +29,7 @@ Function Invoke-CIPPStandardTeamsExternalFileSharing { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 index 13a4705338c3..930bff06c4db 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 @@ -15,10 +15,10 @@ Function Invoke-CIPPStandardTeamsFederationConfiguration { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"boolean","name":"standards.TeamsFederationConfiguration.AllowTeamsConsumer","label":"Allow users to communicate with other organizations"} - {"type":"boolean","name":"standards.TeamsFederationConfiguration.AllowPublicUsers","label":"Allow users to communicate with Skype Users"} - {"type":"Select","name":"standards.TeamsFederationConfiguration.DomainControl","label":"Communication Mode","values":[{"label":"Allow all external domains","value":"AllowAllExternal"},{"label":"Block all external domains","value":"BlockAllExternal"},{"label":"Allow specific external domains","value":"AllowSpecificExternal"},{"label":"Block specific external domains","value":"BlockSpecificExternal"}]} - {"type":"input","name":"standards.TeamsFederationConfiguration.DomainList","label":"Domains, Comma separated"} + {"type":"switch","name":"standards.TeamsFederationConfiguration.AllowTeamsConsumer","label":"Allow users to communicate with other organizations"} + {"type":"switch","name":"standards.TeamsFederationConfiguration.AllowPublicUsers","label":"Allow users to communicate with Skype Users"} + {"type":"autoComplete","multiple":false,"name":"standards.TeamsFederationConfiguration.DomainControl","label":"Communication Mode","options":[{"label":"Allow all external domains","value":"AllowAllExternal"},{"label":"Block all external domains","value":"BlockAllExternal"},{"label":"Allow specific external domains","value":"AllowSpecificExternal"},{"label":"Block specific external domains","value":"BlockSpecificExternal"}]} + {"type":"textField","name":"standards.TeamsFederationConfiguration.DomainList","label":"Domains, Comma separated","required":false} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -27,7 +27,7 @@ Function Invoke-CIPPStandardTeamsFederationConfiguration { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 index 4357b39bcb88..5827f007b0f1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 @@ -15,7 +15,9 @@ Function Invoke-CIPPStandardTeamsGlobalMeetingPolicy { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","name":"standards.TeamsGlobalMeetingPolicy.DesignatedPresenterRoleMode","label":"Default value of the `Who can present?`","values":[{"label":"EveryoneUserOverride","value":"EveryoneUserOverride"},{"label":"EveryoneInCompanyUserOverride","value":"EveryoneInCompanyUserOverride"},{"label":"EveryoneInSameAndFederatedCompanyUserOverride","value":"EveryoneInSameAndFederatedCompanyUserOverride"},{"label":"OrganizerOnlyUserOverride","value":"OrganizerOnlyUserOverride"}]} + {"type":"autoComplete","multiple":false,"name":"standards.TeamsGlobalMeetingPolicy.DesignatedPresenterRoleMode","label":"Default value of the `Who can present?`","options":[{"label":"EveryoneUserOverride","value":"EveryoneUserOverride"},{"label":"EveryoneInCompanyUserOverride","value":"EveryoneInCompanyUserOverride"},{"label":"EveryoneInSameAndFederatedCompanyUserOverride","value":"EveryoneInSameAndFederatedCompanyUserOverride"},{"label":"OrganizerOnlyUserOverride","value":"OrganizerOnlyUserOverride"}]} + {"type":"switch","name":"standards.TeamsGlobalMeetingPolicy.AllowAnonymousUsersToJoinMeeting","label":"Allow anonymous users to join meeting"} + {"type":"autoComplete","multiple":false,"name":"standards.TeamsGlobalMeetingPolicy.MeetingChatEnabledType","label":"Meeting chat policy","options":[{"label":"On for everyone","value":"Enabled"},{"label":"On for everyone but anonymous users","value":"EnabledExceptAnonymous"},{"label":"Off for everyone","value":"Disabled"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -25,7 +27,7 @@ Function Invoke-CIPPStandardTeamsGlobalMeetingPolicy { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#low-impact #> ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsGlobalMeetingPolicy' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 93a2a288845b..6c14e3df7ebf 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -15,7 +15,7 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { TAG "lowimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.TeamsMeetingsByDefault.state","values":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"select","multiple":false,"label":"Select value","name":"standards.TeamsMeetingsByDefault.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -24,7 +24,7 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 new file mode 100644 index 000000000000..cb0a7c4d796b --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 @@ -0,0 +1,100 @@ +Function Invoke-CIPPStandardTeamsMessagingPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsMessagingPolicy + .SYNOPSIS + (Label) Global Messaging Policy for Microsoft Teams + .DESCRIPTION + (Helptext) Sets the properties of the Global messaging policy. + (DocsDescription) Sets the properties of the Global messaging policy. Messaging policies control which chat and channel messaging features are available to users in Teams. + .NOTES + CAT + Teams Standards + TAG + "mediumimpact" + ADDEDCOMPONENT + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowOwnerDeleteMessage","label":"Allow Owner to Delete Messages","default":false} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowUserDeleteMessage","label":"Allow User to Delete Messages","default":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowUserEditMessage","label":"Allow User to Edit Messages","default":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowUserDeleteChat","label":"Allow User to Delete Chats","default":true} + {"type":"autoComplete","multiple":false,"name":"standards.TeamsMessagingPolicy.ReadReceiptsEnabledType","label":"Read Receipts Enabled Type","options":[{"label":"User controlled","value":"UserPreference"},{"label":"Turned on for everyone","value":"Everyone"},{"label":"Turned off for everyone","value":"None"}]} + {"type":"switch","name":"standards.TeamsMessagingPolicy.CreateCustomEmojis","label":"Allow Creating Custom Emojis","default":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.DeleteCustomEmojis","label":"Allow Deleting Custom Emojis","default":false} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowSecurityEndUserReporting","label":"Allow reporting message as security concern","default":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowCommunicationComplianceEndUserReporting","label":"Allow reporting message as inappropriate content","default":true} + IMPACT + Medium Impact + POWERSHELLEQUIVALENT + Set-CsTeamsMessagingPolicy + RECOMMENDEDBY + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/teams-standards#medium-impact + #> + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsMessagingPolicy' + + param($Tenant, $Settings) + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsMessagingPolicy' -CmdParams @{Identity = 'Global' } + + if ($null -eq $Settings.AllowOwnerDeleteMessage) { $Settings.AllowOwnerDeleteMessage = $CurrentState.AllowOwnerDeleteMessage } + if ($null -eq $Settings.AllowUserDeleteMessage) { $Settings.AllowUserDeleteMessage = $CurrentState.AllowUserDeleteMessage } + if ($null -eq $Settings.AllowUserEditMessage) { $Settings.AllowUserEditMessage = $CurrentState.AllowUserEditMessage } + if ($null -eq $Settings.AllowUserDeleteChat) { $Settings.AllowUserDeleteChat = $CurrentState.AllowUserDeleteChat } + if ($null -eq $Settings.ReadReceiptsEnabledType) { $Settings.ReadReceiptsEnabledType = $CurrentState.ReadReceiptsEnabledType } + if ($null -eq $Settings.CreateCustomEmojis) { $Settings.CreateCustomEmojis = $CurrentState.CreateCustomEmojis } + if ($null -eq $Settings.DeleteCustomEmojis) { $Settings.DeleteCustomEmojis = $CurrentState.DeleteCustomEmojis } + if ($null -eq $Settings.AllowSecurityEndUserReporting) { $Settings.AllowSecurityEndUserReporting = $CurrentState.AllowSecurityEndUserReporting } + if ($null -eq $Settings.AllowCommunicationComplianceEndUserReporting) { $Settings.AllowCommunicationComplianceEndUserReporting = $CurrentState.AllowCommunicationComplianceEndUserReporting } + + $StateIsCorrect = ($CurrentState.AllowOwnerDeleteMessage -eq $Settings.AllowOwnerDeleteMessage) -and + ($CurrentState.AllowUserDeleteMessage -eq $Settings.AllowUserDeleteMessage) -and + ($CurrentState.AllowUserEditMessage -eq $Settings.AllowUserEditMessage) -and + ($CurrentState.AllowUserDeleteChat -eq $Settings.AllowUserDeleteChat) -and + ($CurrentState.ReadReceiptsEnabledType -eq $Settings.ReadReceiptsEnabledType) -and + ($CurrentState.CreateCustomEmojis -eq $Settings.CreateCustomEmojis) -and + ($CurrentState.DeleteCustomEmojis -eq $Settings.DeleteCustomEmojis) -and + ($CurrentState.AllowSecurityEndUserReporting -eq $Settings.AllowSecurityEndUserReporting) -and + ($CurrentState.AllowCommunicationComplianceEndUserReporting -eq $Settings.AllowCommunicationComplianceEndUserReporting) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Global Teams Messaging policy already configured.' -sev Info + } else { + $cmdparams = @{ + Identity = 'Global' + AllowOwnerDeleteMessage = $Settings.AllowOwnerDeleteMessage + AllowUserDeleteMessage = $Settings.AllowUserDeleteMessage + AllowUserEditMessage = $Settings.AllowUserEditMessage + AllowUserDeleteChat = $Settings.AllowUserDeleteChat + ReadReceiptsEnabledType = $Settings.ReadReceiptsEnabledType + CreateCustomEmojis = $Settings.CreateCustomEmojis + DeleteCustomEmojis = $Settings.DeleteCustomEmojis + AllowSecurityEndUserReporting = $Settings.AllowSecurityEndUserReporting + AllowCommunicationComplianceEndUserReporting = $Settings.AllowCommunicationComplianceEndUserReporting + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsMessagingPolicy' -CmdParams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated global Teams messaging policy' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to configure global Teams messaging policy." -sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Global Teams messaging policy is configured correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Global Teams messaging policy is not configured correctly.' -sev Alert + } + } + + if ($Setings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TeamsMessagingPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 index cbc223e26374..73b7d7e97614 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 @@ -24,7 +24,7 @@ function Invoke-CIPPStandardTenantDefaultTimezone { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 index 9586aeb3cd6d..0b2a2096aa89 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 @@ -1,7 +1,27 @@ function Invoke-CIPPStandardTransportRuleTemplate { <# .FUNCTIONALITY - Internal + Internal + .COMPONENT + (APIName) TransportRuleTemplate + .SYNOPSIS + (Label) Transport Rule Template + .DESCRIPTION + (Helptext) Deploy transport rules to manage email flow. + (DocsDescription) Deploy transport rules to manage email flow. + .NOTES + CAT + Templates + DISABLEDFEATURES + + IMPACT + Medium + ADDEDCOMPONENT + {"type":"autoComplete","name":"transportRuleTemplate","label":"Select Transport Rule Template","api":{"url":"/api/ListTransportRulesTemplates","labelField":"name","valueField":"GUID","queryKey":"ListTransportRulesTemplates"}} + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/ #> param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TransportRuleTemplate' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 index 5548e1f0b6c5..333de3e01992 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardUndoOauth { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index 985d040aab8e..265d37507f8b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -15,8 +15,8 @@ function Invoke-CIPPStandardUserSubmissions { TAG "mediumimpact" ADDEDCOMPONENT - {"type":"Select","label":"Select value","name":"standards.UserSubmissions.state","values":[{"label":"Enabled","value":"enable"},{"label":"Disabled","value":"disable"}]} - {"type":"input","name":"standards.UserSubmissions.email","label":"Destination email address"} + {"type":"select","multiple":false,"label":"Select value","name":"standards.UserSubmissions.state","options":[{"label":"Enabled","value":"enable"},{"label":"Disabled","value":"disable"}]} + {"type":"textField","name":"standards.UserSubmissions.email","required":false,"label":"Destination email address"} IMPACT Medium Impact POWERSHELLEQUIVALENT @@ -25,7 +25,7 @@ function Invoke-CIPPStandardUserSubmissions { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 index 15bd3658b861..6035ca8d04dc 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardallowOAuthTokens { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 index 7f5d0a442113..9b9441b9e951 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardallowOTPTokens { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 index a67b9132dedb..cbb3e14e1329 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 @@ -15,9 +15,9 @@ function Invoke-CIPPStandardcalDefault { TAG "lowimpact" DISABLEDFEATURES - + ADDEDCOMPONENT - {"type":"Select","label":"Select Sharing Level","name":"standards.calDefault.permissionlevel","values":[{"label":"Owner - The user can create, read, edit, and delete all items in the folder, and create subfolders. The user is both folder owner and folder contact.","value":"Owner"},{"label":"Publishing Editor - The user can create, read, edit, and delete all items in the folder, and create subfolders.","value":"PublishingEditor"},{"label":"Editor - The user can create items in the folder. The contents of the folder do not appear.","value":"Editor"},{"label":"Publishing Author. The user can read, create all items/subfolders. Can modify and delete only items they create.","value":"PublishingAuthor"},{"label":"Author - The user can create and read items, and modify and delete items that they create.","value":"Author"},{"label":"Non Editing Author - The user has full read access and create items. Can can delete only own items.","value":"NonEditingAuthor"},{"label":"Reviewer - The user can read all items in the folder.","value":"Reviewer"},{"label":"Contributor - The user can create items and folders.","value":"Contributor"},{"label":"Availability Only - Indicates that the user can view only free/busy time within the calendar.","value":"AvailabilityOnly"},{"label":"Limited Details - The user can view free/busy time within the calendar and the subject and location of appointments.","value":"LimitedDetails"},{"label":"None - The user has no permissions on the folder.","value":"none"}]} + {"type":"select","multiple":false,"label":"Select Sharing Level","name":"standards.calDefault.permissionlevel","options":[{"label":"Owner - The user can create, read, edit, and delete all items in the folder, and create subfolders. The user is both folder owner and folder contact.","value":"Owner"},{"label":"Publishing Editor - The user can create, read, edit, and delete all items in the folder, and create subfolders.","value":"PublishingEditor"},{"label":"Editor - The user can create items in the folder. The contents of the folder do not appear.","value":"Editor"},{"label":"Publishing Author. The user can read, create all items/subfolders. Can modify and delete only items they create.","value":"PublishingAuthor"},{"label":"Author - The user can create and read items, and modify and delete items that they create.","value":"Author"},{"label":"Non Editing Author - The user has full read access and create items. Can can delete only own items.","value":"NonEditingAuthor"},{"label":"Reviewer - The user can read all items in the folder.","value":"Reviewer"},{"label":"Contributor - The user can create items and folders.","value":"Contributor"},{"label":"Availability Only - Indicates that the user can view only free/busy time within the calendar.","value":"AvailabilityOnly"},{"label":"Limited Details - The user can view free/busy time within the calendar and the subject and location of appointments.","value":"LimitedDetails"},{"label":"None - The user has no permissions on the folder.","value":"none"}]} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -26,13 +26,14 @@ function Invoke-CIPPStandardcalDefault { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/exchange-standards#low-impact #> param($Tenant, $Settings, $QueueItem) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'calDefault' # Input validation + $Settings.permissionlevel = $Settings.permissionlevel.value ? $Settings.permissionlevel.value : $Settings.permissionlevel if ([string]::IsNullOrWhiteSpace($Settings.permissionlevel) -or $Settings.permissionlevel -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'calDefault: Invalid permissionlevel parameter set' -sev Error Return @@ -63,44 +64,44 @@ function Invoke-CIPPStandardcalDefault { $Mailbox = $_ try { New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MailboxFolderStatistics' -cmdParams @{identity = $Mailbox.UserPrincipalName; FolderScope = 'Calendar' } -Anchor $Mailbox.UserPrincipalName | Where-Object { $_.FolderType -eq 'Calendar' } | - ForEach-Object { - try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MailboxFolderPermission' -cmdparams @{Identity = "$($Mailbox.UserPrincipalName):$($_.FolderId)"; User = 'Default'; AccessRights = $Settings.permissionlevel } -Anchor $Mailbox.UserPrincipalName - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName):\$($_.Name) to $($Settings.permissionlevel)" -sev Debug - $SuccessCounter++ - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-Host "Setting cal failed: $ErrorMessage" - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $ErrorMessage" -sev Error + ForEach-Object { + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MailboxFolderPermission' -cmdparams @{Identity = "$($Mailbox.UserPrincipalName):$($_.FolderId)"; User = 'Default'; AccessRights = $Settings.permissionlevel } -Anchor $Mailbox.UserPrincipalName + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName):\$($_.Name) to $($Settings.permissionlevel)" -sev Debug + $SuccessCounter++ + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-Host "Setting cal failed: $ErrorMessage" + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $ErrorMessage" -sev Error + } } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $ErrorMessage" -sev Error } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $ErrorMessage" -sev Error - } - $processedMailboxes++ - if ($processedMailboxes % 25 -eq 0) { - $LastRun = @{ - RowKey = 'calDefaults' - PartitionKey = $Tenant - totalMailboxes = $TotalMailboxes - processedMailboxes = $processedMailboxes - currentSuccessCount = $SuccessCounter + $processedMailboxes++ + if ($processedMailboxes % 25 -eq 0) { + $LastRun = @{ + RowKey = 'calDefaults' + PartitionKey = $Tenant + totalMailboxes = $TotalMailboxes + processedMailboxes = $processedMailboxes + currentSuccessCount = $SuccessCounter + } + Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force + Write-Host "Processed $processedMailboxes mailboxes" } - Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force - Write-Host "Processed $processedMailboxes mailboxes" } - } - $LastRun = @{ - RowKey = 'calDefaults' - PartitionKey = $Tenant - totalMailboxes = $TotalMailboxes - processedMailboxes = $processedMailboxes - currentSuccessCount = $SuccessCounter - } - Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force + $LastRun = @{ + RowKey = 'calDefaults' + PartitionKey = $Tenant + totalMailboxes = $TotalMailboxes + processedMailboxes = $processedMailboxes + currentSuccessCount = $SuccessCounter + } + Add-CIPPAzDataTableEntity @LastRunTable -Entity $LastRun -Force - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully set default calendar permissions for $SuccessCounter out of $TotalMailboxes mailboxes." -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully set default calendar permissions for $SuccessCounter out of $TotalMailboxes mailboxes." -sev Info + } } -} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 index aeb24bbe8d7a..dc6b2184a4d5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandarddisableMacSync { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 index c4e9be0222af..420f3c11498f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 @@ -15,16 +15,16 @@ function Invoke-CIPPStandardintuneBrandingProfile { TAG "lowimpact" ADDEDCOMPONENT - {"type":"input","name":"standards.intuneBrandingProfile.displayName","label":"Organization name"} - {"type":"boolean","name":"standards.intuneBrandingProfile.showLogo","label":"Show logo"} - {"type":"boolean","name":"standards.intuneBrandingProfile.showDisplayNameNextToLogo","label":"Show organization name next to logo"} - {"type":"input","name":"standards.intuneBrandingProfile.contactITName","label":"Contact IT name"} - {"type":"input","name":"standards.intuneBrandingProfile.contactITPhoneNumber","label":"Contact IT phone number"} - {"type":"input","name":"standards.intuneBrandingProfile.contactITEmailAddress","label":"Contact IT email address"} - {"type":"input","name":"standards.intuneBrandingProfile.contactITNotes","label":"Contact IT notes"} - {"type":"input","name":"standards.intuneBrandingProfile.onlineSupportSiteName","label":"Online support site name"} - {"type":"input","name":"standards.intuneBrandingProfile.onlineSupportSiteUrl","label":"Online support site URL"} - {"type":"input","name":"standards.intuneBrandingProfile.privacyUrl","label":"Privacy statement URL"} + {"type":"textField","name":"standards.intuneBrandingProfile.displayName","label":"Organization name","required":false} + {"type":"switch","name":"standards.intuneBrandingProfile.showLogo","label":"Show logo"} + {"type":"switch","name":"standards.intuneBrandingProfile.showDisplayNameNextToLogo","label":"Show organization name next to logo","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.contactITName","label":"Contact IT name","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.contactITPhoneNumber","label":"Contact IT phone number","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.contactITEmailAddress","label":"Contact IT email address","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.contactITNotes","label":"Contact IT notes","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.onlineSupportSiteName","label":"Online support site name","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.onlineSupportSiteUrl","label":"Online support site URL","required":false} + {"type":"textField","name":"standards.intuneBrandingProfile.privacyUrl","label":"Privacy statement URL","required":false} IMPACT Low Impact POWERSHELLEQUIVALENT @@ -33,7 +33,7 @@ function Invoke-CIPPStandardintuneBrandingProfile { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/intune-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 index beb6174fbdcc..f6840bafc092 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 @@ -24,7 +24,7 @@ function Invoke-CIPPStandardintuneDeviceReg { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/intune-standards#medium-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 index 6e8792d71df7..3cab0708f09d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 @@ -24,7 +24,7 @@ function Invoke-CIPPStandardintuneDeviceRetirementDays { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/intune-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 index dfce677e2bc3..9939dd0005c6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 @@ -22,7 +22,7 @@ function Invoke-CIPPStandardintuneRequireMFA { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/intune-standards#medium-impact #> param($Tenant, $Settings) @@ -36,8 +36,8 @@ function Invoke-CIPPStandardintuneRequireMFA { } else { try { $NewSetting = $PreviousSetting - $NewSetting.multiFactorAuthConfiguration = '1' - $Newbody = ConvertTo-Json -Compress -InputObject $NewSetting + $NewSetting.multiFactorAuthConfiguration = 'required' + $Newbody = ConvertTo-Json -Compress -InputObject $NewSetting -Depth 10 New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/deviceRegistrationPolicy' -Type PUT -Body $NewBody -ContentType 'application/json' Write-LogMessage -API 'Standards' -tenant $tenant -message 'Set required to use MFA when joining/registering Entra Devices' -sev Info } catch { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 index 307e631cd868..da89f92a6795 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardlaps { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/entra-aad-standards#low-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index a8c962b2f0a0..277263b94e61 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -5,10 +5,10 @@ function Invoke-CIPPStandardsharingCapability { .COMPONENT (APIName) sharingCapability .SYNOPSIS - (Label) Set Sharing Level for OneDrive and Sharepoint + (Label) Set Sharing Level for OneDrive and SharePoint .DESCRIPTION - (Helptext) Sets the default sharing level for OneDrive and Sharepoint. This is a tenant wide setting and overrules any settings set on the site level - (DocsDescription) Sets the default sharing level for OneDrive and Sharepoint. This is a tenant wide setting and overrules any settings set on the site level + (Helptext) Sets the default sharing level for OneDrive and SharePoint. This is a tenant wide setting and overrules any settings set on the site level + (DocsDescription) Sets the default sharing level for OneDrive and SharePoint. This is a tenant wide setting and overrules any settings set on the site level .NOTES CAT SharePoint Standards @@ -16,7 +16,7 @@ function Invoke-CIPPStandardsharingCapability { "highimpact" "CIS" ADDEDCOMPONENT - {"type":"Select","label":"Select Sharing Level","name":"standards.sharingCapability.Level","values":[{"label":"Users can share only with people in the organization. No external sharing is allowed.","value":"disabled"},{"label":"Users can share with new and existing guests. Guests must sign in or provide a verification code.","value":"externalUserSharingOnly"},{"label":"Users can share with anyone by using links that do not require sign-in.","value":"externalUserAndGuestSharing"},{"label":"Users can share with existing guests (those already in the directory of the organization).","value":"existingExternalUserSharingOnly"}]} + {"type":"select","multiple":false,"label":"Select Sharing Level","name":"standards.sharingCapability.Level","options":[{"label":"Users can share only with people in the organization. No external sharing is allowed.","value":"disabled"},{"label":"Users can share with new and existing guests. Guests must sign in or provide a verification code.","value":"externalUserSharingOnly"},{"label":"Users can share with anyone by using links that do not require sign-in.","value":"externalUserAndGuestSharing"},{"label":"Users can share with existing guests (those already in the directory of the organization).","value":"existingExternalUserSharingOnly"}]} IMPACT High Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardsharingCapability { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 index 9ea89a31897b..098b0ef3e17e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 @@ -16,8 +16,8 @@ function Invoke-CIPPStandardsharingDomainRestriction { "highimpact" "CIS" ADDEDCOMPONENT - {"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"} + {"type":"select","multiple":false,"name":"standards.sharingDomainRestriction.Mode","label":"Limit external sharing by domains","options":[{"label":"Off","value":"none"},{"label":"Restrict sharing to specific domains","value":"allowList"},{"label":"Block sharing to specific domains","value":"blockList"}]} + {"type":"textField","name":"standards.sharingDomainRestriction.Domains","label":"Domains to allow/block, comma separated","required":false} IMPACT High Impact POWERSHELLEQUIVALENT @@ -26,7 +26,7 @@ function Invoke-CIPPStandardsharingDomainRestriction { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 index 4e2ad5693119..416af1a6ded7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 @@ -23,7 +23,7 @@ function Invoke-CIPPStandardunmanagedSync { UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK - https://docs.cipp.app/user-documentation/tenant/standards/edit-standards + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#high-impact #> param($Tenant, $Settings) diff --git a/Modules/CIPPCore/Public/Standards/Merge-CippStandards.ps1 b/Modules/CIPPCore/Public/Standards/Merge-CippStandards.ps1 new file mode 100644 index 000000000000..abd8f21ab319 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Merge-CippStandards.ps1 @@ -0,0 +1,34 @@ + +function Merge-CippStandards { + param( + [Parameter(Mandatory = $true)] $Existing, + [Parameter(Mandatory = $true)] $CurrentStandard + ) + $Existing = [pscustomobject]$Existing + $CurrentStandard = [pscustomobject]$CurrentStandard + $ExistingActionValues = @() + if ($Existing.PSObject.Properties.Name -contains 'action') { + if ($Existing.action -and $Existing.action.value) { + $ExistingActionValues = @($Existing.action.value) + } + $null = $Existing.PSObject.Properties.Remove('action') + } + + $CurrentActionValues = @() + if ($CurrentStandard.PSObject.Properties.Name -contains 'action') { + if ($CurrentStandard.action -and $CurrentStandard.action.value) { + $CurrentActionValues = @($CurrentStandard.action.value) + } + $null = $CurrentStandard.PSObject.Properties.Remove('action') + } + $AllActionValues = ($ExistingActionValues + $CurrentActionValues) | Select-Object -Unique + foreach ($prop in $CurrentStandard.PSObject.Properties) { + if ($prop.Name -eq 'action') { continue } + $Existing | Add-Member -NotePropertyName $prop.Name -NotePropertyValue $prop.Value -Force + } + if ($AllActionValues.Count -gt 0) { + $Existing | Add-Member -NotePropertyName 'combinedActions' -NotePropertyValue $AllActionValues -Force + } + + return $Existing +} diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 index ff9878957e2b..a47643c18b7c 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 @@ -23,15 +23,13 @@ function Test-CIPPAccessPermissions { TenantId = '' UserPrincipalName = '' } - Write-Host 'Setting success to true by default.' $Success = $true try { Set-Location (Get-Item $PSScriptRoot).FullName - $ExpectedPermissions = Get-Content '.\SAMManifest.json' | ConvertFrom-Json $null = Get-CIPPAuthentication $GraphToken = Get-GraphToken -returnRefresh $true -SkipCache $true if ($GraphToken) { - $GraphPermissions = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/myorganization/applications(appId='$env:ApplicationID')" -NoAuthCheck $true + $GraphPermissions = Get-CippSamPermissions } if ($env:MSI_SECRET) { try { @@ -41,15 +39,8 @@ function Test-CIPPAccessPermissions { $KV = $ENV:WEBSITE_DEPLOYMENT_ID $KeyVaultRefresh = Get-AzKeyVaultSecret -VaultName $kv -Name 'RefreshToken' -AsPlainText if ($ENV:RefreshToken -ne $KeyVaultRefresh) { - Write-Host 'Setting success to false due to nonmaching token.' - $Success = $false - $ErrorMessages.Add('Your refresh token does not match key vault, clear your cache or wait 30 minutes.') | Out-Null - $Links.Add([PSCustomObject]@{ - Text = 'Clear Token Cache' - Href = 'https://docs.cipp.app/setup/installation/cleartokencache' - } - ) | Out-Null + $ErrorMessages.Add('Your refresh token does not match key vault, wait 30 minutes for the function app to update.') | Out-Null } else { $Messages.Add('Your refresh token matches key vault.') | Out-Null } @@ -57,6 +48,8 @@ function Test-CIPPAccessPermissions { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -user $User -API $APINAME -tenant $tenant -message "Key vault exception: $($ErrorMessage.NormalizedError) " -Sev 'Error' -LogData $ErrorMessage } + } else { + $Messages.Add('Your refresh token matches key vault.') | Out-Null } try { @@ -69,21 +62,28 @@ function Test-CIPPAccessPermissions { } Write-LogMessage -user $User -API $APINAME -tenant $tenant -message "Token exception: $($ErrorMessage.NormalizedError_) " -Sev 'Error' -LogData $ErrorMessage $Success = $false - Write-Host 'Setting success to false due to not able to decode token.' - } if ($AccessTokenDetails.Name -eq '') { $ErrorMessages.Add('Your refresh token is invalid, check for line breaks or missing characters.') | Out-Null - Write-Host 'Setting success to false invalid token.' - $Success = $false } else { + if ($AccessTokenDetails.Name -match 'CIPP' -or $AccessTokenDetails.UserPrincipalName -match 'CIPP' -or $AccessTokenDetails.Name -match 'Service' -or $AccessTokenDetails.UserPrincipalName -match 'Service') { + $Messages.Add('You are running CIPP as a service account.') | Out-Null + } else { + $ErrorMessages.Add('You do not appear to be running CIPP as a service account.') | Out-Null + $Success = $false + $Links.Add([PSCustomObject]@{ + Text = 'Creating the CIPP Service Account' + Href = 'https://docs.cipp.app/setup/installation/creating-the-cipp-service-account-gdap-ready' + } + ) | Out-Null + } + if ($AccessTokenDetails.AuthMethods -contains 'mfa') { $Messages.Add('Your access token contains the MFA claim.') | Out-Null } else { $ErrorMessages.Add('Your access token does not contain the MFA claim, Refresh your SAM tokens.') | Out-Null - Write-Host 'Setting success to False due to invalid list of claims.' $Success = $false $Links.Add([PSCustomObject]@{ @@ -94,13 +94,30 @@ function Test-CIPPAccessPermissions { } } - $MissingPermissions = $ExpectedPermissions.requiredResourceAccess.ResourceAccess.id | Where-Object { $_ -notin $GraphPermissions.requiredResourceAccess.ResourceAccess.id } - if ($MissingPermissions) { - Write-Host "Setting success to False due to permissions issues: $($MissingPermissions | ConvertTo-Json)" - $Translator = Get-Content '.\PermissionsTranslator.json' | ConvertFrom-Json - $TranslatedPermissions = $Translator | Where-Object id -In $MissingPermissions | ForEach-Object { "$($_.value) - $($_.Origin)" } - $MissingPermissions = @($TranslatedPermissions) + $MissingSamPermissions = $GraphPermissions.MissingPermissions + if (($MissingSamPermissions.PSObject.Properties.Name | Measure-Object).Count -gt 0) { + + $MissingPermissions = foreach ($AppId in $MissingSamPermissions.PSObject.Properties.Name) { + $ServicePrincipal = $GraphPermissions.UsedServicePrincipals | Where-Object -Property appId -EQ $AppId + + foreach ($Permission in $MissingSamPermissions.$AppId.applicationPermissions) { + [PSCustomObject]@{ + Application = $ServicePrincipal.displayName + Type = 'Application' + PermissionId = $Permission.id + Permission = $Permission.value + } + } + foreach ($Permission in $MissingSamPermissions.$AppId.delegatedPermissions) { + [PSCustomObject]@{ + Application = $ServicePrincipal.displayName + Type = 'Delegated' + PermissionId = $Permission.id + Permission = $Permission.value + } + } + } $Success = $false $Links.Add([PSCustomObject]@{ Text = 'Permissions' @@ -108,15 +125,35 @@ function Test-CIPPAccessPermissions { } ) | Out-Null } else { - $Messages.Add('Your Secure Application Model has all required permissions') | Out-Null + $Messages.Add('You have all the required permissions.') | Out-Null } + $LastUpdate = [DateTime]::SpecifyKind($GraphPermissions.Timestamp.DateTime, [DateTimeKind]::Utc) + $CpvTable = Get-CippTable -tablename 'cpvtenants' + $CpvRefresh = Get-CippAzDataTableEntity @CpvTable -Filter "PartitionKey eq 'Tenant'" + $TenantList = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -ne $env:TenantID -and $_.Excluded -eq $false } + $CPVRefreshList = [System.Collections.Generic.List[object]]::new() + $CPVSuccess = $true + foreach ($Tenant in $TenantList) { + $LastRefresh = ($CpvRefresh | Where-Object { $_.RowKey -EQ $Tenant.customerId }).Timestamp.DateTime + if ($LastRefresh -lt $LastUpdate) { + $CPVSuccess = $false + $CPVRefreshList.Add([PSCustomObject]@{ + CustomerId = $Tenant.customerId + DisplayName = $Tenant.displayName + DefaultDomainName = $Tenant.DefaultDomainName + LastRefresh = $LastRefresh + }) + } + } + if (!$CPVSuccess) { + $ErrorMessages.Add('Some tenants need a CPV refresh.') | Out-Null + $Success = $false + } } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -user $User -API $APINAME -message "Permissions check failed: $($ErrorMessage.NormalizedError) " -Sev 'Error' -LogData $ErrorMessage $ErrorMessages.Add("We could not connect to the API to retrieve the permissions. There might be a problem with the secure application model configuration. The returned error is: $($ErrorMessage.NormalizedError)") | Out-Null - Write-Host 'Setting success to False due to not being able to connect.' - $Success = $false } @@ -129,6 +166,7 @@ function Test-CIPPAccessPermissions { Messages = @($Messages) ErrorMessages = @($ErrorMessages) MissingPermissions = @($MissingPermissions) + CPVRefreshList = @($CPVRefreshList) Links = @($Links) Success = $Success } @@ -144,7 +182,9 @@ function Test-CIPPAccessPermissions { Data = [string](ConvertTo-Json -InputObject $AccessCheck -Depth 10 -Compress) } } - Add-CIPPAzDataTableEntity @Table -Entity $Data -Force + try { + Add-CIPPAzDataTableEntity @Table -Entity $Data -Force + } catch {} return $AccessCheck } diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 index 69d1057e4302..575993740ca6 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 @@ -1,7 +1,7 @@ function Test-CIPPAccessTenant { [CmdletBinding()] param ( - $TenantCSV, + $Tenant = 'AllTenants', $APIName = 'Access Check', $ExecutingUser ) @@ -19,14 +19,48 @@ function Test-CIPPAccessTenant { @{ Name = 'Privileged Role Administrator'; Id = 'e8611ab8-c189-46e8-94e1-60213ab1f814' }, @{ Name = 'Privileged Authentication Administrator'; Id = '7be44c8a-adaf-4e2a-84d6-ab2649e08a13' } ) - $Tenants = ($TenantCSV).split(',') - if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } - $TenantList = Get-Tenants - $results = foreach ($tenant in $Tenants) { + $TenantParams = @{ + IncludeErrors = $true + } + if ($Tenant -eq 'AllTenants') { + $TenantList = Get-Tenants @TenantParams + $Queue = New-CippQueueEntry -Name 'Tenant Access Check' -TotalTasks ($TenantList | Measure-Object).Count + + $InputObject = [PSCustomObject]@{ + QueueFunction = @{ + FunctionName = 'GetTenants' + TenantParams = $TenantParams + DurableName = 'CIPPAccessTenantTest' + QueueId = $Queue.RowKey + } + OrchestratorName = 'CippAccessTenantTest' + SkipLog = $true + } + $null = Start-NewOrchestration -FunctionName CIPPOrchestrator -InputObject ($InputObject | ConvertTo-Json -Depth 10) + $Results = "Queued $($TenantList.Count) tenants for access checks" + + } else { + $TenantParams.TenantFilter = $Tenant + $Tenant = Get-Tenants @TenantParams + + $GraphStatus = $false + $ExchangeStatus = $false + + $Results = [PSCustomObject]@{ + TenantName = $Tenant.defaultDomainName + GraphStatus = $false + GraphTest = '' + ExchangeStatus = $false + ExchangeTest = '' + GDAPRoles = '' + MissingRoles = '' + LastRun = (Get-Date).ToUniversalTime() + } + $AddedText = '' try { - $TenantId = ($TenantList | Where-Object { $_.defaultDomainName -eq $tenant }).customerId + $TenantId = $Tenant.customerId $BulkRequests = $ExpectedRoles | ForEach-Object { @( @{ id = "roleManagement_$($_.Id)" @@ -35,11 +69,10 @@ function Test-CIPPAccessTenant { } ) } - $GDAPRolesGraph = New-GraphBulkRequest -tenantid $tenant -Requests $BulkRequests + $GDAPRolesGraph = New-GraphBulkRequest -tenantid $TenantId -Requests $BulkRequests $GDAPRoles = [System.Collections.Generic.List[object]]::new() $MissingRoles = [System.Collections.Generic.List[object]]::new() - #Write-Host ($GDAPRolesGraph.body.value | ConvertTo-Json -Depth 10) foreach ($RoleId in $ExpectedRoles) { $GraphRole = $GDAPRolesGraph.body.value | Where-Object -Property roleDefinitionId -EQ $RoleId.Id $Role = $GraphRole.principal | Where-Object -Property organizationId -EQ $ENV:TenantID @@ -59,48 +92,53 @@ function Test-CIPPAccessTenant { }) } } - if (!($MissingRoles | Measure-Object).Count -gt 0) { - $MissingRoles = $true - } - @{ - TenantName = "$($Tenant)" - Status = "Successfully connected $($AddedText)" - GDAPRoles = $GDAPRoles - MissingRoles = $MissingRoles - } - Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $tenant -message 'Tenant access check executed successfully' -Sev 'Info' + $GraphTest = "Successfully connected to Graph $($AddedText)" + $GraphStatus = $true } catch { $ErrorMessage = Get-CippException -Exception $_ - @{ - TenantName = "$($tenant)" - Status = "Failed to connect: $($ErrorMessage.NormalizedError)" - GDAP = '' - } - Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $tenant -message "Tenant access check failed: $($ErrorMessage.NormalizedError) " -Sev 'Error' -LogData $ErrorMessage - + $GraphTest = "Failed to connect to Graph: $($ErrorMessage.NormalizedError)" + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $tenant.defaultDomainName -message "Tenant access check failed: $($ErrorMessage.NormalizedError) " -Sev 'Error' -LogData $ErrorMessage } try { - $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' -ErrorAction Stop - @{ - TenantName = "$($Tenant)" - Status = 'Successfully connected to Exchange' - } - + $null = New-ExoRequest -tenantid $Tenant.customerId -cmdlet 'Get-OrganizationConfig' -ErrorAction Stop + $ExchangeStatus = $true + $ExchangeTest = 'Successfully connected to Exchange' } catch { $ErrorMessage = Get-CippException -Exception $_ $ReportedError = ($_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue) $Message = if ($ReportedError.error.details.message) { $ReportedError.error.details.message } else { $ReportedError.error.innererror.internalException.message } if ($null -eq $Message) { $Message = $($_.Exception.Message) } - @{ - TenantName = "$($Tenant)" - Status = "Failed to connect to Exchange: $($ErrorMessage.NormalizedError)" - } - Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $tenant -message "Tenant access check for Exchange failed: $($ErrorMessage.NormalizedError) " -Sev 'Error' -LogData $ErrorMessage + + $ExchangeTest = "Failed to connect to Exchange: $($ErrorMessage.NormalizedError)" + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $tenant.defaultDomainName -message "Tenant access check for Exchange failed: $($ErrorMessage.NormalizedError) " -Sev 'Error' -LogData $ErrorMessage + } + + if ($GraphStatus -and $ExchangeStatus) { + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $Tenant.defaultDomainName -tenantId $Tenant.customerId -message 'Tenant access check executed successfully' -Sev 'Info' + } + + $Results.GraphStatus = $GraphStatus + $Results.GraphTest = $GraphTest + $Results.ExchangeStatus = $ExchangeStatus + $Results.ExchangeTest = $ExchangeTest + $Results.GDAPRoles = @($GDAPRoles) + $Results.MissingRoles = @($MissingRoles) + + $ExecutingUser = $ExecutingUser.UserDetails + $Entity = @{ + PartitionKey = 'TenantAccessChecks' + RowKey = $Tenant.customerId + Data = [string]($Results | ConvertTo-Json -Depth 10 -Compress) + } + $Table = Get-CIPPTable -TableName 'AccessChecks' + try { + $null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force + } catch { + Write-LogMessage -user $ExecutingUser -API $APINAME -tenant $Tenant.defaultDomainName -message "Failed to add access check for $($Tenant.customerId): $($_.Exception.Message)" -Sev 'Error' -LogData (Get-CippException -Exception $_) } } - if (!$Tenants) { $results = 'Could not load the tenants list from cache. Please run permissions check first, or visit the tenants page.' } - return $results + return $Results } diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 71b7cae9808a..09cf46fe35c4 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -6,7 +6,8 @@ function Test-CIPPGDAPRelationships { $ExecutingUser ) - $GDAPissues = [System.Collections.ArrayList]@() + $GDAPissues = [System.Collections.Generic.List[object]]@() + $MissingGroups = [System.Collections.Generic.List[object]]@() try { #Get graph request to list all relationships. $Relationships = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/delegatedAdminRelationships?`$filter=status eq 'active'" -tenantid $ENV:TenantID -NoAuthCheck $true @@ -17,8 +18,8 @@ function Test-CIPPGDAPRelationships { $GDAPissues.add([PSCustomObject]@{ Type = 'Error' Issue = 'This tenant only has a MLT(Microsoft Led Transition) relationship. This is a read-only relationship. You must migrate this tenant to GDAP.' - Tenant = $Tenant.Group.customer.displayName - Relationship = $Tenant.Group.displayName + Tenant = [string]$Tenant.Group.customer.displayName + Relationship = [string]$Tenant.Group.displayName Link = 'https://docs.cipp.app/setup/gdap/index' }) | Out-Null } @@ -27,8 +28,8 @@ function Test-CIPPGDAPRelationships { $GDAPissues.add([PSCustomObject]@{ Type = 'Warning' Issue = 'The relationship has global administrator access. Auto-Extend is not available.' - Tenant = $Group.customer.displayName | Out-String - Relationship = $Group.displayName | Out-String + Tenant = [string]$Group.customer.displayName + Relationship = [string]$Group.displayName Link = 'https://docs.cipp.app/setup/gdap/troubleshooting#autoextend' }) | Out-Null @@ -75,6 +76,10 @@ function Test-CIPPGDAPRelationships { Link = 'https://docs.cipp.app/setup/gdap/troubleshooting#groups' }) | Out-Null + $MissingGroups.Add([PSCustomObject]@{ + Name = $Group + Type = 'SAM User Membership' + }) | Out-Null } if ($CIPPGroupCount -lt 12) { $GDAPissues.add([PSCustomObject]@{ @@ -102,6 +107,7 @@ function Test-CIPPGDAPRelationships { $Table = Get-CIPPTable -TableName AccessChecks $Data = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'AccessCheck' and RowKey eq 'GDAPRelationships'" + if ($Data) { $Data.Data = [string](ConvertTo-Json -InputObject $GDAPRelationships -Depth 10 -Compress) } else { @@ -111,7 +117,9 @@ function Test-CIPPGDAPRelationships { Data = [string](ConvertTo-Json -InputObject $GDAPRelationships -Depth 10 -Compress) } } - Add-CIPPAzDataTableEntity @Table -Entity $Data -Force + try { + Add-CIPPAzDataTableEntity @Table -Entity $Data -Force + } catch {} return $GDAPRelationships } diff --git a/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 b/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 index 8480f943a384..39384ad879bc 100644 --- a/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 @@ -6,7 +6,8 @@ function Test-CIPPRerun { $API, $Settings, $ExecutingUser, - [switch]$Clear + [switch]$Clear, + [switch]$ClearAll ) $RerunTable = Get-CIPPTable -tablename 'RerunCache' $EstimatedDifference = switch ($Type) { @@ -19,6 +20,12 @@ function Test-CIPPRerun { try { $RerunData = Get-CIPPAzDataTableEntity @RerunTable -filter "PartitionKey eq '$($TenantFilter)' and RowKey eq '$($Type)_$($API)'" + if ($ClearAll.IsPresent) { + $AllRerunData = Get-CIPPAzDataTableEntity @RerunTable + Remove-AzDataTableEntity @RerunTable -Entity $AllRerunData -Force + return $false + } + if ($Clear.IsPresent) { if ($RerunData) { Remove-AzDataTableEntity @RerunTable -Entity $RerunData @@ -38,7 +45,7 @@ function Test-CIPPRerun { } } if ($RerunData.EstimatedNextRun -gt $CurrentUnixTime) { - Write-LogMessage -message "Standard rerun detected for $($API). Prevented from running again." -tenant $TenantFilter -user $ExecutingUser -Sev 'Info' + Write-LogMessage -API $API -message "Standard rerun detected for $($API). Prevented from running again." -tenant $TenantFilter -user $ExecutingUser -Sev 'Info' return $true } else { $RerunData.EstimatedNextRun = $EstimatedNextRun diff --git a/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 index a6212c26f322..c03f02629b58 100644 --- a/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 @@ -37,7 +37,7 @@ function New-CIPPGraphSubscription { WebhookEvents = @($EventList) } try { - $EventCompare = Compare-Object $EventList ($MatchedWebhook.EventType | ConvertFrom-Json) + $EventCompare = Compare-Object $EventList ($MatchedWebhook.EventType | ConvertFrom-Json -ErrorAction Stop) } catch { $EventCompare = $false } diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 index 94d2a83278bd..e820377bd909 100644 --- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -29,7 +29,7 @@ function Test-CIPPAuditLogRules { $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } | ForEach-Object { [pscustomobject]@{ - Tenants = ($_.Tenants | ConvertFrom-Json).fullValue + Tenants = ($_.Tenants | ConvertFrom-Json) Conditions = $_.Conditions Actions = $_.Actions LogType = $_.Type @@ -37,16 +37,18 @@ function Test-CIPPAuditLogRules { } #write-warning 'Getting audit records from Graph API' try { + $LogCount = Get-CippAuditLogSearchResults -TenantFilter $TenantFilter -QueryId $SearchId -CountOnly + $RunGuid = (New-Guid).Guid + Write-Warning "Logs to process: $LogCount - SearchId: $SearchId - RunGuid: $($RunGuid) - $($TenantFilter)" + $Results.TotalLogs = $LogCount + Write-Information "RunGuid: $RunGud - Collecting logs" $SearchResults = Get-CippAuditLogSearchResults -TenantFilter $TenantFilter -QueryId $SearchId } catch { Write-Warning "Error getting audit logs: $($_.Exception.Message)" Write-LogMessage -API 'Webhooks' -message "Error getting audit logs for search $($SearchId)" -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter throw $_ } - $LogCount = ($SearchResults | Measure-Object).Count - $RunGuid = New-Guid - Write-Warning "Logs to process: $LogCount - RunGuid: $($RunGuid) - $($TenantFilter)" - $Results.TotalLogs = $LogCount + if ($LogCount -gt 0) { $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' $ProcessedData = foreach ($AuditRecord in $SearchResults) { @@ -90,7 +92,7 @@ function Test-CIPPAuditLogRules { $Data.clientip = $Data.clientip -replace ':\d+$', '' # Remove the port number if present } # Check if IP is on trusted IP list - $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Data.clientip)' and state eq 'Trusted'" + $TrustedIP = Get-CIPPAzDataTableEntity @TrustedIPTable -Filter "((PartitionKey eq '$TenantFilter') or (PartitionKey eq 'AllTenants')) and RowKey eq '$($Data.clientip)' and state eq 'Trusted'" if ($TrustedIP) { #write-warning "IP $($Data.clientip) is trusted" $Trusted = $true diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index ae942d328329..e7de51d858a7 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -208,7 +208,7 @@ function Receive-CIPPTimerTrigger { foreach ($Function in $Functions) { Write-Information "CIPPTimer: $($Function.Command) - $($Function.Cron)" - $FunctionStatus = $Statuses | Where-Object { $_.RowKey -eq $Function.Command } + $FunctionStatus = $Statuses | Where-Object { $_.RowKey -eq $Function.Id } if ($FunctionStatus.OrchestratorId) { $FunctionName = $env:WEBSITE_SITE_NAME $InstancesTable = Get-CippTable -TableName ('{0}Instances' -f ($FunctionName -replace '-', '')) @@ -223,7 +223,13 @@ function Receive-CIPPTimerTrigger { if ($FunctionStatus.PSObject.Properties.Name -contains 'ErrorMsg') { $FunctionStatus.ErrorMsg = '' } - $Results = Invoke-Command -ScriptBlock { & $Function.Command } + + $Parameters = @{} + if ($Function.Parameters) { + $Parameters = $Function.Parameters | ConvertTo-Json | ConvertFrom-Json -AsHashtable + } + + $Results = Invoke-Command -ScriptBlock { & $Function.Command @Parameters } if ($Results -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') { $FunctionStatus.OrchestratorId = $Results $Status = 'Started' diff --git a/Modules/CippExtensions/ConversionTable.csv b/Modules/CippExtensions/ConversionTable.csv index 55ebdfd465b9..4463224224a6 100644 --- a/Modules/CippExtensions/ConversionTable.csv +++ b/Modules/CippExtensions/ConversionTable.csv @@ -1428,6 +1428,17 @@ Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99 Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_BUSINESS_CHAT,3f30311c-6b1e-48a4-ab79-725b469da960,Microsoft Copilot with Graph-grounded chat Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_CONNECTORS,89f1c4c8-0878-40f7-804d-869c9128ab5d,Power Platform Connectors in Microsoft 365 Copilot Microsoft 365 Domestic Calling Plan (120 minutes) - US,MCOPSTN5_US,d13e9d1b-316a-4946-98c6-362c97a4fdfe,PSTN5_US,1346d5e6-15a6-4b88-9693-806ff7296a7a,Microsoft 365 Domestic Calling Plan - US (120 minutes) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings @@ -1445,6 +1456,7 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_O365,882e1d0 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway @@ -1466,6 +1478,56 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_A,c1ec4a95-1 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MDE_LITE,292cc034-7b7c-4950-aaf5-943befd3f1d4,Microsoft Defender for Endpoint Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_LOOP,c4b8c31a-fb44-4c65-9837-a21f55fcabda,Microsoft Loop +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,UNIVERSAL_PRINT_01,795f6fe0-cc4d-4773-b050-5dde4dc704c9,Universal Print +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WIN10_PRO_ENT_SUB,21b439ba-a0ca-424f-a6cc-52f954a5b111,Windows 10/11 Enterprise (Original) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Windows_Autopatch,9a6eeb79-0b4b-4bf0-9808-39d99a2cd5a3,Windows Autopatch +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WINDOWSUPDATEFORBUSINESS_DEPLOYMENTSERVICE,7bf960f6-2cd9-443a-8046-5dbff9558365,Windows Update for Business Deployment Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_PREMIUM,6c57d4b6-3b23-47a5-9bc9-69f17b4947b3,Azure Information Protection Premium P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MFA_PREMIUM,8a256a2b-b617-496d-b51b-e76466e88db0,Microsoft Azure Multi-Factor Authentication +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ADALLOM_S_DISCOVERY,932ad362-64a8-4783-9106-97849a1a30b9,Microsoft Defender for Cloud Apps Discovery +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,AAD_PREMIUM,41781fb2-bc02-4b7c-bd55-b576c07bb09d,Microsoft Entra ID P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_A,c1ec4a95-1f05-45b3-a911-aa3fa01094f5,Microsoft Intune Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,Commercial data protection for Microsoft Copilot @@ -3186,6 +3248,8 @@ Microsoft Defender for Identity,ATA,98defdf7-f6c1-44f5-a1f6-943b6764e7a5,ADALLOM Microsoft Defender for Office 365 (Plan 1) Faculty,ATP_ENTERPRISE_FACULTY,26ad4b5c-b686-462e-84b9-d7c22b46837f,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 1) GCC,ATP_ENTERPRISE_GOV,d0d1ca43-b81a-4f51-81e5-a5b1ad7bb005,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH,ATP_ENTERPRISE_USGOV_GCCHIGH ,550f19ba-f323-4a7d-a8d2-8971b0d9ea85,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student,ATP_ENTERPRISE_STUDENT,917fb2b4-f71c-43a1-8edc-75532b554bb5,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student use benefit,ATP_ENTERPRISE_STUDENTS_USE_BENEFIT,a237b6d8-572e-4839-bffd-7786d32a5d0e,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,MTP,bf28f719-7844-4079-9c78-c1307898e192,Microsoft 365 Defender Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,THREAT_INTELLIGENCE_GOV,900018f1-0cdb-4ecb-94d4-90281760fdc6,Microsoft Defender for Office 365 (Plan 2) for Government @@ -3468,9 +3532,9 @@ Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,MIN Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,MINECRAFT_EDUCATION_EDITION,4c246bbc-f513-4311-beff-eba54c353256,Minecraft Education Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,NONPROFIT_PORTAL,7dbc2d88-20e2-4eb6-b065-4510b38d6eb2,Nonprofit Portal Office 365 A1 for faculty,STANDARDWOFFPACK_FACULTY,94763226-9b3c-4e75-a931-5c89701abe66,AAD_BASIC_EDU,1d0f309f-fdf9-4b2a-9ae7-9c48b91f1426,Microsoft Entra ID Basic for Education @@ -3858,6 +3922,23 @@ Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWERAPPS_O365_P1,92f7a6f3-b89b-4bbd-8c30-809e6da5ad1c,Power Apps for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,FLOW_O365_P1,0f9b09cb-62d1-4ff4-9129-43f4996f83f4,Power Automate for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWER_VIRTUAL_AGENTS_O365_P1,0683001c-0492-4d59-9515-d9a6426b5813,Power Virtual Agents for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,CDS_O365_P1,bed136c6-b799-4462-824d-fc045d3a9d25,Common Data Service for Teams +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,Exchange Online (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FORMS_PLAN_E1_AR_GCCHIGH,9c37c053-dfe3-4421-b6d4-bac8b86d42bd,Microsoft Forms (Plan E1) for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFT_SEARCH_GCCH,fc9f7921-4ca5-42c6-8533-1b84c4ee496b,Microsoft Search for Arlington +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,TEAMS_AR_GCCHIGH,9953b155-8aef-4c56-92f3-72b0487fce41,Microsoft Teams for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,OFFICEMOBILE_SUBSCRIPTION,c63d4d19-e8cb-460e-b37c-4d6c34603745,Office Mobile Apps for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SharePoint (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,DYN365_CDS_O365_P1,40b010bb-0b69-4654-ac5e-ba161433f4b4,Common Data Service +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,STREAM_O365_E1,743dd19e-1ce3-4c62-a3ad-49ba8f63a2f6,Microsoft Stream for Office 365 E1 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,POWERAPPS_O365_P1_GCCHIGH,3913e44e-824e-490c-a182-82785d769b45,Power Apps for Office 365 for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FLOW_O365_P1_GCCHIGH,e923bad8-588e-44d5-acd0-b226daa7b4de,Power Automate for Office 365 for GCCHigh Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,BPOS_S_TODO_1,5e62787c-c316-451f-b873-1d05acd4d12c,BPOS_S_TODO_1 Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,MICROSOFT STAFFHUB Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,EXCHANGE ONLINE (PLAN 1) @@ -3908,6 +3989,44 @@ Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,DYN365_CDS_O36 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard @@ -4563,16 +4682,16 @@ Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-5 Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,CDS_ POWERAPPS_PER_USER_CUSTOM,2e8dde43-6986-479d-b179-7dbe31c31f60,CDS Power Apps Per User Custom Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,DYN365_CDS_P1_GOV,ce361df2-f2a5-4713-953f-4050ba09aad8,Common Data Service for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,FLOW_P1_GOV,774da41c-a8b3-47c1-8322-b9c1ab68be9f,Power Automate (Plan 1) for Government @@ -4810,26 +4929,26 @@ Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4c Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,SWAY -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,Common Data Service for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,Power Automate for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT STANDARD -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project @@ -4948,13 +5067,13 @@ Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,OneDrive for Business (Basic) Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,Visio Desktop App Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,Visio Web App -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,EXCHANGE FOUNDATION FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,ONEDRIVE_BASIC_GOV,98709c2e-96b5-4244-95f5-a0ebe139fb8a,ONEDRIVE FOR BUSINESS BASIC FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,VISIO_CLIENT_SUBSCRIPTION_GOV,f85945f4-7a55-4009-bc39-6a5f14a8eac1,VISIO DESKTOP APP FOR Government diff --git a/Modules/CippExtensions/Public/ConversionTable.csv b/Modules/CippExtensions/Public/ConversionTable.csv index 55ebdfd465b9..4463224224a6 100644 --- a/Modules/CippExtensions/Public/ConversionTable.csv +++ b/Modules/CippExtensions/Public/ConversionTable.csv @@ -1428,6 +1428,17 @@ Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99 Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_BUSINESS_CHAT,3f30311c-6b1e-48a4-ab79-725b469da960,Microsoft Copilot with Graph-grounded chat Microsoft Copilot for Microsoft 365,M365_Copilot,a809996b-059e-42e2-9866-db24b99a9782,M365_COPILOT_CONNECTORS,89f1c4c8-0878-40f7-804d-869c9128ab5d,Power Platform Connectors in Microsoft 365 Copilot Microsoft 365 Domestic Calling Plan (120 minutes) - US,MCOPSTN5_US,d13e9d1b-316a-4946-98c6-362c97a4fdfe,PSTN5_US,1346d5e6-15a6-4b88-9693-806ff7296a7a,Microsoft 365 Domestic Calling Plan - US (120 minutes) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings @@ -1445,6 +1456,7 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_O365,882e1d0 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway @@ -1466,6 +1478,56 @@ Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,INTUNE_A,c1ec4a95-1 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Microsoft 365 E3,SPE_E3,05e9a617-0261-4cee-bb44-138d3ef5d965,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MDE_LITE,292cc034-7b7c-4950-aaf5-943befd3f1d4,Microsoft Defender for Endpoint Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_LOOP,c4b8c31a-fb44-4c65-9837-a21f55fcabda,Microsoft Loop +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,UNIVERSAL_PRINT_01,795f6fe0-cc4d-4773-b050-5dde4dc704c9,Universal Print +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WIN10_PRO_ENT_SUB,21b439ba-a0ca-424f-a6cc-52f954a5b111,Windows 10/11 Enterprise (Original) +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,Windows_Autopatch,9a6eeb79-0b4b-4bf0-9808-39d99a2cd5a3,Windows Autopatch +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,WINDOWSUPDATEFORBUSINESS_DEPLOYMENTSERVICE,7bf960f6-2cd9-443a-8046-5dbff9558365,Windows Update for Business Deployment Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,RMS_S_PREMIUM,6c57d4b6-3b23-47a5-9bc9-69f17b4947b3,Azure Information Protection Premium P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,MFA_PREMIUM,8a256a2b-b617-496d-b51b-e76466e88db0,Microsoft Azure Multi-Factor Authentication +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,ADALLOM_S_DISCOVERY,932ad362-64a8-4783-9106-97849a1a30b9,Microsoft Defender for Cloud Apps Discovery +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,AAD_PREMIUM,41781fb2-bc02-4b7c-bd55-b576c07bb09d,Microsoft Entra ID P1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,INTUNE_A,c1ec4a95-1f05-45b3-a911-aa3fa01094f5,Microsoft Intune Plan 1 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Microsoft 365 E3 (no Teams),Microsoft_365_E3_(no_Teams),dcf0408c-aaec-446c-afd4-43e3683943ea,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Microsoft 365 E3 EEA (no Teams),O365_w/o Teams Bundle_M3,c2fe850d-fbbb-4858-b67d-bd0c6e746da3,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,Commercial data protection for Microsoft Copilot @@ -3186,6 +3248,8 @@ Microsoft Defender for Identity,ATA,98defdf7-f6c1-44f5-a1f6-943b6764e7a5,ADALLOM Microsoft Defender for Office 365 (Plan 1) Faculty,ATP_ENTERPRISE_FACULTY,26ad4b5c-b686-462e-84b9-d7c22b46837f,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 1) GCC,ATP_ENTERPRISE_GOV,d0d1ca43-b81a-4f51-81e5-a5b1ad7bb005,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH,ATP_ENTERPRISE_USGOV_GCCHIGH ,550f19ba-f323-4a7d-a8d2-8971b0d9ea85,ATP_ENTERPRISE,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student,ATP_ENTERPRISE_STUDENT,917fb2b4-f71c-43a1-8edc-75532b554bb5,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) +Microsoft Defender for Office 365 (Plan 1) Student use benefit,ATP_ENTERPRISE_STUDENTS_USE_BENEFIT,a237b6d8-572e-4839-bffd-7786d32a5d0e,ATP_ENTERPRISE ,f20fedf3-f3c3-43c3-8267-2bfdd51c0939,Microsoft Defender for Office 365 (Plan 1) Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,MTP,bf28f719-7844-4079-9c78-c1307898e192,Microsoft 365 Defender Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,ATP_ENTERPRISE_GOV,493ff600-6a2b-4db6-ad37-a7d4eb214516,Microsoft Defender for Office 365 (Plan 1) for Government Microsoft Defender for Office 365 (Plan 2) GCC,THREAT_INTELLIGENCE_GOV,56a59ffb-9df1-421b-9e61-8b568583474d,THREAT_INTELLIGENCE_GOV,900018f1-0cdb-4ecb-94d4-90281760fdc6,Microsoft Defender for Office 365 (Plan 2) for Government @@ -3468,9 +3532,9 @@ Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,MIN Minecraft Education Student,MEE_STUDENT,533b8f26-f74b-4e9c-9c59-50fc4b393b63,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,MINECRAFT_EDUCATION_EDITION,4c246bbc-f513-4311-beff-eba54c353256,Minecraft Education Minecraft Education Faculty,MEE_FACULTY,984df360-9a74-4647-8cf8-696749f6247a,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo -Multi-Geo Capabilities in Office 365,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,EXCHANGEONLINE_MULTIGEO,897d51f1-2cfa-4848-9b30-469149f5e68e,Exchange Online Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,SHAREPOINTONLINE_MULTIGEO,735c1d98-dd3f-4818-b4ed-c8052e18e62d,SharePoint Multi-Geo +Office 365 Multi-Geo Capabilities,OFFICE365_MULTIGEO,84951599-62b7-46f3-9c9d-30551b2ad607,TEAMSMULTIGEO,41eda15d-6b52-453b-906f-bc4a5b25a26b,Teams Multi-Geo Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Nonprofit Portal,NONPROFIT_PORTAL,aa2695c9-8d59-4800-9dc8-12e01f1735af,NONPROFIT_PORTAL,7dbc2d88-20e2-4eb6-b065-4510b38d6eb2,Nonprofit Portal Office 365 A1 for faculty,STANDARDWOFFPACK_FACULTY,94763226-9b3c-4e75-a931-5c89701abe66,AAD_BASIC_EDU,1d0f309f-fdf9-4b2a-9ae7-9c48b91f1426,Microsoft Entra ID Basic for Education @@ -3858,6 +3922,23 @@ Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWERAPPS_O365_P1,92f7a6f3-b89b-4bbd-8c30-809e6da5ad1c,Power Apps for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,FLOW_O365_P1,0f9b09cb-62d1-4ff4-9129-43f4996f83f4,Power Automate for Office 365 Office 365 E1 EEA (no Teams),Office_365_w/o_Teams_Bundle_E1,b57282e3-65bd-4252-9502-c0eae1e5ab7f,POWER_VIRTUAL_AGENTS_O365_P1,0683001c-0492-4d59-9515-d9a6426b5813,Power Virtual Agents for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,CDS_O365_P1,bed136c6-b799-4462-824d-fc045d3a9d25,Common Data Service for Teams +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,Exchange Online (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FORMS_PLAN_E1_AR_GCCHIGH,9c37c053-dfe3-4421-b6d4-bac8b86d42bd,Microsoft Forms (Plan E1) for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MICROSOFT_SEARCH_GCCH,fc9f7921-4ca5-42c6-8533-1b84c4ee496b,Microsoft Search for Arlington +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,TEAMS_AR_GCCHIGH,9953b155-8aef-4c56-92f3-72b0487fce41,Microsoft Teams for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,OFFICEMOBILE_SUBSCRIPTION,c63d4d19-e8cb-460e-b37c-4d6c34603745,Office Mobile Apps for Office 365 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SharePoint (Plan 1) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,DYN365_CDS_O365_P1,40b010bb-0b69-4654-ac5e-ba161433f4b4,Common Data Service +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,STREAM_O365_E1,743dd19e-1ce3-4c62-a3ad-49ba8f63a2f6,Microsoft Stream for Office 365 E1 +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,POWERAPPS_O365_P1_GCCHIGH,3913e44e-824e-490c-a182-82785d769b45,Power Apps for Office 365 for GCCHigh +Office 365 E1_USGOV_GCCHIGH,STANDARDPACK_USGOV_GCCHIGH,f698ca06-024f-4562-b029-9cb1f1e02646,FLOW_O365_P1_GCCHIGH,e923bad8-588e-44d5-acd0-b226daa7b4de,Power Automate for Office 365 for GCCHigh Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,BPOS_S_TODO_1,5e62787c-c316-451f-b873-1d05acd4d12c,BPOS_S_TODO_1 Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,MICROSOFT STAFFHUB Office 365 E2,STANDARDWOFFPACK,6634e0ce-1a9f-428c-a498-f84ec7b8aa2e,EXCHANGE_S_STANDARD,9aaf7827-d63c-4b61-89c3-182f06f82e5c,EXCHANGE ONLINE (PLAN 1) @@ -3908,6 +3989,44 @@ Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,DYN365_CDS_O36 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 Office 365 E3,ENTERPRISEPACK,6fd2c87f-b296-42f0-b197-1e91e994b900,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_FOR_TEAMS,dcf9d2f4-772e-4434-b757-77a453cfbc02,Avatars for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_AVATARS_ADDITIONAL_FOR_TEAMS,3efbd4ed-8958-4824-8389-1321f8730af8,Avatars for Teams (additional) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,RMS_S_ENTERPRISE,bea4c11e-220a-4e6d-8eb8-8ea15d019f90,Azure Rights Management +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,GRAPH_CONNECTORS_SEARCH_INDEX,a6520331-d7d4-4276-95f5-15c0933bc757,Graph Connectors Search with Index +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MESH_IMMERSIVE_FOR_TEAMS,f0ff6ac6-297d-49cd-be34-6dfef97f0c28,Immersive spaces for Teams +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MIP_S_CLP1,5136a095-5cf0-4aff-bec3-e84448b38ea5,Information Protection for Office 365 - Standard +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MYANALYTICS_P2,33c4f319-9bdd-48d6-9c4d-410b750a4a5a,Insights by MyAnalytics +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,OFFICESUBSCRIPTION,43de0ff5-c92c-492b-9116-175376d08c38,Microsoft 365 Apps for enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFTBOOKINGS,199a5c09-e0ca-4e37-8f7c-b05d533e1ea2,Microsoft Bookings +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,CLIPCHAMP,a1ace008-72f3-4ea0-8dac-33b3a23a2472,Microsoft Clipchamp +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FORMS_PLAN_E3,2789c901-c14e-48ab-a76a-be334d9d793a,Microsoft Forms (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,KAIZALA_O365_P3,aebd3021-9f8f-4bf8-bbe3-0ed2f4f047a1,Microsoft Kaizala Pro +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECTWORKMANAGEMENT,b737dad2-2f6c-4c65-90e3-ca563267e8b9,Microsoft Planner +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MICROSOFT_SEARCH,94065c59-bc8e-4e8b-89e5-5138d471eaff,Microsoft Search +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Deskless,8c7d2df8-86f0-4902-b2ed-a0458298f3b3,Microsoft StaffHub +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,STREAM_O365_E3,9e700747-8b1d-45e5-ab8d-ef187ceec156,Microsoft Stream for Office 365 E3 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,INTUNE_O365,882e1d05-acd1-4ccb-8708-6ee03664b117,Mobile Device Management for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Nucleus,db4d623d-b514-490b-b7ef-8885eee514de,Nucleus +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the Web +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PLACES_CORE,1fe6227d-3e01-46d0-9510-0acad4ff6e94,Places Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,PROJECT_O365_P2,31b4e2fc-4cd6-4e7d-9c1b-41407303bd66,Project for Office (Plan E3) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,Bing_Chat_Enterprise,0d0c0d31-fae7-41f2-b909-eaf4d7f26dba,RETIRED - Commercial data protection for Microsoft Copilot +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,MCOSTANDARD,0feaeb32-d00e-4d66-bd5a-43b5b83db82c,Skype for Business Online (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,Sway +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,BPOS_S_TODO_2,c87f142c-d1e9-4363-8630-aaea9c4d9ae5,To-Do (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVAENGAGE_CORE,a82fbf69-b4d7-49f4-83a6-915b2cf354f4,Viva Engage Core +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,VIVA_LEARNING_SEEDED,b76fb638-6ba6-402a-b9f9-83d28acb3d86,Viva Learning Seeded +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,WHITEBOARD_PLAN2,94a54592-cd8b-425e-87c6-97868b000b91,Whiteboard (Plan 2) +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,YAMMER_ENTERPRISE,7547a3fe-08ee-4ccb-b430-5077c5041653,Yammer Enterprise +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,DYN365_CDS_O365_P2,4ff01e01-1ba7-4d71-8cf8-ce96c3bbcf14,Common Data Service +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWERAPPS_O365_P2,c68f8d98-5534-41c8-bf36-22fa496fa792,Power Apps for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,FLOW_O365_P2,76846ad7-7776-4c40-a281-a386362dd1b9,Power Automate for Office 365 +Office 365 E3 (no Teams),Office_365_E3_(no_Teams),46c3a859-c90d-40b3-9551-6178a48d5c18,POWER_VIRTUAL_AGENTS_O365_P2,041fe683-03e4-45b6-b1af-c0cdc516daee,Power Virtual Agents for Office 365 Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,CDS_O365_P2,95b76021-6a53-4741-ab8b-1d1f3d66a95a,Common Data Service for Teams Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,EXCHANGE_S_ENTERPRISE,efb87545-963c-4e0d-99df-69c6916d9eb0,Exchange Online (Plan 2) Office 365 E3 EEA (no Teams),O365_w/o_Teams_Bundle_E3,d711d25a-a21c-492f-bd19-aae1e8ebaf30,ContentExplorer_Standard,2b815d45-56e4-4e3a-b65c-66cb9175b560,Information Protection and Governance Analytics – Standard @@ -4563,16 +4682,16 @@ Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-5 Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,CDS_ POWERAPPS_PER_USER_CUSTOM,2e8dde43-6986-479d-b179-7dbe31c31f60,CDS Power Apps Per User Custom Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan Power Apps Per User BD Only,POWERAPPS_PER_USER_BD_ONLY,2ced8a00-3ed1-4295-ab7c-57170ff28e58,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan -Power Apps per user plan,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government -Power Apps per user plan for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,DYN365_CDS_P2,6ea4c1ef-c259-46df-bce2-943342cd3cb2,Common Data Service - P2 +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,POWERAPPS_PER_USER,ea2cf03b-ac60-46ae-9c1d-eeaeb63cec86,Power Apps per User Plan +Power Apps Premium,POWERAPPS_PER_USER,b30411f5-fea1-4a59-9ad9-3db7c7ead579,Flow_PowerApps_PerUser,dc789ed8-0170-4b65-a415-eb77d5bb350a,Power Automate for Power Apps per User Plan +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER,91f50f7b-2204-4803-acac-5cf5668b8b39,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,CDSAICAPACITY_PERUSER_NEW,74d93933-6f22-436e-9441-66d205435abb,AI Builder capacity Per User add-on +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,DYN365_CDS_P2_GOV,37396c73-2203-48e6-8be1-d882dae53275,Common Data Service for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,POWERAPPS_PER_USER_GCC,8f55b472-f8bf-40a9-be30-e29919d4ddfe,Power Apps per User Plan for Government +Power Apps Premium for Government,POWERAPPS_PER_USER_GCC,8e4c6baa-f2ff-4884-9c38-93785d0d7ba1,Flow_PowerApps_PerUser_GCC,8e3eb3bd-bc99-4221-81b8-8b8bc882e128,Power Automate for Power Apps per User Plan for GCC PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,DYN365_CDS_P1_GOV,ce361df2-f2a5-4713-953f-4050ba09aad8,Common Data Service for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government PowerApps Plan 1 for Government,POWERAPPS_P1_GOV,eca22b68-b31f-4e9c-a20c-4d40287bc5dd,FLOW_P1_GOV,774da41c-a8b3-47c1-8322-b9c1ab68be9f,Power Automate (Plan 1) for Government @@ -4810,26 +4929,26 @@ Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4c Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE Project Online With Project for Office 365,PROJECTONLINE_PLAN_2,f82a60b8-1ee3-4cfb-a4fe-1c6a53c2656c,SWAY,a23b959c-7ce8-4e57-9140-b90eb88a9e97,SWAY -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 -Project Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,COMMON DATA SERVICE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,POWER AUTOMATE FOR PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,PROJECT P1 +Planner Plan 1,PROJECT_P1,beb6439c-caad-48d3-bf46-0c82871e12be,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,DYN365_CDS_FOR_PROJECT_P1,a6f677b3-62a6-4644-93e7-2a85d240845e,Common Data Service for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,Power_Automate_For_Project_P1,00283e6b-2bd8-440f-a2d5-87358e4c89a1,Power Automate for Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,PROJECT_P1,4a12c688-56c6-461a-87b1-30d6f32136f9,Project P1 Project Plan 1 (for Department),PROJECT_PLAN1_DEPT,84cd610f-a3f8-4beb-84ab-d9d2c902c6c9,SHAREPOINTSTANDARD,c7699d2e-19aa-44de-8edf-1736da088ca1,SHAREPOINT STANDARD -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 -Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,Office for the web +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_CLIENT_SUBSCRIPTION,fafd7243-e5c1-4a3a-9e40-495efcb1d3c3,Project Online Desktop Client +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINT_PROJECT,fe71d6c3-a2ea-4499-9778-da042bf08063,Project Online Service +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,PROJECT_PROFESSIONAL,818523f5-016b-4355-9be8-ed6944946ea7,Project P3 +Planner and Project Plan 3,PROJECTPROFESSIONAL,53818b1b-4a27-454b-8896-0dba576410e6,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,DYN365_CDS_PROJECT,50554c47-71d9-49fd-bc54-42a2765c555c,Common Data Service for Project Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Project Plan 3 (for Department),PROJECT_PLAN3_DEPT,46102f44-d912-47e7-b0ca-1bd7b70ada3b,FLOW_FOR_PROJECT,fa200448-008c-4acb-abd4-ea106ed2199d,Flow for Project @@ -4948,13 +5067,13 @@ Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,OneDrive for Business (Basic) Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,Visio Desktop App Visio Plan 2_USGOV_GCCHIGH,VISIOCLIENT_USGOV_GCCHIGH,80e52531-ad7f-44ea-abc3-28e389462f1b,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,Visio Web App -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP -Visio Online Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 1,VISIOONLINE_PLAN1,4b244418-9658-4451-a2b8-b5e2b364e9bd,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,EXCHANGE FOUNDATION +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,ONEDRIVE_BASIC,da792a53-cbc0-4184-a10d-e544dd34b3c1,ONEDRIVE FOR BUSINESS BASIC +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIO_CLIENT_SUBSCRIPTION,663a804f-1c30-4ff0-9915-9db84f0d1cea,VISIO DESKTOP APP +Visio Plan 2,VISIOCLIENT,c5928f49-12ba-48f7-ada3-0d743a3601d5,VISIOONLINE,2bdbaf8f-738f-4ac7-9234-3c3ee2ce7d0f,VISIO WEB APP Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,EXCHANGE FOUNDATION FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,ONEDRIVE_BASIC_GOV,98709c2e-96b5-4244-95f5-a0ebe139fb8a,ONEDRIVE FOR BUSINESS BASIC FOR GOVERNMENT Visio Plan 2 for GCC,VISIOCLIENT_GOV,4ae99959-6b0f-43b0-b1ce-68146001bdba,VISIO_CLIENT_SUBSCRIPTION_GOV,f85945f4-7a55-4009-bc39-6a5f14a8eac1,VISIO DESKTOP APP FOR Government diff --git a/Modules/CippExtensions/Public/Extension Functions/Add-HuduAssetLayoutM365Field.ps1 b/Modules/CippExtensions/Public/Extension Functions/Add-HuduAssetLayoutField.ps1 similarity index 58% rename from Modules/CippExtensions/Public/Extension Functions/Add-HuduAssetLayoutM365Field.ps1 rename to Modules/CippExtensions/Public/Extension Functions/Add-HuduAssetLayoutField.ps1 index 5ab07cbc3887..8669019b3321 100644 --- a/Modules/CippExtensions/Public/Extension Functions/Add-HuduAssetLayoutM365Field.ps1 +++ b/Modules/CippExtensions/Public/Extension Functions/Add-HuduAssetLayoutField.ps1 @@ -1,20 +1,24 @@ -function Add-HuduAssetLayoutM365Field { +function Add-HuduAssetLayoutField { Param( - $AssetLayoutId + $AssetLayoutId, + $Label = 'Microsoft 365', + $FieldType = 'RichText', + $Position = 0, + $ShowInList = $false ) $M365Field = @{ - position = 0 - label = 'Microsoft 365' - field_type = 'RichText' - show_in_list = $false + position = $Position + label = $Label + field_type = $FieldType + show_in_list = $ShowInList required = $false expiration = $false } $AssetLayout = Get-HuduAssetLayouts -LayoutId $AssetLayoutId - if ($AssetLayout.fields.label -contains 'Microsoft 365') { + if ($AssetLayout.fields.label -contains $Label) { return $AssetLayout } diff --git a/Modules/CippExtensions/Public/Extension Functions/Get-ExtensionMapping.ps1 b/Modules/CippExtensions/Public/Extension Functions/Get-ExtensionMapping.ps1 index 6a0ac35728c6..c81a8cdbf453 100644 --- a/Modules/CippExtensions/Public/Extension Functions/Get-ExtensionMapping.ps1 +++ b/Modules/CippExtensions/Public/Extension Functions/Get-ExtensionMapping.ps1 @@ -4,12 +4,5 @@ function Get-ExtensionMapping { ) $Table = Get-CIPPTable -TableName CippMapping - $Mapping = @{} - Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Extension)Mapping'" | ForEach-Object { - $Mapping[$_.RowKey] = @{ - label = "$($_.IntegrationName)" - value = "$($_.IntegrationId)" - } - } - return [PSCustomObject]$Mapping -} \ No newline at end of file + return Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Extension)Mapping'" +} diff --git a/Modules/CippExtensions/Public/Extension Functions/Set-ExtensionFieldMapping.ps1 b/Modules/CippExtensions/Public/Extension Functions/Set-ExtensionFieldMapping.ps1 index 52d59ab12d77..4228bfd77e1f 100644 --- a/Modules/CippExtensions/Public/Extension Functions/Set-ExtensionFieldMapping.ps1 +++ b/Modules/CippExtensions/Public/Extension Functions/Set-ExtensionFieldMapping.ps1 @@ -8,7 +8,7 @@ function Set-ExtensionFieldMapping { $TriggerMetadata ) - foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + foreach ($Mapping in ([pscustomobject]$Request.Body).psobject.properties) { $AddObject = @{ PartitionKey = "$($Extension)FieldMapping" RowKey = "$($mapping.name)" @@ -21,4 +21,4 @@ function Set-ExtensionFieldMapping { $Result = [pscustomobject]@{'Results' = 'Successfully edited mapping table.' } Return $Result -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/HIBP/Get-BreachInfo.ps1 b/Modules/CippExtensions/Public/HIBP/Get-BreachInfo.ps1 new file mode 100644 index 000000000000..f90f478b0e70 --- /dev/null +++ b/Modules/CippExtensions/Public/HIBP/Get-BreachInfo.ps1 @@ -0,0 +1,19 @@ +function Get-BreachInfo { + [CmdletBinding()] + param( + [Parameter()] + $TenantFilter, + [Parameter()]$Domain + + ) + if ($TenantFilter) { + $Data = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter | ForEach-Object { + Invoke-RestMethod -Uri "https://geoipdb.azurewebsites.net/api/Breach?func=domain&domain=$($_.id)" + } + return $Data + } else { + $data = Invoke-RestMethod -Uri "https://geoipdb.azurewebsites.net/api/Breach?func=domain&domain=$($domain)&format=breachlist" + return $Data + } + +} diff --git a/Modules/CippExtensions/Public/HIBP/Get-HIBPAuth.ps1 b/Modules/CippExtensions/Public/HIBP/Get-HIBPAuth.ps1 new file mode 100644 index 000000000000..ec2d5dacbea0 --- /dev/null +++ b/Modules/CippExtensions/Public/HIBP/Get-HIBPAuth.ps1 @@ -0,0 +1,17 @@ +function Get-HIBPAuth { + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = (Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'HIBP' and RowKey eq 'HIBP'").APIKey + } else { + $null = Connect-AzAccount -Identity + $VaultName = $WEBSITE_OWNER_NAME -like '3e625d35-bf18-4e55*' ? 'hibp-kv' : ($ENV:WEBSITE_DEPLOYMENT_ID -split '-')[0] + $Secret = Get-AzKeyVaultSecret -VaultName $VaultName -Name 'HIBP' -AsPlainText + } + + return @{ + 'User-Agent' = "CIPP-$($ENV:TenantID)" + 'Accept' = 'application/json' + 'api-version' = '3' + 'hibp-api-key' = $Secret + } +} diff --git a/Modules/CippExtensions/Public/HIBP/Get-HIBPConnectionTest.ps1 b/Modules/CippExtensions/Public/HIBP/Get-HIBPConnectionTest.ps1 new file mode 100644 index 000000000000..2cbf90eb7e8e --- /dev/null +++ b/Modules/CippExtensions/Public/HIBP/Get-HIBPConnectionTest.ps1 @@ -0,0 +1,8 @@ +function Get-HIBPConnectionTest { + $uri = 'https://haveibeenpwned.com/api/v3/subscription/status' + try { + Invoke-RestMethod -Uri $uri -Headers (Get-HIBPAuth) + } catch { + throw "Failed to connect to HIBP: $($_.Exception.Message)" + } +} diff --git a/Modules/CippExtensions/Public/HIBP/Get-HIBPRequest.ps1 b/Modules/CippExtensions/Public/HIBP/Get-HIBPRequest.ps1 new file mode 100644 index 000000000000..1de419c98064 --- /dev/null +++ b/Modules/CippExtensions/Public/HIBP/Get-HIBPRequest.ps1 @@ -0,0 +1,24 @@ +function Get-HIBPRequest { + [CmdletBinding()] + param( + [Parameter()] + $endpoint + ) + $uri = "https://haveibeenpwned.com/api/v3/$endpoint" + try { + return Invoke-RestMethod -Uri $uri -Headers (Get-HIBPAuth) + } catch { + if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 404) { + return @() + } elseif ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 429) { + Write-Host 'Rate limited hit for hibp.' + return @{ + Wait = ($_.Exception.Response.headers | Where-Object -Property key -EQ 'Retry-After').value + 'rate-limit' = $true + } + } else { + throw "Failed to connect to HIBP: $($_.Exception.Message)" + } + } + throw "Failed to connect to HIBP after $maxRetries retries." +} diff --git a/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1 b/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1 new file mode 100644 index 000000000000..96ce636256d0 --- /dev/null +++ b/Modules/CippExtensions/Public/HIBP/New-BreachTenantSearch.ps1 @@ -0,0 +1,36 @@ +function New-BreachTenantSearch { + [CmdletBinding()] + param ( + [Parameter()]$TenantFilter, + [Parameter()][switch]$Force + ) + + $Table = Get-CIPPTable -TableName UserBreaches + $LatestBreach = Get-BreachInfo -TenantFilter $TenantFilter + + $usersResults = foreach ($domain in $LatestBreach) { + $ExistingBreaches = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$TenantFilter'" + if ($null -eq $domain.result) { + Write-Host "No breaches found for domain $($domain.domain)" + continue + } + $SumOfBreaches = ($LatestBreach | Measure-Object -Sum -Property found).sum + if ($ExistingBreaches.sum -eq $SumOfBreaches -and $Force.IsPresent -eq $false) { + Write-Host "No new breaches found for tenant $TenantFilter" + continue + } + + @{ + RowKey = $domain.domain + PartitionKey = $TenantFilter + breaches = "$($LatestBreach.Result | ConvertTo-Json -Depth 10 -Compress)" + sum = $SumOfBreaches + } + } + + #Add user breaches to table + if ($usersResults) { + $entity = Add-CIPPAzDataTableEntity @Table -Entity $usersResults -Force + return $LatestBreach.Result + } +} diff --git a/Modules/CippExtensions/Public/Halo/Get-HaloMapping.ps1 b/Modules/CippExtensions/Public/Halo/Get-HaloMapping.ps1 index 9add516bc763..787159880e16 100644 --- a/Modules/CippExtensions/Public/Halo/Get-HaloMapping.ps1 +++ b/Modules/CippExtensions/Public/Halo/Get-HaloMapping.ps1 @@ -21,9 +21,22 @@ function Get-HaloMapping { Add-CIPPAzDataTableEntity @CIPPMapping -Entity $MigrateRows -Force } - $Mappings = Get-ExtensionMapping -Extension 'Halo' + $ExtensionMappings = Get-ExtensionMapping -Extension 'Halo' $Tenants = Get-Tenants -IncludeErrors + + $Mappings = foreach ($Mapping in $ExtensionMappings) { + $Tenant = $Tenants | Where-Object { $_.RowKey -eq $Mapping.RowKey } + if ($Tenant) { + [PSCustomObject]@{ + TenantId = $Tenant.customerId + Tenant = $Tenant.displayName + TenantDomain = $Tenant.defaultDomainName + IntegrationId = $Mapping.IntegrationId + IntegrationName = $Mapping.IntegrationName + } + } + } $Table = Get-CIPPTable -TableName Extensionsconfig try { $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json -ea stop).HaloPSA @@ -53,11 +66,10 @@ function Get-HaloMapping { } } $MappingObj = [PSCustomObject]@{ - Tenants = @($Tenants) Companies = @($HaloClients) Mappings = $Mappings } return $MappingObj -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/Halo/Set-HaloMapping.ps1 b/Modules/CippExtensions/Public/Halo/Set-HaloMapping.ps1 index 8827e099e3c3..fb8c0c51585e 100644 --- a/Modules/CippExtensions/Public/Halo/Set-HaloMapping.ps1 +++ b/Modules/CippExtensions/Public/Halo/Set-HaloMapping.ps1 @@ -8,12 +8,12 @@ function Set-HaloMapping { Get-CIPPAzDataTableEntity @CIPPMapping -Filter "PartitionKey eq 'HaloMapping'" | ForEach-Object { Remove-AzDataTableEntity -Force @CIPPMapping -Entity $_ } - foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + foreach ($Mapping in $Request.Body) { $AddObject = @{ PartitionKey = 'HaloMapping' - RowKey = "$($mapping.name)" - IntegrationId = "$($mapping.value.value)" - IntegrationName = "$($mapping.value.label)" + RowKey = "$($mapping.TenantId)" + IntegrationId = "$($mapping.IntegrationId)" + IntegrationName = "$($mapping.IntegrationName)" } Add-CIPPAzDataTableEntity @CIPPMapping -Entity $AddObject -Force @@ -23,4 +23,4 @@ function Set-HaloMapping { $Result = [pscustomobject]@{'Results' = 'Successfully edited mapping table.' } Return $Result -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/Hudu/Connect-HuduAPI.ps1 b/Modules/CippExtensions/Public/Hudu/Connect-HuduAPI.ps1 index 05c2f9b1e78f..433bbe8547f5 100644 --- a/Modules/CippExtensions/Public/Hudu/Connect-HuduAPI.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Connect-HuduAPI.ps1 @@ -12,6 +12,12 @@ function Connect-HuduAPI { $null = Connect-AzAccount -Identity $APIKey = (Get-AzKeyVaultSecret -VaultName $keyvaultname -Name 'Hudu' -AsPlainText) } + # Add logic to check if we're using CloudFlare Tunnel (if Hudu.CFEnabled checkbox is checked from Extensions.json). If the checkbox is checked, pull CloudFlare ClientID and API Key and add as a header + if ($Configuration.CFEnabled) { + $CFClientID = (Get-AzKeyVaultSecret -VaultName $keyvaultname -Name 'CloudFlareClientID' -AsPlainText) + $CFAPIKey = (Get-AzKeyVaultSecret -VaultName $keyvaultname -Name 'CloudFlareAPIKey' -AsPlainText) + New-HuduCustomHeaders -Headers @{"CF-Access-Client-Id" = "$CFClientID"; "CF-Access-Client-Secret" = "$CFAPIKey"} + } New-HuduBaseURL -BaseURL $Configuration.BaseURL New-HuduAPIKey -ApiKey $APIKey } diff --git a/Modules/CippExtensions/Public/Hudu/Get-HuduMapping.ps1 b/Modules/CippExtensions/Public/Hudu/Get-HuduMapping.ps1 index 7ffbddfa57a0..622dfa10765f 100644 --- a/Modules/CippExtensions/Public/Hudu/Get-HuduMapping.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Get-HuduMapping.ps1 @@ -4,8 +4,22 @@ function Get-HuduMapping { $CIPPMapping ) - $Mappings = Get-ExtensionMapping -Extension 'Hudu' + $ExtensionMappings = Get-ExtensionMapping -Extension 'Hudu' + $Tenants = Get-Tenants -IncludeErrors + + $Mappings = foreach ($Mapping in $ExtensionMappings) { + $Tenant = $Tenants | Where-Object { $_.RowKey -eq $Mapping.RowKey } + if ($Tenant) { + [PSCustomObject]@{ + TenantId = $Tenant.customerId + Tenant = $Tenant.displayName + TenantDomain = $Tenant.defaultDomainName + IntegrationId = $Mapping.IntegrationId + IntegrationName = $Mapping.IntegrationName + } + } + } $Tenants = Get-Tenants -IncludeErrors $Table = Get-CIPPTable -TableName Extensionsconfig try { @@ -31,7 +45,6 @@ function Get-HuduMapping { } } $MappingObj = [PSCustomObject]@{ - Tenants = @($Tenants) Companies = @($HuduCompanies) Mappings = $Mappings } diff --git a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 index 7eae2f462326..f30721b8d303 100644 --- a/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Invoke-HuduExtensionSync.ps1 @@ -56,7 +56,9 @@ function Invoke-HuduExtensionSync { try { if (![string]::IsNullOrEmpty($PeopleLayoutId)) { - $null = Add-HuduAssetLayoutM365Field -AssetLayoutId $PeopleLayoutId + # Add required fields to People Layout + $null = Add-HuduAssetLayoutField -AssetLayoutId $PeopleLayoutId -Label 'Microsoft 365' + $null = Add-HuduAssetLayoutField -AssetLayoutId $PeopleLayoutId -Label 'Email Address' -Position 1 -ShowInList $true -FieldType 'Text' $CreateUsers = $Configuration.CreateMissingUsers $PeopleLayout = Get-HuduAssetLayouts -Id $PeopleLayoutId if ($PeopleLayout.id) { @@ -81,7 +83,7 @@ function Invoke-HuduExtensionSync { try { if (![string]::IsNullOrEmpty($DeviceLayoutId)) { - $null = Add-HuduAssetLayoutM365Field -AssetLayoutId $DeviceLayoutId + $null = Add-HuduAssetLayoutField -AssetLayoutId $DeviceLayoutId $CreateDevices = $Configuration.CreateMissingDevices $DesktopsLayout = Get-HuduAssetLayouts -Id $DeviceLayoutId if ($DesktopsLayout.id) { diff --git a/Modules/CippExtensions/Public/Hudu/Set-HuduMapping.ps1 b/Modules/CippExtensions/Public/Hudu/Set-HuduMapping.ps1 index d5ca71df0ae4..1f8ba6c37d88 100644 --- a/Modules/CippExtensions/Public/Hudu/Set-HuduMapping.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Set-HuduMapping.ps1 @@ -8,19 +8,18 @@ function Set-HuduMapping { Get-CIPPAzDataTableEntity @CIPPMapping -Filter "PartitionKey eq 'HuduMapping'" | ForEach-Object { Remove-AzDataTableEntity -Force @CIPPMapping -Entity $_ } - foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + foreach ($Mapping in $Request.Body) { $AddObject = @{ PartitionKey = 'HuduMapping' - RowKey = "$($mapping.name)" - IntegrationId = "$($mapping.value.value)" - IntegrationName = "$($mapping.value.label)" + RowKey = "$($mapping.TenantId)" + IntegrationId = "$($mapping.IntegrationId)" + IntegrationName = "$($mapping.IntegrationName)" } Add-CIPPAzDataTableEntity @CIPPMapping -Entity $AddObject -Force - Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' } $Result = [pscustomobject]@{'Results' = 'Successfully edited mapping table.' } Return $Result -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneOrgMapping.ps1 index 24c7e6405560..7bdba1ebef18 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneOrgMapping.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneOrgMapping.ps1 @@ -6,23 +6,22 @@ function Get-NinjaOneOrgMapping { try { $Tenants = Get-Tenants -IncludeErrors - $Filter = "PartitionKey eq 'NinjaOrgsMapping'" - $MigrateRows = Get-AzDataTableEntity @CIPPMapping -Filter $Filter | ForEach-Object { - #$Mappings | Add-Member -NotePropertyName $_.RowKey -NotePropertyValue @{ label = "$($_.NinjaOneName)"; value = "$($_.NinjaOne)" } - [PSCustomObject]@{ - RowKey = $_.RowKey - IntegrationName = $_.NinjaOneName - IntegrationId = $_.NinjaOne - PartitionKey = 'NinjaOneMapping' - } - Remove-AzDataTableEntity @CIPPMapping -Entity $_ - } + $ExtensionMappings = Get-ExtensionMapping -Extension 'NinjaOne' - if (($MigrateRows | Measure-Object).Count -gt 0) { - Add-AzDataTableEntity @CIPPMapping -Entity $MigrateRows -Force - } + $Tenants = Get-Tenants -IncludeErrors - $Mappings = Get-ExtensionMapping -Extension 'NinjaOne' + $Mappings = foreach ($Mapping in $ExtensionMappings) { + $Tenant = $Tenants | Where-Object { $_.RowKey -eq $Mapping.RowKey } + if ($Tenant) { + [PSCustomObject]@{ + TenantId = $Tenant.customerId + Tenant = $Tenant.displayName + TenantDomain = $Tenant.defaultDomainName + IntegrationId = $Mapping.IntegrationId + IntegrationName = $Mapping.IntegrationName + } + } + } #Get Available Tenants #Get available Ninja clients @@ -53,11 +52,10 @@ function Get-NinjaOneOrgMapping { } $MappingObj = [PSCustomObject]@{ - Tenants = @($Tenants) Companies = @($NinjaOrgs | Sort-Object name) Mappings = $Mappings } return $MappingObj -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 index 6b5687d6059f..443e3d49042b 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneOrgMapping.ps1 @@ -15,7 +15,7 @@ function Invoke-NinjaOneOrgMapping { } #Get Available Tenants - $Tenants = Get-Tenants + $Tenants = Get-Tenants -IncludeErrors #Get available Ninja clients $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-AzDataTableEntity @Table).config | ConvertFrom-Json).NinjaOne diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index a17940bd369b..696190855327 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -763,7 +763,7 @@ function Invoke-NinjaOneTenantSync { $DeviceLinksData = @( @{ Name = 'Entra ID' - Link = "https://entra.microsoft.com/$($Customer.defaultDomainName)/#view/Microsoft_AAD_Devices/DeviceDetailsMenuBlade/~/Properties/deviceId/$($Device.azureADDeviceId)/deviceId/" + Link = "https://entra.microsoft.com/$($Customer.defaultDomainName)/#view/Microsoft_AAD_Devices/DeviceDetailsMenuBlade/~/Properties/deviceId/$($Device.azureADDeviceId)" Icon = 'fab fa-microsoft' }, @{ @@ -1748,7 +1748,7 @@ function Invoke-NinjaOneTenantSync { }, @{ Name = 'Compliance Portal' - Link = "https://compliance.microsoft.com/?tid=$($Customer.CustomerId)" + Link = "https://purview.microsoft.com/?tid=$($Customer.CustomerId)" Icon = 'fas fa-user-shield' }, @{ diff --git a/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneFieldMapping.ps1 b/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneFieldMapping.ps1 index 87d243b8cda1..abba4fc1a022 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneFieldMapping.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneFieldMapping.ps1 @@ -8,24 +8,18 @@ function Set-NinjaOneFieldMapping { ) $SettingsTable = Get-CIPPTable -TableName NinjaOneSettings - $AddObject = @{ - PartitionKey = 'NinjaConfig' - RowKey = 'CIPPURL' - 'SettingValue' = ([System.Uri]$TriggerMetadata.Headers.referer).Host - } - Add-AzDataTableEntity @SettingsTable -Entity $AddObject -Force - - foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + foreach ($Mapping in $Request.Body.PSObject.Properties) { $AddObject = @{ PartitionKey = 'NinjaOneFieldMapping' RowKey = "$($mapping.name)" IntegrationId = "$($mapping.value.value)" IntegrationName = "$($mapping.value.label)" } + Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' } $Result = [pscustomobject]@{'Results' = 'Successfully edited mapping table.' } Return $Result -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneOrgMapping.ps1 b/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneOrgMapping.ps1 index d58c6093f6f2..d501714d1a6d 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneOrgMapping.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Set-NinjaOneOrgMapping.ps1 @@ -9,17 +9,19 @@ function Set-NinjaOneOrgMapping { Get-CIPPAzDataTableEntity @CIPPMapping -Filter "PartitionKey eq 'NinjaOneMapping'" | ForEach-Object { Remove-AzDataTableEntity -Force @CIPPMapping -Entity $_ } - foreach ($Mapping in ([pscustomobject]$Request.body.mappings).psobject.properties) { + foreach ($Mapping in $Request.Body) { $AddObject = @{ PartitionKey = 'NinjaOneMapping' - RowKey = "$($mapping.name)" - IntegrationId = "$($mapping.value.value)" - IntegrationName = "$($mapping.value.label)" + RowKey = "$($mapping.TenantId)" + IntegrationId = "$($mapping.IntegrationId)" + IntegrationName = "$($mapping.IntegrationName)" } - Add-AzDataTableEntity @CIPPMapping -Entity $AddObject -Force + + Add-CIPPAzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' } $Result = [pscustomobject]@{'Results' = 'Successfully edited mapping table.' } Return $Result -} \ No newline at end of file +} diff --git a/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 b/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 index 0a29234f0071..566bf8c3cb45 100644 --- a/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 +++ b/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 @@ -1,11 +1,11 @@ function New-PwPushLink { - [CmdletBinding()] + [CmdletBinding(SupportsShouldProcess)] Param( $Payload ) $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).PWPush - if ($Configuration.Enabled) { + if ($Configuration.Enabled -eq $true) { Set-PwPushConfig -Configuration $Configuration $PushParams = @{ Payload = $Payload @@ -14,15 +14,17 @@ function New-PwPushLink { if ($Configuration.ExpireAfterViews) { $PushParams.ExpireAfterViews = $Configuration.ExpireAfterViews } if ($Configuration.DeletableByViewer) { $PushParams.DeletableByViewer = $Configuration.DeletableByViewer } try { - $Link = New-Push @PushParams | Select-Object Link, LinkRetrievalStep - if ($Configuration.RetrievalStep) { - $Link.Link = $Link.LinkRetrievalStep + if ($PSCmdlet.ShouldProcess('Create a new PwPush link')) { + $Link = New-Push @PushParams + if ($Configuration.RetrievalStep) { + return $Link.LinkRetrievalStep + } + return $Link.Link } - $Link | Select-Object -ExpandProperty Link } catch { $LogData = [PSCustomObject]@{ - 'Response' = $Link - 'Exception' = Get-CippException -Exception $_ + 'Response' = $Link + 'Exception' = Get-CippException -Exception $_ } Write-LogMessage -API PwPush -Message "Failed to create a new PwPush link: $($_.Exception.Message)" -Sev 'Error' -LogData $LogData throw 'Failed to create a new PwPush link, check the log book for more details' diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebAuthentication.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebAuthentication.ps1 new file mode 100644 index 000000000000..457308343457 --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebAuthentication.ps1 @@ -0,0 +1,27 @@ +function Get-SherwebAuthentication { + $Table = Get-CIPPTable -TableName Extensionsconfig + $Config = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).Sherweb + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $APIKey = (Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Sherweb' and RowKey eq 'Sherweb'").APIKey + } else { + $keyvaultname = ($ENV:WEBSITE_DEPLOYMENT_ID -split '-')[0] + $null = Connect-AzAccount -Identity + $APIKey = (Get-AzKeyVaultSecret -VaultName $keyvaultname -Name 'sherweb' -AsPlainText) + } + $AuthBody = @{ + client_id = $Config.clientId + client_secret = $APIKey + scope = 'service-provider' + grant_type = 'client_credentials' + } + + $Token = (Invoke-RestMethod -Uri 'https://api.sherweb.com/auth/oidc/connect/token' -Method POST -Body $AuthBody).access_token + $authHeader = @{ + Authorization = "Bearer $Token" + 'Ocp-Apim-Subscription-Key' = $Config.SubscriptionKey + } + + return $authHeader +} diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 new file mode 100644 index 000000000000..a7cd3a8f406a --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCatalog.ps1 @@ -0,0 +1,16 @@ +function Get-SherwebCatalog { + param( + [Parameter(Mandatory = $false)] + [string]$CustomerId, + [string]$TenantFilter + ) + if ($TenantFilter) { + Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { + Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" + $CustomerId = $_.IntegrationId + } + } + $AuthHeader = Get-SherwebAuthentication + $SubscriptionsList = Invoke-RestMethod -Uri "https://api.sherweb.com/service-provider/v1/customer-catalogs/$CustomerId" -Method GET -Headers $AuthHeader + return $SubscriptionsList.catalogItems +} diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 new file mode 100644 index 000000000000..1c260ccd2cfd --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCurrentSubscription.ps1 @@ -0,0 +1,28 @@ +function Get-SherwebCurrentSubscription { + param( + [Parameter(Mandatory = $false)] + [string]$TenantFilter, + [string]$CustomerId, + [string]$SKU, + [string]$ProductName + ) +if($TenantFilter){ + Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { + write-host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" + $CustomerId = $_.IntegrationId + } +} + $AuthHeader = Get-SherwebAuthentication + $Uri = "https://api.sherweb.com/service-provider/v1/billing/subscriptions/details?customerId=$CustomerId" + $SubscriptionDetails = Invoke-RestMethod -Uri $Uri -Method GET -Headers $AuthHeader + + $AllSubscriptions = $SubscriptionDetails.items + + if ($SKU) { + return $AllSubscriptions | Where-Object { $_.sku -eq $SKU } + } elseif ($ProductName) { + return $AllSubscriptions | Where-Object { $_.productName -eq $ProductName } + } else { + return $AllSubscriptions + } +} diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 new file mode 100644 index 000000000000..b315ee4ae057 --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomerConfiguration.ps1 @@ -0,0 +1,23 @@ +function Get-SherwebCustomerConfiguration { + param( + [Parameter(Mandatory = $true)] + [string]$CustomerId, + [string]$TenantFilter + ) + if ($TenantFilter) { + Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { + Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" + $CustomerId = $_.IntegrationId + } + } + $AuthHeader = Get-SherwebAuthentication + $Uri = "https://api.sherweb.com/service-provider/v1/customers/$($CustomerId)/platforms-configurations/" + $CustomerConfig = Invoke-RestMethod -Uri $Uri -Method GET -Headers $AuthHeader + $customerPlatforms = foreach ($Config in $CustomerConfig.configuredPlatforms) { + #https://api.sherweb.com/service-provider/v1/customers/{customerId}/platforms/{platformId}/details + $Uri = "https://api.sherweb.com/service-provider/v1/customers/$($CustomerId)/platforms/$($Config.id)/details" + Invoke-RestMethod -Uri $Uri -Method GET -Headers $AuthHeader + } + return $customerPlatforms + +} diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomers.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomers.ps1 new file mode 100644 index 000000000000..53af35e197ad --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebCustomers.ps1 @@ -0,0 +1,5 @@ +function Get-SherwebCustomers { + $AuthHeader = Get-SherwebAuthentication + $CustomersList = Invoke-RestMethod -Uri 'https://api.sherweb.com/service-provider/v1/customers' -Method GET -Headers $AuthHeader + return $CustomersList.items +} diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebMapping.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebMapping.ps1 new file mode 100644 index 000000000000..1fa0f5cbb0f6 --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebMapping.ps1 @@ -0,0 +1,47 @@ +function Get-SherwebMapping { + [CmdletBinding()] + param ( + $CIPPMapping + ) + + $ExtensionMappings = Get-ExtensionMapping -Extension 'Sherweb' + + $Tenants = Get-Tenants -IncludeErrors + $Mappings = foreach ($Mapping in $ExtensionMappings) { + $Tenant = $Tenants | Where-Object { $_.customerId -eq $Mapping.RowKey } + if ($Tenant) { + [PSCustomObject]@{ + TenantId = $Tenant.customerId + Tenant = $Tenant.displayName + TenantDomain = $Tenant.defaultDomainName + IntegrationId = $Mapping.IntegrationId + IntegrationName = $Mapping.IntegrationName + } + } + } + try { + $SherwebCustomers = Get-SherwebCustomers | ForEach-Object { + [PSCustomObject]@{ + name = $_.displayName + value = "$($_.id)" + } + } + } catch { + $Message = if ($_.ErrorDetails.Message) { + Get-NormalizedError -Message $_.ErrorDetails.Message + } else { + $_.Exception.message + } + + Write-LogMessage -Message "Could not get Sherweb Companies, error: $Message " -Level Error -tenant 'CIPP' -API 'SherwebMapping' + $SherwebCustomers = @(@{name = "Could not get Sherweb Companies, error: $Message"; value = '-1' }) + } + + $MappingObj = [PSCustomObject]@{ + Companies = @($SherwebCustomers) + Mappings = @($Mappings) + } + + return $MappingObj + +} diff --git a/Modules/CippExtensions/Public/Sherweb/Get-SherwebOrderStatus.ps1 b/Modules/CippExtensions/Public/Sherweb/Get-SherwebOrderStatus.ps1 new file mode 100644 index 000000000000..ca5a91cd71b3 --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Get-SherwebOrderStatus.ps1 @@ -0,0 +1,10 @@ +function Get-SherwebOrderStatus { + param( + [Parameter(Mandatory = $true)] + [string]$RequestTrackingId + ) + $AuthHeader = Get-SherwebAuthentication + $Uri = "https://api.sherweb.com/service-provider/v1/tracking/$RequestTrackingId" + $Tracking = Invoke-RestMethod -Uri $Uri -Method GET -Headers $AuthHeader + return $Tracking +} diff --git a/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 b/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 new file mode 100644 index 000000000000..cfdfc21c8148 --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Remove-SherwebSubscription.ps1 @@ -0,0 +1,23 @@ +function Remove-SherwebSubscription { + param( + [Parameter(Mandatory = $false)] + [string]$CustomerId, + [Parameter(Mandatory = $true)] + [string[]]$SubscriptionIds, + [string]$TenantFilter + ) + if ($TenantFilter) { + Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { + Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" + $CustomerId = $_.IntegrationId + } + } + $AuthHeader = Get-SherwebAuthentication + $Body = ConvertTo-Json -Depth 10 -InputObject @{ + subscriptionIds = @($SubscriptionIds) + } + + $Uri = "https://api.sherweb.com/service-provider/v1/billing/subscriptions/cancellations?customerId=$CustomerId" + $Cancel = Invoke-RestMethod -Uri $Uri -Method POST -Headers $AuthHeader -Body $Body -ContentType 'application/json' + return $Cancel +} diff --git a/Modules/CippExtensions/Public/Sherweb/Set-SherwebMapping.ps1 b/Modules/CippExtensions/Public/Sherweb/Set-SherwebMapping.ps1 new file mode 100644 index 000000000000..f9f7b25e07b7 --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Set-SherwebMapping.ps1 @@ -0,0 +1,26 @@ +function Set-SherwebMapping { + [CmdletBinding()] + param ( + $CIPPMapping, + $APIName, + $Request + ) + Get-CIPPAzDataTableEntity @CIPPMapping -Filter "PartitionKey eq 'SherwebMapping'" | ForEach-Object { + Remove-AzDataTableEntity -Force @CIPPMapping -Entity $_ + } + foreach ($Mapping in $Request.Body) { + Write-Host "Adding mapping for $($mapping.IntegrationId)" + $AddObject = @{ + PartitionKey = 'SherwebMapping' + RowKey = "$($mapping.TenantId)" + IntegrationId = "$($mapping.IntegrationId)" + IntegrationName = "$($mapping.IntegrationName)" + } + + Add-CIPPAzDataTableEntity @CIPPMapping -Entity $AddObject -Force + Write-LogMessage -API $APINAME -user $request.headers.'x-ms-client-principal' -message "Added mapping for $($mapping.name)." -Sev 'Info' + } + $Result = [pscustomobject]@{'Results' = 'Successfully edited mapping table.' } + + Return $Result +} diff --git a/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 b/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 new file mode 100644 index 000000000000..057a198966ac --- /dev/null +++ b/Modules/CippExtensions/Public/Sherweb/Set-SherwebSubscription.ps1 @@ -0,0 +1,71 @@ +function Set-SherwebSubscription { + param( + [Parameter(Mandatory = $false)] + [string]$CustomerId, + [Parameter(Mandatory = $true)] + [string]$SKU, + [int]$Quantity, + [int]$Add, + [int]$Remove, + [string]$TenantFilter + ) + if ($TenantFilter) { + Get-ExtensionMapping -Extension 'Sherweb' | Where-Object { $_.RowKey -eq $TenantFilter } | ForEach-Object { + Write-Host "Extracted customer id from tenant filter - It's $($_.IntegrationId)" + $CustomerId = $_.IntegrationId + } + } + $AuthHeader = Get-SherwebAuthentication + $ExistingSubscription = Get-SherwebCurrentSubscription -CustomerId $CustomerId -SKU $SKU + + if (-not $ExistingSubscription) { + if ($Add -or $Remove) { + throw "Unable to Add or Remove. No existing subscription with SKU '$SKU' found." + } + + if (-not $Quantity -or $Quantity -le 0) { + throw 'A valid Quantity must be specified to create a new subscription when none currently exists.' + } + $OrderBody = ConvertTo-Json -Depth 10 -InputObject @{ + cartItems = @( + @{ + sku = $SKU + quantity = $Quantity + } + ) + orderedBy = 'CIPP-API' + } + $OrderUri = "https://api.sherweb.com/service-provider/v1/orders?customerId=$CustomerId" + $Order = Invoke-RestMethod -Uri $OrderUri -Method POST -Headers $AuthHeader -Body $OrderBody -ContentType 'application/json' + return $Order + + } else { + $SubscriptionId = $ExistingSubscription[0].id + $CurrentQuantity = $ExistingSubscription[0].quantity + + if ($Add) { + $FinalQuantity = $CurrentQuantity + $Add + } elseif ($Remove) { + $FinalQuantity = $CurrentQuantity - $Remove + if ($FinalQuantity -lt 0) { + throw "Cannot remove more licenses than currently allocated. Current: $CurrentQuantity, Attempting to remove: $Remove." + } + } else { + if (-not $Quantity -or $Quantity -le 0) { + throw 'A valid Quantity must be specified if Add/Remove are not used.' + } + $FinalQuantity = $Quantity + } + $Body = ConvertTo-Json -Depth 10 -InputObject @{ + subscriptionAmendmentParameters = @( + @{ + subscriptionId = $SubscriptionId + newQuantity = $FinalQuantity + } + ) + } + $Uri = "https://api.sherweb.com/service-provider/v1/billing/subscriptions/amendments?customerId=$CustomerId" + $Update = Invoke-RestMethod -Uri $Uri -Method POST -Headers $AuthHeader -Body $Body -ContentType 'application/json' + return $Update + } +} diff --git a/Tools/Update-StandardsComments.ps1 b/Tools/Update-StandardsComments.ps1 index c47bb4d4a6cb..c3d7c9cc30f1 100644 --- a/Tools/Update-StandardsComments.ps1 +++ b/Tools/Update-StandardsComments.ps1 @@ -118,7 +118,25 @@ foreach ($Standard in $StandardsInfo) { $NewComment.Add(" Run the Tools\Update-StandardsComments.ps1 script to update this comment block`r`n") # -Online help link $NewComment.Add(" .LINK`r`n") - $NewComment.Add(" https://docs.cipp.app/user-documentation/tenant/standards/edit-standards`r`n") + $DocsLink = 'https://docs.cipp.app/user-documentation/tenant/standards/list-standards/' + + switch ($Standard.cat) { + 'Global Standards' { $DocsLink += 'global-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + 'Entra (AAD) Standards' { $DocsLink += 'entra-aad-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + 'Exchange Standards' { $DocsLink += 'exchange-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + 'Defender Standards' { $DocsLink += 'defender-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + 'Intune Standards' { $DocsLink += 'intune-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + 'SharePoint Standards' { $DocsLink += 'sharepoint-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + 'Teams Standards' { $DocsLink += 'teams-standards#' + $Standard.impact.ToLower() -replace ' ', '-' } + Default {} + } + + switch ($Standard.impact) { + condition { } + Default {} + } + + $NewComment.Add(" $DocsLink`r`n") $NewComment.Add(' #>') # Write the new comment block to the file diff --git a/profile.ps1 b/profile.ps1 index 173bc71ffb8c..5230a3b5561d 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -53,7 +53,6 @@ Write-Information "Function: $($env:WEBSITE_SITE_NAME) Version: $CurrentVersion" $LastStartup = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'Version' and RowKey eq '$($env:WEBSITE_SITE_NAME)'" if (!$LastStartup -or $CurrentVersion -ne $LastStartup.Version) { Write-Information "Version has changed from $($LastStartup.Version ?? 'None') to $CurrentVersion" - Clear-CippDurables if ($LastStartup) { $LastStartup.Version = $CurrentVersion } else { @@ -63,7 +62,12 @@ if (!$LastStartup -or $CurrentVersion -ne $LastStartup.Version) { Version = $CurrentVersion } } - Update-AzDataTableEntity @Table -Entity $LastStartup + Update-AzDataTableEntity @Table -Entity $LastStartup -Force + try { + Clear-CippDurables + } catch { + Write-LogMessage -message 'Failed to clear durables after update' -LogData (Get-CippException -Exception $_) -Sev 'Error' + } } # Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell. # Enable-AzureRmAlias diff --git a/version_latest.txt b/version_latest.txt index db0785f27378..a8a188756826 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -6.5.3 +7.1.2