diff --git a/.editorconfig b/.editorconfig index b0c2c5085172..eecafcffcb70 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,12 +8,12 @@ insert_final_newline = true [*.{ps1, psd1, psm1}] indent_size = 4 -end_of_line = crlf +end_of_line = lf trim_trailing_whitespace = true [*.json] indent_size = 2 -end_of_line = crlf +end_of_line = lf trim_trailing_whitespace = true [*.{md, txt}] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..6b7b1bb62a3f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +* text=lf + +*.txt text eol=crlf +*.md text eol=crlf + +*.ps1 text eol=lf +*.psd1 text eol=lf +*.psm1 text eol=lf + +*.json text eol=lf + +*.png binary +*.jpg binary diff --git a/.github/workflows/dev_cippjta72.yml b/.github/workflows/dev_api.yml similarity index 84% rename from .github/workflows/dev_cippjta72.yml rename to .github/workflows/dev_api.yml index 23c0cd3668d6..47181a0b2f68 100644 --- a/.github/workflows/dev_cippjta72.yml +++ b/.github/workflows/dev_api.yml @@ -1,30 +1,31 @@ -# 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 - cippjta72 - -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: 'cippjta72' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_5B44448119C645C099EE192346D7433A }} \ No newline at end of file +# 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: dev_api + +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: + if: github.event.repository.fork == false && github.event_name == 'push' + 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: 'cippjta72' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_5B44448119C645C099EE192346D7433A }} diff --git a/.github/workflows/dev_cippjta72-proc.yml b/.github/workflows/dev_api_proc.yml similarity index 83% rename from .github/workflows/dev_cippjta72-proc.yml rename to .github/workflows/dev_api_proc.yml index 530581163549..61591158e040 100644 --- a/.github/workflows/dev_cippjta72-proc.yml +++ b/.github/workflows/dev_api_proc.yml @@ -1,30 +1,31 @@ -# 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 - cippjta72-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: 'cippjta72-proc' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_A53AC5C52A55459DA0A3D8F1716638CB }} \ No newline at end of file +# 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: dev_api_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: + if: github.event.repository.fork == false && github.event_name == 'push' + 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: 'cippjta72-proc' + slot-name: 'Production' + package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_A53AC5C52A55459DA0A3D8F1716638CB }} diff --git a/.github/workflows/dev_cipp44thq.yml b/.github/workflows/dev_cipp44thq.yml deleted file mode 100644 index f21a9de0596d..000000000000 --- a/.github/workflows/dev_cipp44thq.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 - cipp44thq - -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: 'cipp44thq' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_2EBCA6FEB5E54403AE417859C5D28817 }} \ No newline at end of file diff --git a/.github/workflows/dev_cippbcaom.yml b/.github/workflows/dev_cippbcaom.yml deleted file mode 100644 index c4bcf1198e74..000000000000 --- a/.github/workflows/dev_cippbcaom.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 - cippbcaom - -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: 'cippbcaom' - slot-name: 'Production' - package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }} - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_0FE8CACBBF7D409DAAF132988BECEC4B }} \ No newline at end of file diff --git a/CIPPTimers.json b/CIPPTimers.json index 12988efc9c8c..51b0debdbb9f 100644 --- a/CIPPTimers.json +++ b/CIPPTimers.json @@ -28,19 +28,29 @@ { "Id": "44a40668-ed71-403c-8c26-b32e320086ad", "Command": "Start-AuditLogOrchestrator", - "Description": "Orchestrator to process audit logs", + "Description": "Orchestrator to download audit logs", "Cron": "0 */15 * * * *", "Priority": 2, "RunOnProcessor": true, "PreferredProcessor": "auditlog", "IsSystem": true }, + { + "Id": "01cd512a-15c4-44a9-b8cb-1e5d879cfd2d", + "Command": "Start-AuditLogProcessingOrchestrator", + "Description": "Orchestrator to process audit logs", + "Cron": "0 */15 * * * *", + "Priority": 3, + "RunOnProcessor": true, + "PreferredProcessor": "auditlog", + "IsSystem": true + }, { "Id": "03475c86-4314-4d7b-90f2-5a0639e3899b", "Command": "Start-AuditLogSearchCreation", "Description": "Timer to create audit log searches", "Cron": "0 */30 * * * *", - "Priority": 3, + "Priority": 4, "RunOnProcessor": true, "PreferredProcessor": "auditlog", "IsSystem": true diff --git a/Config/CyberEssentials.BPATemplate.json b/Config/CyberEssentials.BPATemplate.json index 31d25321dc88..5d340abd2a11 100644 --- a/Config/CyberEssentials.BPATemplate.json +++ b/Config/CyberEssentials.BPATemplate.json @@ -54,7 +54,7 @@ "StoreAs": "JSON", "API": "Graph", "ExtractFields": ["windowsProtectionState"], - "parameters": {}, + "Parameters": {}, "URL": "https://graph.microsoft.com/beta/deviceManagement/managedDevices?$expand=windowsProtectionState" }, { diff --git a/ConversionTable.csv b/ConversionTable.csv index 4463224224a6..e38e1d159430 100644 --- a/ConversionTable.csv +++ b/ConversionTable.csv @@ -228,9 +228,9 @@ Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE_NOPREREQ,2cf302fe-62db-4e20-b573-e0998b1208b5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,CRMINSTANCE_GCC,483cc331-f4df-4a3b-b8ca-fe1a247569f6,Microsoft Dynamics CRM Online Instance Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,CDS_FIELD_SERVICE_CONTRACTOR_GCC,2457fe40-65be-48a1-935f-924ad6e62dba,Common Data Service Field service Part Time Contractors for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government @@ -253,27 +253,27 @@ Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAG Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_CDS_RETAIL,93cc200d-a47f-4c56-aec1-83f8b0d0425a,Common Data Service for Dynamics 365 Retail Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,FLOW_FOR_IOM_USL,9e6d1620-dce9-4655-8933-af8fa5bccc9c,Data Integration for IOM with Power Automate USL Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_RETAIL,117e3aa0-8d08-4a19-a6a5-90b7a96e2128,Dynamics 365 Commerce -Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_ACC_PROTECTION,4c00c16c-0304-4421-b598-555c3e78edcb,Dynamics 365 Fraud Protection - Account Protection Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_LOSS_PREVENTION,ecc62904-fa88-4552-a62c-fe582fb31444,Dynamics 365 Fraud Protection - Loss Prevention Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_PURCH_PROTECTION,d703990f-006e-459b-b8dd-1267c4533a22,Dynamics 365 Fraud Protection - Purchase Protection @@ -296,14 +296,14 @@ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,POWERAPPS FOR DYNAMICS 365 Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,DYNAMICS 365 FOR CUSTOMER SERVICE Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,D365_FIELD_SERVICE_ATTACH,55c9148b-d5f0-4101-b5a0-b2727cfc0916,Dynamics 365 for Field Service Attach Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Field Service Enterprise Edition,DYN365_ENTERPRISE_FIELD_SERVICE,c7d15985-e746-4f01-b113-20b575898250,DYN365_ENTERPRISE_FIELD_SERVICE,8c66ef8a-177f-4c0d-853c-d4f219331d09,Dynamics 365 for Field Service @@ -393,13 +393,13 @@ Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54- Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Forms_Pro_SalesEnt_GCC,33850b82-0a37-4ebb-a0b2-ee163facd716,Microsoft Dynamics 365 Customer Voice for Sales Enterprise for GCC Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User @@ -411,12 +411,12 @@ Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3 Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,DYN365_SALES_INSIGHTS,fedc185f-0711-4cc0-80ed-0a92da1a8384,Dynamics 365 AI for Sales (Embedded) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials @@ -432,7 +432,7 @@ Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd9 Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_CDS_SUPPLYCHAINMANAGEMENT,b6a8b974-2956-4e14-ae81-f0384c363528,Common Data Service for Dynamics 365 Supply Chain Management Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM -Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,D365_SCM_Attach,b21c777f-c2d5-486e-88f6-fc0a3e474271,Dynamics 365 for Supply Chain Management Attach Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Marketing Business Edition,DYN365_BUSINESS_MARKETING,238e2f8d-e429-4035-94db-6926be4ffe7b,DYN365_BUSINESS_Marketing,393a0c96-9ba1-4af0-8975-fa2f853a25ac,Dynamics 365 Marketing @@ -521,7 +521,7 @@ Dynamics 365 P1 Tria for Information Workers,DYN365_ENTERPRISE_P1_IW,338148b6-1b Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365CDSforProjectOperations,7df1d500-ca5c-4229-8cea-815bc88798c9,Common Data Service for Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperationsCDS,18fa3aba-b085-4105-87d7-55617b8585e6,Dynamics 365 Project Operations CDS Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperations,69f07c66-bee4-4222-b051-195095efee5b,Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 @@ -4797,18 +4797,18 @@ Power Pages authenticated users T2 min 100 units - 100 users/per site/month capa Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T2_min_100_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,7cae5432-61bb-48c3-b75c-831394ec13a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,DYN365_CDS_VIRAL,17ab22cd-a0b3-4536-910a-cb6eb12696c0,Common Data Service Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,POWER_PAGES_VTRIAL,6817d093-2d30-4249-8bd6-774f01efa78c,Power Pages vTrial for Makers @@ -5146,7 +5146,7 @@ Windows 365 Business 2 vCPU 4 GB 64 GB,CPC_B_2C_4RAM_64GB,42e6818f-8966-444b-b7a Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,Windows 365 Business 2 vCPU, 8 GB, 128 GB +Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,"Windows 365 Business 2 vCPU, 8 GB, 128 GB" Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) @@ -5177,14 +5177,14 @@ Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67 Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,CPC_B_8C_32RAM_512GB,4229a0b4-7f34-4835-b068-6dc8d10be57c,Windows 365 Business 8 vCPU 32 GB 512 GB -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,Windows 365 Business 16 vCPU, 64 GB, 512 GB -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,Windows 365 Business 16 vCPU, 64 GB, 1 TB +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,"Windows 365 Business 16 vCPU, 64 GB, 512 GB" +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,"Windows 365 Business 16 vCPU, 64 GB, 1 TB" Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,CPC_E_1C_2GB_64GB,86d70dbb-d4c6-4662-ba17-3014204cbb28,Windows 365 Enterprise 1 vCPU 2 GB 64 GB Windows 365 Enterprise 2 vCPU 4 GB 64 GB,CPC_E_2C_4GB_64GB,7bb14422-3b90-4389-a7be-f1b745fc037f,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation diff --git a/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 b/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 index 3bd121c0c1c6..509be7e36fc2 100644 --- a/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 @@ -20,7 +20,7 @@ function Add-CIPPAzDataTableEntity { 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) + #Write-Information ($SingleEnt | ConvertTo-Json) $largePropertyNames = [System.Collections.Generic.List[string]]::new() $entitySize = 0 @@ -137,14 +137,18 @@ function Add-CIPPAzDataTableEntity { 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 -Compress)))" - Add-AzDataTableEntity -Context $Context -Force:$Force -CreateTableIfNotExists:$CreateTableIfNotExists -Entity $row + $NewRow = [PSCustomObject]$row + Add-AzDataTableEntity -Context $Context -Force:$Force -CreateTableIfNotExists:$CreateTableIfNotExists -Entity $NewRow } } else { - Add-AzDataTableEntity -Context $Context -Force:$Force -CreateTableIfNotExists:$CreateTableIfNotExists -Entity $SingleEnt + $NewEnt = [PSCustomObject]$SingleEnt + Add-AzDataTableEntity -Context $Context -Force:$Force -CreateTableIfNotExists:$CreateTableIfNotExists -Entity $NewEnt } } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-Warning ("AzBobbyTables Error") + Write-Information ($SingleEnt | ConvertTo-Json) throw "Error processing entity: $ErrorMessage Linenumber: $($_.InvocationInfo.ScriptLineNumber)" } } else { diff --git a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 index ed2bfd4da7c0..f4c22a7e626e 100644 --- a/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPScheduledTask.ps1 @@ -23,6 +23,10 @@ function Add-CIPPScheduledTask { $Parameters = [System.Collections.Hashtable]@{} foreach ($Key in $task.Parameters.PSObject.Properties.Name) { $Param = $task.Parameters.$Key + + if ($null -eq $Param -or $Param -eq '' -or ($Param | Measure-Object).Count -eq 0) { + continue + } if ($Param -is [System.Collections.IDictionary] -or $Param.Key) { $ht = @{} foreach ($p in $Param.GetEnumerator()) { diff --git a/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearches.ps1 b/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearches.ps1 index 1aac0b36eeab..693011c25aba 100644 --- a/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearches.ps1 +++ b/Modules/CIPPCore/Public/AuditLogs/Get-CippAuditLogSearches.ps1 @@ -31,7 +31,6 @@ function Get-CippAuditLogSearches { return @() } $Queries = New-GraphBulkRequest -Requests @($BulkRequests) -AsApp $true -TenantId $TenantFilter | Select-Object -ExpandProperty body - $Queries = $Queries | Where-Object { $PendingQueries.RowKey -contains $_.id -and $_.status -eq 'succeeded' } } else { $Queries = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/auditLog/queries' -AsApp $true -tenantid $TenantFilter diff --git a/Modules/CIPPCore/Public/AuditLogs/New-CIPPAuditLogSearchResultsCache.ps1 b/Modules/CIPPCore/Public/AuditLogs/New-CIPPAuditLogSearchResultsCache.ps1 new file mode 100644 index 000000000000..76701ac05736 --- /dev/null +++ b/Modules/CIPPCore/Public/AuditLogs/New-CIPPAuditLogSearchResultsCache.ps1 @@ -0,0 +1,103 @@ +function New-CIPPAuditLogSearchResultsCache { + <# + .SYNOPSIS + Cache audit log search results for more efficient processing + .DESCRIPTION + Retrieves audit log searches for a tenant, processes them, and stores the results in a cache table. + Also tracks performance metrics for download and processing times. + .PARAMETER TenantFilter + The tenant to filter on. + #> + param ( + [Parameter(Mandatory = $true)] + [string]$TenantFilter, + [string]$SearchId + ) + try { + $FailedDownloadsTable = Get-CippTable -TableName 'FailedAuditLogDownloads' + $fourHoursAgo = (Get-Date).AddHours(-4).ToUniversalTime() + $failedEntity = Get-CIPPAzDataTableEntity @FailedDownloadsTable -Filter "PartitionKey eq '$TenantFilter' and SearchId eq '$SearchId' and Timestamp ge datetime'$($fourHoursAgo.ToString('yyyy-MM-ddTHH:mm:ssZ'))'" + + if ($failedEntity) { + $message = "Skipping search ID: $SearchId for tenant: $TenantFilter - Previous attempt failed within the last 4 hours" + Write-LogMessage -API 'AuditLog' -tenant $TenantFilter -message $message -Sev 'Info' + Write-Information $message + exit 0 + } + } catch { + Write-Information "Error checking for failed downloads: $($_.Exception.Message)" + } + + try { + Write-Information "Starting audit log cache process for tenant: $TenantFilter" + $CacheWebhooksTable = Get-CippTable -TableName 'CacheWebhooks' + $CacheWebhookStatsTable = Get-CippTable -TableName 'CacheWebhookStats' + # Check if we haven't already downloaded this search by checking the cache table + $searchEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and SearchId eq '$SearchId'" + if ($searchEntity) { + Write-Information "Search ID: $SearchId already cached for tenant: $TenantFilter" + exit 0 + } + + # Record this attempt in the FailedAuditLogDownloads table BEFORE starting the download + # This way, if the function is killed before completion, the record will remain + try { + $FailedDownloadsTable = Get-CippTable -TableName 'FailedAuditLogDownloads' + $attemptId = [guid]::NewGuid().ToString() + $failedEntity = @{ + RowKey = $attemptId + PartitionKey = $TenantFilter + SearchId = $SearchId + ErrorMessage = 'Download attempt in progress' + } + Add-CIPPAzDataTableEntity @FailedDownloadsTable -Entity $failedEntity -Force + Write-Information "Recorded download attempt for search ID: $SearchId, tenant: $TenantFilter" + } catch { + Write-Information "Failed to record download attempt: $($_.Exception.Message)" + } + + $downloadStartTime = Get-Date + try { + Write-Information "Processing search ID: $($SearchId) for tenant: $TenantFilter" + $searchResults = Get-CippAuditLogSearchResults -TenantFilter $TenantFilter -QueryId $SearchId + foreach ($searchResult in $searchResults) { + $cacheEntity = @{ + RowKey = $searchResult.id + PartitionKey = $TenantFilter + SearchId = $SearchId + JSON = [string]($searchResult | ConvertTo-Json -Depth 10) + } + Add-CIPPAzDataTableEntity @CacheWebhooksTable -Entity $cacheEntity -Force + } + Write-Information "Successfully cached search ID: $($SearchId) for tenant: $TenantFilter" + try { + $FailedDownloadsTable = Get-CippTable -TableName 'FailedAuditLogDownloads' + $failedEntities = Get-CIPPAzDataTableEntity @FailedDownloadsTable -Filter "PartitionKey eq '$TenantFilter' and SearchId eq '$SearchId'" + if ($failedEntities) { + Remove-AzDataTableEntity @FailedDownloadsTable -Entity $failedEntities -Force + Write-Information "Removed failed download records for search ID: $SearchId, tenant: $TenantFilter" + } + } catch { + Write-Information "Failed to remove download attempt record: $($_.Exception.Message)" + } + } catch { + throw $_ + } + + $downloadEndTime = Get-Date + $downloadSeconds = ($downloadEndTime - $downloadStartTime).TotalSeconds + + $statsEntity = @{ + RowKey = $TenantFilter + PartitionKey = 'Stats' + DownloadSecs = [string]$downloadSeconds + SearchCount = [string]($searchResults ? $searchResults.Count : 0) + } + Add-CIPPAzDataTableEntity @CacheWebhookStatsTable -Entity $statsEntity -Force + Write-Information "Completed audit log cache process for tenant: $TenantFilter. Download time: $downloadSeconds seconds" + return ($searchResults ? $searchResults.Count : 0) + } catch { + Write-Information "Error in New-CIPPAuditLogSearchResultsCache for tenant: $TenantFilter. Error: $($_.Exception.Message)" + throw $_ + } +} diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 index 7738d9babd37..f4f80f4cb5dc 100644 --- a/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 +++ b/Modules/CIPPCore/Public/CippQueue/Invoke-ListCippQueue.ps1 @@ -10,9 +10,6 @@ function Invoke-ListCippQueue { if ($Request) { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' } $CippQueue = Get-CippTable -TableName 'CippQueue' diff --git a/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 b/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 index afd30af62654..a9c2a9081c6a 100644 --- a/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 +++ b/Modules/CIPPCore/Public/CippQueue/Invoke-RemoveCippQueue.ps1 @@ -10,9 +10,6 @@ function Invoke-RemoveCippQueue { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - $CippQueue = Get-CippTable -TableName 'CippQueue' Clear-AzDataTable @CippQueue $CippQueueTasks = Get-CippTable -TableName 'CippQueueTasks' diff --git a/Modules/CIPPCore/Public/ConversionTable.csv b/Modules/CIPPCore/Public/ConversionTable.csv index 4463224224a6..e38e1d159430 100644 --- a/Modules/CIPPCore/Public/ConversionTable.csv +++ b/Modules/CIPPCore/Public/ConversionTable.csv @@ -228,9 +228,9 @@ Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE_NOPREREQ,2cf302fe-62db-4e20-b573-e0998b1208b5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,CRMINSTANCE_GCC,483cc331-f4df-4a3b-b8ca-fe1a247569f6,Microsoft Dynamics CRM Online Instance Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,CDS_FIELD_SERVICE_CONTRACTOR_GCC,2457fe40-65be-48a1-935f-924ad6e62dba,Common Data Service Field service Part Time Contractors for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government @@ -253,27 +253,27 @@ Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAG Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_CDS_RETAIL,93cc200d-a47f-4c56-aec1-83f8b0d0425a,Common Data Service for Dynamics 365 Retail Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,FLOW_FOR_IOM_USL,9e6d1620-dce9-4655-8933-af8fa5bccc9c,Data Integration for IOM with Power Automate USL Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_RETAIL,117e3aa0-8d08-4a19-a6a5-90b7a96e2128,Dynamics 365 Commerce -Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_ACC_PROTECTION,4c00c16c-0304-4421-b598-555c3e78edcb,Dynamics 365 Fraud Protection - Account Protection Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_LOSS_PREVENTION,ecc62904-fa88-4552-a62c-fe582fb31444,Dynamics 365 Fraud Protection - Loss Prevention Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_PURCH_PROTECTION,d703990f-006e-459b-b8dd-1267c4533a22,Dynamics 365 Fraud Protection - Purchase Protection @@ -296,14 +296,14 @@ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,POWERAPPS FOR DYNAMICS 365 Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,DYNAMICS 365 FOR CUSTOMER SERVICE Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,D365_FIELD_SERVICE_ATTACH,55c9148b-d5f0-4101-b5a0-b2727cfc0916,Dynamics 365 for Field Service Attach Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Field Service Enterprise Edition,DYN365_ENTERPRISE_FIELD_SERVICE,c7d15985-e746-4f01-b113-20b575898250,DYN365_ENTERPRISE_FIELD_SERVICE,8c66ef8a-177f-4c0d-853c-d4f219331d09,Dynamics 365 for Field Service @@ -393,13 +393,13 @@ Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54- Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Forms_Pro_SalesEnt_GCC,33850b82-0a37-4ebb-a0b2-ee163facd716,Microsoft Dynamics 365 Customer Voice for Sales Enterprise for GCC Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User @@ -411,12 +411,12 @@ Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3 Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,DYN365_SALES_INSIGHTS,fedc185f-0711-4cc0-80ed-0a92da1a8384,Dynamics 365 AI for Sales (Embedded) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials @@ -432,7 +432,7 @@ Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd9 Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_CDS_SUPPLYCHAINMANAGEMENT,b6a8b974-2956-4e14-ae81-f0384c363528,Common Data Service for Dynamics 365 Supply Chain Management Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM -Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,D365_SCM_Attach,b21c777f-c2d5-486e-88f6-fc0a3e474271,Dynamics 365 for Supply Chain Management Attach Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Marketing Business Edition,DYN365_BUSINESS_MARKETING,238e2f8d-e429-4035-94db-6926be4ffe7b,DYN365_BUSINESS_Marketing,393a0c96-9ba1-4af0-8975-fa2f853a25ac,Dynamics 365 Marketing @@ -521,7 +521,7 @@ Dynamics 365 P1 Tria for Information Workers,DYN365_ENTERPRISE_P1_IW,338148b6-1b Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365CDSforProjectOperations,7df1d500-ca5c-4229-8cea-815bc88798c9,Common Data Service for Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperationsCDS,18fa3aba-b085-4105-87d7-55617b8585e6,Dynamics 365 Project Operations CDS Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperations,69f07c66-bee4-4222-b051-195095efee5b,Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 @@ -4797,18 +4797,18 @@ Power Pages authenticated users T2 min 100 units - 100 users/per site/month capa Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T2_min_100_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,7cae5432-61bb-48c3-b75c-831394ec13a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,DYN365_CDS_VIRAL,17ab22cd-a0b3-4536-910a-cb6eb12696c0,Common Data Service Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,POWER_PAGES_VTRIAL,6817d093-2d30-4249-8bd6-774f01efa78c,Power Pages vTrial for Makers @@ -5146,7 +5146,7 @@ Windows 365 Business 2 vCPU 4 GB 64 GB,CPC_B_2C_4RAM_64GB,42e6818f-8966-444b-b7a Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,Windows 365 Business 2 vCPU, 8 GB, 128 GB +Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,"Windows 365 Business 2 vCPU, 8 GB, 128 GB" Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) @@ -5177,14 +5177,14 @@ Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67 Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,CPC_B_8C_32RAM_512GB,4229a0b4-7f34-4835-b068-6dc8d10be57c,Windows 365 Business 8 vCPU 32 GB 512 GB -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,Windows 365 Business 16 vCPU, 64 GB, 512 GB -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,Windows 365 Business 16 vCPU, 64 GB, 1 TB +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,"Windows 365 Business 16 vCPU, 64 GB, 512 GB" +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,"Windows 365 Business 16 vCPU, 64 GB, 1 TB" Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,CPC_E_1C_2GB_64GB,86d70dbb-d4c6-4662-ba17-3014204cbb28,Windows 365 Enterprise 1 vCPU 2 GB 64 GB Windows 365 Enterprise 2 vCPU 4 GB 64 GB,CPC_E_2C_4GB_64GB,7bb14422-3b90-4389-a7be-f1b745fc037f,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 index 3c47e4eb5c51..a116159aba13 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Graph Requests/Push-ListGraphRequestQueue.ps1 @@ -21,9 +21,9 @@ function Push-ListGraphRequestQueue { Write-Information "Queue Table: $TableName" $Table = Get-CIPPTable -TableName $TableName - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}'" -f $PartitionKey, $Item.TenantFilter + $Filter = "PartitionKey eq '{0}' and (RowKey eq '{1}' or OriginalEntityId eq '{1}')" -f $PartitionKey, $Item.TenantFilter Write-Information "Filter: $Filter" - $Existing = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + $Existing = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey, OriginalEntityId if ($Existing) { $null = Remove-AzDataTableEntity -Force @Table -Entity $Existing } @@ -41,26 +41,25 @@ function Push-ListGraphRequestQueue { $RawGraphRequest = try { Get-GraphRequestList @GraphRequestParams } catch { + $CippException = Get-CippException -Exception $_.Exception [PSCustomObject]@{ Tenant = $Item.TenantFilter - CippStatus = "Could not connect to tenant. $($_.Exception.message)" + CippStatus = "Could not connect to tenant. $($CippException.NormalizedMessage)" + CippException = [string]($CippException | ConvertTo-Json -Depth 10 -Compress) } } - $GraphResults = foreach ($Request in $RawGraphRequest) { - $Json = ConvertTo-Json -Depth 10 -Compress -InputObject $Request - $RowKey = $Request.id ?? (New-Guid).Guid - [PSCustomObject]@{ - Tenant = [string]$Item.TenantFilter - QueueId = [string]$Item.QueueId - QueueType = [string]$Item.QueueType - RowKey = [string]$RowKey - PartitionKey = [string]$PartitionKey - Data = [string]$Json - } + $Json = ConvertTo-Json -Depth 10 -Compress -InputObject $RawGraphRequest + $GraphResults = [PSCustomObject]@{ + PartitionKey = [string]$PartitionKey + RowKey = [string]$Item.TenantFilter + QueueId = [string]$Item.QueueId + QueueType = [string]$Item.QueueType + Data = [string]$Json } Add-CIPPAzDataTableEntity @Table -Entity $GraphResults -Force | Out-Null } catch { - Write-Information "Queue Error: $($_.Exception.Message)" + Write-Warning "Queue Error: $($_.Exception.Message)" + #Write-Information ($GraphResults | ConvertTo-Json -Depth 10 -Compress) throw $_ } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index 4317db419974..460ea3456778 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -10,6 +10,8 @@ function Push-ExecScheduledCommand { $Table = Get-CippTable -tablename 'ScheduledTasks' $task = $Item.TaskInfo $commandParameters = $Item.Parameters | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashtable + $Tenant = $Item.Parameters.TenantFilter ?? $Item.TaskInfo.Tenant + $TenantInfo = Get-Tenants -TenantFilter $Tenant $Function = Get-Command -Name $Item.Command if ($null -eq $Function) { @@ -21,7 +23,7 @@ function Push-ExecScheduledCommand { Results = "$Results" TaskState = $State } - Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): The command $($Item.Command) does not exist." -sev Error + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $Tenant -tenantid $TenantInfo.customerId -message "Failed to execute task $($task.Name): The command $($Item.Command) does not exist." -sev Error return } @@ -40,8 +42,7 @@ function Push-ExecScheduledCommand { Write-Host "Failed to remove parameters: $($_.Exception.Message)" } - $tenant = $Item.Parameters.TenantFilter - Write-Host "Started Task: $($Item.Command) for tenant: $tenant" + Write-Host "Started Task: $($Item.Command) for tenant: $Tenant" try { try { @@ -85,27 +86,27 @@ function Push-ExecScheduledCommand { Results = "$errorMessage" TaskState = $State } - Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to execute task $($task.Name): $errorMessage" -sev Error -LogData (Get-CippExceptionData -Exception $_.Exception) + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $Tenant -tenantid $TenantInfo.customerId -message "Failed to execute task $($task.Name): $errorMessage" -sev Error -LogData (Get-CippExceptionData -Exception $_.Exception) } Write-Host 'Sending task results to target. Updating the task state.' if ($Results) { $TableDesign = '' $FinalResults = if ($results -is [array] -and $results[0] -is [string]) { $Results | ConvertTo-Html -Fragment -Property @{ l = 'Text'; e = { $_ } } } else { $Results | ConvertTo-Html -Fragment } - $HTML = $FinalResults -replace '', "This alert is for tenant $tenant.

$TableDesign
" | Out-String - $title = "$TaskType - $tenant - $($task.Name)" + $HTML = $FinalResults -replace '
', "This alert is for tenant $Tenant.

$TableDesign
" | Out-String + $title = "$TaskType - $Tenant - $($task.Name)" Write-Host 'Scheduler: Sending the results to the target.' Write-Host "The content of results is: $Results" switch -wildcard ($task.PostExecution) { - '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML -TenantFilter $tenant } - '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML -TenantFilter $tenant } + '*psa*' { Send-CIPPAlert -Type 'psa' -Title $title -HTMLContent $HTML -TenantFilter $Tenant } + '*email*' { Send-CIPPAlert -Type 'email' -Title $title -HTMLContent $HTML -TenantFilter $Tenant } '*webhook*' { $Webhook = [PSCustomObject]@{ - 'Tenant' = $tenant + 'Tenant' = $Tenant 'TaskInfo' = $Item.TaskInfo 'Results' = $Results } - Send-CIPPAlert -Type 'webhook' -Title $title -TenantFilter $tenant -JSONContent $($Webhook | ConvertTo-Json -Depth 20) + Send-CIPPAlert -Type 'webhook' -Title $title -TenantFilter $Tenant -JSONContent $($Webhook | ConvertTo-Json -Depth 20) } } } @@ -149,6 +150,6 @@ function Push-ExecScheduledCommand { } } if ($TaskType -ne 'Alert') { - Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Successfully executed task: $($task.Name)" -sev Info + Write-LogMessage -API 'Scheduler_UserTasks' -tenant $Tenant -tenantid $TenantInfo.customerId -message "Successfully executed task: $($task.Name)" -sev Info } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 index 08bbc50757f8..d465d57274cf 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-SchedulerCIPPNotifications.ps1 @@ -128,8 +128,8 @@ function Push-SchedulerCIPPNotifications { Add-CIPPAzDataTableEntity @Table -Entity $UpdateLogs -Force } } catch { - Write-Information "Could not send alerts to webhook: $($_.Exception.message)" - Write-LogMessage -API 'Alerts' -message "Could not send alerts to : $($_.Exception.message)" -tenant $Tenant -sev error + Write-Information "Could not send alerts to webhook $($config.webhook): $($_.Exception.message)" + Write-LogMessage -API 'Alerts' -message "Could not send alerts to webhook $($config.webhook): $($_.Exception.message)" -tenant $Tenant -sev error -LogData (Get-CippException -Exception $_) } if ($config.sendtoIntegration) { @@ -157,4 +157,4 @@ function Push-SchedulerCIPPNotifications { } -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 index 757180f3a0bd..20744662daa8 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogBundleProcessing.ps1 @@ -1,8 +1,8 @@ function Push-AuditLogBundleProcessing { Param($Item) - return # Disabled for now, as it's not used - + #return # Disabled for now, as it's not used + exit 0 try { $AuditBundleTable = Get-CippTable -tablename 'AuditLogBundles' $AuditLogBundle = Get-CIPPAzDataTableEntity @AuditBundleTable -Filter "PartitionKey eq '$($Item.TenantFilter)' and RowKey eq '$($Item.ContentId)'" diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 similarity index 57% rename from Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 rename to Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 index 4276b516c810..51556092951f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantDownload.ps1 @@ -1,10 +1,10 @@ -function Push-AuditLogTenant { +function Push-AuditLogTenantDownload { Param($Item) $ConfigTable = Get-CippTable -TableName 'WebhookRules' $TenantFilter = $Item.TenantFilter try { - Write-Information "Audit Logs: Processing $($TenantFilter)" + Write-Information "Audit Logs: Downloading $($TenantFilter)" # Get CIPP Url, cleanup legacy tasks $SchedulerConfig = Get-CippTable -TableName 'SchedulerConfig' $LegacyWebhookTasks = Get-CIPPAzDataTableEntity @SchedulerConfig -Filter "PartitionKey eq 'webhookcreation'" @@ -27,13 +27,13 @@ function Push-AuditLogTenant { $CIPPURL = $LegacyUrl } else { 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 + $CippConfig = @{ + PartitionKey = 'InstanceProperties' + RowKey = 'CIPPURL' + Value = [string]([System.Uri]$Request.Headers.'x-ms-original-url').Host + } + Add-AzDataTableEntity @CippConfigTable -Entity $CippConfig -Force + $CIPPURL = 'https://{0}' -f $CippConfig.Value } else { $CIPPURL = 'https://{0}' -f $CippConfig.Value } } @@ -45,20 +45,15 @@ function Push-AuditLogTenant { if ($Configuration) { try { $LogSearches = Get-CippAuditLogSearches -TenantFilter $TenantFilter -ReadyToProcess | Select-Object -First 10 - Write-Information ('Audit Logs: Found {0} searches, begin processing' -f $LogSearches.Count) + Write-Information ('Audit Logs: Found {0} searches, begin downloading' -f $LogSearches.Count) foreach ($Search in $LogSearches) { $SearchEntity = Get-CIPPAzDataTableEntity @LogSearchesTable -Filter "Tenant eq '$($TenantFilter)' and RowKey eq '$($Search.id)'" $SearchEntity.CippStatus = 'Processing' Add-CIPPAzDataTableEntity @LogSearchesTable -Entity $SearchEntity -Force try { - # Test the audit log rules against the search results - $AuditLogTest = Test-CIPPAuditLogRules -TenantFilter $TenantFilter -SearchId $Search.id - - $SearchEntity.CippStatus = 'Completed' - $MatchedRules = [string](ConvertTo-Json -Compress -InputObject $AuditLogTest.MatchedRules) - $SearchEntity | Add-Member -MemberType NoteProperty -Name MatchedRules -Value $MatchedRules -Force - $SearchEntity | Add-Member -MemberType NoteProperty -Name MatchedLogs -Value $AuditLogTest.MatchedLogs -Force - $SearchEntity | Add-Member -MemberType NoteProperty -Name TotalLogs -Value $AuditLogTest.TotalLogs -Force + Write-Information "Audit Log search: Processing search ID: $($Search.id) for tenant: $TenantFilter" + $Downloads = New-CIPPAuditLogSearchResultsCache -TenantFilter $TenantFilter -searchId $Search.id + $SearchEntity.CippStatus = 'Downloaded' } catch { if ($_.Exception.Message -match 'Request rate is large. More Request Units may be needed, so no changes were made. Please retry this request later.') { $SearchEntity.CippStatus = 'Pending' @@ -74,34 +69,17 @@ function Push-AuditLogTenant { $SearchEntity.CippStatus = 'Failed' Write-Information "Error processing audit log rules: $($_.Exception.Message)" } - $AuditLogTest = [PSCustomObject]@{ - DataToProcess = @() - } + } Add-CIPPAzDataTableEntity @LogSearchesTable -Entity $SearchEntity -Force - $DataToProcess = ($AuditLogTest).DataToProcess - Write-Information "Audit Logs: Data to process found: $($DataToProcess.count) items" - if ($DataToProcess) { - foreach ($AuditLog in $DataToProcess) { - Write-Information "Processing $($AuditLog.operation)" - $Webhook = @{ - Data = $AuditLog - CIPPURL = [string]$CIPPURL - TenantFilter = $TenantFilter - } - try { - Invoke-CippWebhookProcessing @Webhook - } catch { - Write-Information "Error processing webhook: $($_.Exception.Message)" - } - } - } } } catch { - Write-Information ( 'Audit Log search: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + Write-Information ('Audit Log search: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + exit 0 } } } catch { - Write-Information ( 'Push-AuditLogTenant: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + Write-Information ('Push-AuditLogTenant: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + exit 0 } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantProcess.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantProcess.ps1 new file mode 100644 index 000000000000..086adcaf37dc --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Webhooks/Push-AuditLogTenantProcess.ps1 @@ -0,0 +1,31 @@ +function Push-AuditLogTenantProcess { + Param($Item) + $TenantFilter = $Item.TenantFilter + $RowIds = $Item.RowIds + + try { + Write-Information "Audit Logs: Processing $($TenantFilter) with $($RowIds.Count) row IDs. We're processing id $($RowIds[0]) to $($RowIds[-1])" + + # Get the CacheWebhooks table + $CacheWebhooksTable = Get-CippTable -TableName 'CacheWebhooks' + # we do it this way because the rows can grow extremely large, if we get them all it might just hang for minutes at a time. + $Rows = foreach ($RowId in $RowIds) { + $CacheEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$RowId'" + if ($CacheEntity) { + $AuditData = $CacheEntity.JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + $AuditData + } + } + + if ($Rows.Count -gt 0) { + Write-Information "Retrieved $($Rows.Count) rows from cache for processing" + Test-CIPPAuditLogRules -TenantFilter $TenantFilter -Rows $Rows + exit 0 + } else { + Write-Information 'No rows found in cache for the provided row IDs' + exit 0 + } + } catch { + Write-Information ('Push-AuditLogTenant: Error {0} line {1} - {2}' -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) + } +} 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 4d59debe39f5..0de78563a5e8 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,6 +10,10 @@ Function Invoke-ExecAddAlert { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Severity = 'Alert' $Result = if ($Request.Body.sendEmailNow -or $Request.Body.sendWebhookNow -eq $true -or $Request.Body.writeLog -eq $true) { @@ -35,11 +39,11 @@ Function Invoke-ExecAddAlert { Send-CIPPAlert @CIPPAlert } if ($Request.Body.writeLog) { - Write-LogMessage -headers $Request.Headers -API 'Alerts' -message $Request.Body.text -Sev $Severity + Write-LogMessage -headers $Headers -API 'Alerts' -message $Request.Body.text -Sev $Severity 'Successfully generated alert.' } } else { - Write-LogMessage -headers $Request.Headers -API 'Alerts' -message $Request.Body.text -Sev $Severity + Write-LogMessage -headers $Headers -API 'Alerts' -message $Request.Body.text -Sev $Severity 'Successfully generated alert.' } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ 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 index 88080bdcf5b4..ecde857f328d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAzBobbyTables.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecAzBobbyTables.ps1 @@ -13,6 +13,10 @@ function Invoke-ExecAzBobbyTables { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $AllowList = @( 'Add-AzDataTableEntity' 'Update-AzDataTableEntity' 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 index dbf1d9de62de..972d03b87485 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCPVRefresh.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCPVRefresh.ps1 @@ -10,10 +10,11 @@ function Invoke-ExecCPVRefresh { CIPP.Core.ReadWrite #> [CmdletBinding()] - param( - $Request, - $TriggerMetadata - ) + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $InstanceId = Start-UpdatePermissionsOrchestrator 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 index a7f4e599579b..5ed10829e631 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCippFunction.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecCippFunction.ps1 @@ -12,6 +12,10 @@ function Invoke-ExecCippFunction { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $BlockList = @( 'Get-GraphToken' 'Get-GraphTokenFromCert' @@ -45,4 +49,4 @@ function Invoke-ExecCippFunction { 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 484bc24dab25..4cbfcda3b49d 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 @@ -8,8 +8,9 @@ function Invoke-ExecDurableFunctions { [CmdletBinding(SupportsShouldProcess = $true)] param($Request, $TriggerMetadata) - $APIName = 'ExecDurableStats' - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Collect info $StorageContext = New-AzStorageContext -ConnectionString $env:AzureWebJobsStorage 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 2cf918816be6..c0e78d9f845c 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 @@ -11,7 +11,8 @@ Function Invoke-ExecEditTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' try { $Table = Get-CippTable -tablename 'templates' 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 0cf94d30d806..45a616403714 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 @@ -11,7 +11,9 @@ Function Invoke-ExecGeoIPLookup { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $IP = $Request.Query.IP ?? $Request.Body.IP if (-not $IP) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGraphRequest.ps1 index dec61d0e5b25..d06367943d64 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGraphRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGraphRequest.ps1 @@ -1,111 +1,112 @@ using namespace System.Net Function Invoke-ExecGraphRequest { - <# + <# .FUNCTIONALITY Entrypoint #> - [CmdletBinding()] - param($Request, $TriggerMetadata) + [CmdletBinding()] + param($Request, $TriggerMetadata) - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - Function ConvertTo-FlatObject { - # https://evotec.xyz/powershell-converting-advanced-object-to-flat-object/ - MIT License - [CmdletBinding()] - Param ( - [Parameter(ValueFromPipeLine)][Object[]]$Objects, - [String]$Separator = '.', - [ValidateSet('', 0, 1)]$Base = 1, - [int]$Depth = 5, - [Parameter(DontShow)][String[]]$Path, - [Parameter(DontShow)][System.Collections.IDictionary] $OutputObject - ) - Begin { - $InputObjects = [System.Collections.Generic.List[Object]]::new() - } - Process { - foreach ($O in $Objects) { - $InputObjects.Add($O) + Function ConvertTo-FlatObject { + # https://evotec.xyz/powershell-converting-advanced-object-to-flat-object/ - MIT License + [CmdletBinding()] + Param ( + [Parameter(ValueFromPipeLine)][Object[]]$Objects, + [String]$Separator = '.', + [ValidateSet('', 0, 1)]$Base = 1, + [int]$Depth = 5, + [Parameter(DontShow)][String[]]$Path, + [Parameter(DontShow)][System.Collections.IDictionary] $OutputObject + ) + Begin { + $InputObjects = [System.Collections.Generic.List[Object]]::new() + } + Process { + foreach ($O in $Objects) { + $InputObjects.Add($O) + } + } + End { + If ($PSBoundParameters.ContainsKey('OutputObject')) { + $Object = $InputObjects[0] + $Iterate = [ordered] @{} + if ($null -eq $Object) { + #Write-Verbose -Message "ConvertTo-FlatObject - Object is null" + } elseif ($Object.GetType().Name -in 'String', 'DateTime', 'TimeSpan', 'Version', 'Enum') { + $Object = $Object.ToString() + } elseif ($Depth) { + $Depth-- + If ($Object -is [System.Collections.IDictionary]) { + $Iterate = $Object + } elseif ($Object -is [Array] -or $Object -is [System.Collections.IEnumerable]) { + $i = $Base + foreach ($Item in $Object.GetEnumerator()) { + $Iterate["$i"] = $Item + $i += 1 } - } - End { - If ($PSBoundParameters.ContainsKey('OutputObject')) { - $Object = $InputObjects[0] - $Iterate = [ordered] @{} - if ($null -eq $Object) { - #Write-Verbose -Message "ConvertTo-FlatObject - Object is null" - } elseif ($Object.GetType().Name -in 'String', 'DateTime', 'TimeSpan', 'Version', 'Enum') { - $Object = $Object.ToString() - } elseif ($Depth) { - $Depth-- - If ($Object -is [System.Collections.IDictionary]) { - $Iterate = $Object - } elseif ($Object -is [Array] -or $Object -is [System.Collections.IEnumerable]) { - $i = $Base - foreach ($Item in $Object.GetEnumerator()) { - $Iterate["$i"] = $Item - $i += 1 - } - } else { - foreach ($Prop in $Object.PSObject.Properties) { - if ($Prop.IsGettable) { - $Iterate["$($Prop.Name)"] = $Object.$($Prop.Name) - } - } - } - } - If ($Iterate.Keys.Count) { - foreach ($Key in $Iterate.Keys) { - ConvertTo-FlatObject -Objects @(, $Iterate["$Key"]) -Separator $Separator -Base $Base -Depth $Depth -Path ($Path + $Key) -OutputObject $OutputObject - } - } else { - $Property = $Path -Join $Separator - $OutputObject[$Property] = $Object - } - } elseif ($InputObjects.Count -gt 0) { - foreach ($ItemObject in $InputObjects) { - $OutputObject = [ordered]@{} - ConvertTo-FlatObject -Objects @(, $ItemObject) -Separator $Separator -Base $Base -Depth $Depth -Path $Path -OutputObject $OutputObject - [PSCustomObject] $OutputObject - } + } else { + foreach ($Prop in $Object.PSObject.Properties) { + if ($Prop.IsGettable) { + $Iterate["$($Prop.Name)"] = $Object.$($Prop.Name) + } } + } } - } - $TenantFilter = $Request.Query.TenantFilter - try { - if ($TenantFilter -ne 'AllTenants') { - $RawGraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Request.Query.Endpoint)" -tenantid $TenantFilter -NoPagination [boolean]$Request.query.DisablePagination -ComplexFilter + If ($Iterate.Keys.Count) { + foreach ($Key in $Iterate.Keys) { + ConvertTo-FlatObject -Objects @(, $Iterate["$Key"]) -Separator $Separator -Base $Base -Depth $Depth -Path ($Path + $Key) -OutputObject $OutputObject + } } else { - $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { - Import-Module '.\Modules\AzBobbyTables' - Import-Module '.\Modules\CIPPCore' - try { - $DefaultDomainName = $_.defaultDomainName - $TenantName = $_.displayName - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($using:Request.Query.Endpoint)" -tenantid $DefaultDomainName -NoPagination [boolean]$using:Request.query.DisablePagination -ComplexFilter | Select-Object @{ - label = 'Tenant' - expression = { $TenantName } - }, * - } catch { - continue - } - } - + $Property = $Path -Join $Separator + $OutputObject[$Property] = $Object + } + } elseif ($InputObjects.Count -gt 0) { + foreach ($ItemObject in $InputObjects) { + $OutputObject = [ordered]@{} + ConvertTo-FlatObject -Objects @(, $ItemObject) -Separator $Separator -Base $Base -Depth $Depth -Path $Path -OutputObject $OutputObject + [PSCustomObject] $OutputObject } - $GraphRequest = $RawGraphRequest | Where-Object -Property '@odata.context' -EQ $null | ConvertTo-FlatObject - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage + } + } + } + $TenantFilter = $Request.Query.TenantFilter + try { + if ($TenantFilter -ne 'AllTenants') { + $RawGraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($Request.Query.Endpoint)" -tenantid $TenantFilter -NoPagination [boolean]$Request.query.DisablePagination -ComplexFilter + } else { + $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { + Import-Module '.\Modules\AzBobbyTables' + Import-Module '.\Modules\CIPPCore' + try { + $DefaultDomainName = $_.defaultDomainName + $TenantName = $_.displayName + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/$($using:Request.Query.Endpoint)" -tenantid $DefaultDomainName -NoPagination [boolean]$using:Request.query.DisablePagination -ComplexFilter | Select-Object @{ + label = 'Tenant' + expression = { $TenantName } + }, * + } catch { + continue + } + } + } + $GraphRequest = $RawGraphRequest | Where-Object -Property '@odata.context' -EQ $null | ConvertTo-FlatObject + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecListBackup.ps1 index 013317b805b6..fe9fa4b02aae 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,23 +10,32 @@ Function Invoke-ExecListBackup { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $Type = $Request.Query.Type + $TenantFilter = $Request.Query.tenantFilter + $NameOnly = $Request.Query.NameOnly + $BackupName = $Request.Query.BackupName + $CippBackupParams = @{} - if ($Request.Query.Type) { - $CippBackupParams.Type = $Request.Query.Type + if ($Type) { + $CippBackupParams.Type = $Type } - if ($Request.Query.TenantFilter) { - $CippBackupParams.TenantFilter = $Request.Query.TenantFilter + if ($TenantFilter) { + $CippBackupParams.TenantFilter = $TenantFilter } - if ($Request.Query.NameOnly) { + if ($NameOnly) { $CippBackupParams.NameOnly = $true } - if ($Request.Query.BackupName) { - $CippBackupParams.Name = $Request.Query.BackupName + if ($BackupName) { + $CippBackupParams.Name = $BackupName } $Result = Get-CIPPBackup @CippBackupParams - if ($request.Query.NameOnly) { + if ($NameOnly) { $Result = $Result | Select-Object @{Name = 'BackupName'; exp = { $_.RowKey } }, Timestamp | Sort-Object Timestamp -Descending } 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 045ad540318f..1e548d669016 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 @@ -7,6 +7,10 @@ function Invoke-ExecPartnerWebhook { #> Param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + switch ($Request.Query.Action) { 'ListEventTypes' { $Uri = 'https://api.partnercenter.microsoft.com/webhooks/v1/registration/events' @@ -42,7 +46,7 @@ function Invoke-ExecPartnerWebhook { PartnerCenter = $true BaseURL = $BaseURL EventType = $Request.Body.EventType - Headers = $Request.Headers.'x-ms-client-principal' + Headers = $Request.Headers.'x-ms-client-principal' } $Results = New-CIPPGraphSubscription @Webhook 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 a2f10c527808..44964e3b490e 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 @@ -8,6 +8,10 @@ function Invoke-ExecServicePrincipals { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $env:TenantID $Success = $true 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 67fab612224f..eacfe5b53646 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 @@ -9,6 +9,11 @@ Function Invoke-ExecSetCIPPAutoBackup { #> [CmdletBinding()] param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $unixtime = [int64](([datetime]::UtcNow) - (Get-Date '1/1/1970')).TotalSeconds if ($Request.Body.Enabled -eq 'True') { $Table = Get-CIPPTable -TableName 'ScheduledTasks' 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 f10665096d54..f28ac30e189c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetCippAlerts.ps1 @@ -10,6 +10,10 @@ Function Invoke-GetCippAlerts { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Alerts = [System.Collections.Generic.List[object]]::new() $Table = Get-CippTable -tablename CippAlerts $PartitionKey = Get-Date -UFormat '%Y%m%d' diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 index 6bc115e7e4f0..706ba63531c9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-GetVersion.ps1 @@ -11,12 +11,12 @@ Function Invoke-GetVersion { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $CIPPVersion = $request.query.localversion + $CIPPVersion = $request.query.LocalVersion $Version = Assert-CippVersion -CIPPVersion $CIPPVersion - # Write to the Azure Functions log stream. # 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-ListApiTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListApiTest.ps1 index b8ba63e8a322..4f359e0bd952 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListApiTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListApiTest.ps1 @@ -8,6 +8,11 @@ function Invoke-ListApiTest { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = ($Request | ConvertTo-Json -Depth 5) 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 index 017d0b60a2ce..045d9e55d818 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphBulkRequest.ps1 @@ -8,16 +8,24 @@ function Invoke-ListGraphBulkRequest { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $TenantFilter = $Request.Body.tenantFilter + $AsApp = $Request.Body.asApp + $Requests = $Request.Body.requests + $GraphRequestParams = @{ - tenantid = $Request.Body.tenantFilter + tenantid = $TenantFilter Requests = @() } - if ($Request.Body.asapp) { - $GraphRequestParams.asapp = $Request.Body.asApp + if ($AsApp) { + $GraphRequestParams.asapp = $AsApp } - $BulkRequests = foreach ($GraphRequest in $Request.Body.requests) { + $BulkRequests = foreach ($GraphRequest in $Requests) { if ($GraphRequest.method -eq 'GET') { @{ id = $GraphRequest.id diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 index 09beb0a109e2..47d517ac3371 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListGraphRequest.ps1 @@ -10,9 +10,9 @@ function Invoke-ListGraphRequest { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - + $Headers = $Request.Headers $Message = 'Accessed this API | Endpoint: {0}' -f $Request.Query.Endpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message $Message -Sev 'Debug' + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev 'Debug' $CippLink = ([System.Uri]$TriggerMetadata.Headers.Referer).PathAndQuery @@ -117,9 +117,6 @@ function Invoke-ListGraphRequest { } $Metadata = $GraphRequestParams - if ($Request.Headers.'x-ms-coldstart' -eq 1) { - $Metadata.ColdStart = $true - } try { $Results = Get-GraphRequestList @GraphRequestParams @@ -142,6 +139,11 @@ function Invoke-ListGraphRequest { $Results = @() } } + + if ($Request.Headers.'x-ms-coldstart' -eq 1) { + $Metadata.ColdStart = $true + } + $GraphRequestData = [PSCustomObject]@{ Results = @($Results) Metadata = $Metadata 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 index c0497528c42a..132eb0ed62b1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/invoke-ListEmptyResults.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/invoke-ListEmptyResults.ps1 @@ -10,7 +10,11 @@ Function invoke-ListEmptyResults { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + # Associate values to output bindings by calling 'Push-OutputBinding'. 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 3fbb1ac29ccf..50bc77460089 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 @@ -11,40 +11,38 @@ Function Invoke-ExecExtensionMapping { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' $Table = Get-CIPPTable -TableName CippMapping if ($Request.Query.List) { switch ($Request.Query.List) { 'HaloPSA' { - $body = Get-HaloMapping -CIPPMapping $Table + $Result = Get-HaloMapping -CIPPMapping $Table } 'NinjaOne' { - $Body = Get-NinjaOneOrgMapping -CIPPMapping $Table + $Result = Get-NinjaOneOrgMapping -CIPPMapping $Table } 'NinjaOneFields' { - $Body = Get-NinjaOneFieldMapping -CIPPMapping $Table + $Result = Get-NinjaOneFieldMapping -CIPPMapping $Table } 'Hudu' { - $Body = Get-HuduMapping -CIPPMapping $Table + $Result = Get-HuduMapping -CIPPMapping $Table } 'HuduFields' { - $Body = Get-HuduFieldMapping -CIPPMapping $Table + $Result = Get-HuduFieldMapping -CIPPMapping $Table } 'Sherweb' { - $Body = Get-SherwebMapping -CIPPMapping $Table + $Result = Get-SherwebMapping -CIPPMapping $Table } 'HaloPSAFields' { $TicketTypes = Get-HaloTicketType - $Body = @{'TicketTypes' = $TicketTypes } + $Result = @{'TicketTypes' = $TicketTypes } } 'PWPushFields' { $Accounts = Get-PwPushAccount - $Body = @{ + $Result = @{ 'Accounts' = $Accounts } } @@ -55,30 +53,35 @@ Function Invoke-ExecExtensionMapping { if ($Request.Query.AddMapping) { switch ($Request.Query.AddMapping) { 'Sherweb' { - $Body = Set-SherwebMapping -CIPPMapping $Table -APIName $APIName -Request $Request + $Result = Set-SherwebMapping -CIPPMapping $Table -APIName $APIName -Request $Request } 'HaloPSA' { - $body = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request + $Result = Set-HaloMapping -CIPPMapping $Table -APIName $APIName -Request $Request } 'NinjaOne' { - $Body = Set-NinjaOneOrgMapping -CIPPMapping $Table -APIName $APIName -Request $Request + $Result = Set-NinjaOneOrgMapping -CIPPMapping $Table -APIName $APIName -Request $Request + Register-CIPPExtensionScheduledTasks } 'NinjaOneFields' { - $Body = Set-NinjaOneFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -TriggerMetadata $TriggerMetadata + $Result = Set-NinjaOneFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -TriggerMetadata $TriggerMetadata + Register-CIPPExtensionScheduledTasks } 'Hudu' { - $Body = Set-HuduMapping -CIPPMapping $Table -APIName $APIName -Request $Request + $Result = Set-HuduMapping -CIPPMapping $Table -APIName $APIName -Request $Request Register-CIPPExtensionScheduledTasks } 'HuduFields' { - $Body = Set-ExtensionFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -Extension 'Hudu' + $Result = Set-ExtensionFieldMapping -CIPPMapping $Table -APIName $APIName -Request $Request -Extension 'Hudu' Register-CIPPExtensionScheduledTasks } } } + $StatusCode = [HttpStatusCode]::OK } catch { - Write-LogMessage -API $APINAME -headers $Request.Headers -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Mapping API failed. $($ErrorMessage.NormalizedError)" + Write-LogMessage -API $APIName -headers $Headers -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } try { @@ -96,20 +99,23 @@ Function Invoke-ExecExtensionMapping { #Write-Host ($InputObject | ConvertTo-Json) $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress) Write-Host "Started permissions orchestration with ID = '$InstanceId'" - $Body = [pscustomobject]@{'Results' = 'Automapping Request has been queued. Exact name matches will appear first and matches on device names and serials will take longer. Please check the CIPP Logbook and refresh the page once complete.' } + $Result = 'AutoMapping Request has been queued. Exact name matches will appear first and matches on device names and serials will take longer. Please check the CIPP Logbook and refresh the page once complete.' } } } + $StatusCode = [HttpStatusCode]::OK } catch { - Write-LogMessage -API $APINAME -headers $Request.Headers -message "mapping API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Mapping API failed. $($ErrorMessage.NormalizedError)" + Write-LogMessage -API $APIName -headers $Headers -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{Results = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionSync.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionSync.ps1 index 239976f082f5..71848a9ca755 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionSync.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionSync.ps1 @@ -11,7 +11,8 @@ Function Invoke-ExecExtensionSync { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' switch ($Request.Query.Extension) { 'Gradient' { 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 a0c36e11d199..2d7800dcfb58 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 @@ -11,12 +11,14 @@ Function Invoke-ExecExtensionTest { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json) # Interact with query parameters or the body of the request. try { - switch ($Request.query.extensionName) { + switch ($Request.Query.extensionName) { 'HaloPSA' { $token = Get-HaloToken -configuration $Configuration.HaloPSA if ($token) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionsConfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionsConfig.ps1 index afba503c5d7c..4745a28e3d7c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionsConfig.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Extensions/Invoke-ExecExtensionsConfig.ps1 @@ -10,8 +10,12 @@ Function Invoke-ExecExtensionsConfig { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Body = [PSCustomObject]$Request.Body - $results = try { + $Results = try { # Check if NinjaOne URL is set correctly and the instance has at least version 5.6 if ($Body.NinjaOne) { $AllowedNinjaHostnames = @( @@ -59,7 +63,7 @@ Function Invoke-ExecExtensionsConfig { $AddObject = @{ PartitionKey = 'InstanceProperties' RowKey = 'CIPPURL' - Value = [string]([System.Uri]$Request.Headers.'x-ms-original-url').Host + Value = [string]([System.Uri]$Headers.'x-ms-original-url').Host } Write-Information ($AddObject | ConvertTo-Json -Compress) $ConfigTable = Get-CIPPTable -tablename 'Config' @@ -72,12 +76,11 @@ Function Invoke-ExecExtensionsConfig { } - $body = [pscustomobject]@{'Results' = $Results } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $body + Body = @{'Results' = $Results } }) } 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 0f8aa6c2bc77..57cad5bd283d 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 @@ -11,10 +11,9 @@ Function Invoke-ListExtensionSync { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' $ScheduledTasksTable = Get-CIPPTable -TableName 'ScheduledTasks' $ScheduledTasks = Get-CIPPAzDataTableEntity @ScheduledTasksTable -Filter 'Hidden eq true' | Where-Object { $_.Command -match 'CippExtension' } @@ -53,6 +52,6 @@ Function Invoke-ListExtensionSync { 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 e8a5c5575739..01f7a7d1f2c0 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 @@ -10,40 +10,50 @@ Function Invoke-ListScheduledItems { [CmdletBinding()] param($Request, $TriggerMetadata) - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + + # Interact with query parameters or the body of the request. + $ShowHidden = $Request.Query.ShowHidden ?? $Request.Body.ShowHidden + $Name = $Request.Query.Name ?? $Request.Body.Name + $Type = $Request.Query.Type ?? $Request.Body.Type $ScheduledItemFilter = [System.Collections.Generic.List[string]]::new() $ScheduledItemFilter.Add("PartitionKey eq 'ScheduledTask'") - if ($Request.Query.ShowHidden) { + if ($ShowHidden -eq $true) { $ScheduledItemFilter.Add('Hidden eq true') } else { $ScheduledItemFilter.Add('Hidden eq false') } - if ($Request.Query.Name) { - $ScheduledItemFilter.Add("Name eq '$($Request.Query.Name)'") + if ($Name -eq $true) { + $ScheduledItemFilter.Add("Name eq '$($Name)'") } $Filter = $ScheduledItemFilter -join ' and ' Write-Host "Filter: $Filter" $Table = Get-CIPPTable -TableName 'ScheduledTasks' - if ($Request.Query.Showhidden -eq $true) { + if ($ShowHidden -eq $true) { $HiddenTasks = $false } else { $HiddenTasks = $true } $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 } + if ($Type) { + $Tasks.Command + $Tasks = $Tasks | Where-Object { $_.command -eq $Type } } $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList + if ($AllowedTenants -notcontains 'AllTenants') { - $Tasks = $Tasks | Where-Object -Property TenantId -In $AllowedTenants + $TenantList = Get-Tenants -IncludeErrors | Select-Object customerId, defaultDomainName + $AllowedTenantDomains = $TenantList | Where-Object -Property customerId -In $AllowedTenants | Select-Object -ExpandProperty defaultDomainName + $Tasks = $Tasks | Where-Object -Property Tenant -In $AllowedTenantDomains } $ScheduledTasks = foreach ($Task in $tasks) { if ($Task.Parameters) { 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 4568e389f721..5a403a6894f9 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 @@ -15,11 +15,15 @@ Function Invoke-ExecAccessChecks { $Table = Get-CIPPTable -tablename 'AccessChecks' $LastRun = (Get-Date).ToUniversalTime() + $4HoursAgo = (Get-Date).AddHours(-1).ToUniversalTime() + $TimestampFilter = $4HoursAgo.ToString('yyyy-MM-ddTHH:mm:ss.fffK') + + 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'" + $Cache = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'AccessPermissions' and Timestamp and Timestamp ge datetime'$TimestampFilter'" $Results = $Cache.Data | ConvertFrom-Json } catch { $Results = $null @@ -75,13 +79,17 @@ Function Invoke-ExecAccessChecks { } catch { $LastRun = $null } + + if (!$Results) { + $Results = @() + } } catch { Write-Host $_.Exception.Message $Results = @() } } - if ($Request.Query.SkipCache -eq 'true' -or $Request.Query.SkipCache -eq $true) { + if ($Request.Query.SkipCache -eq 'true' -or $Request.Query.SkipCache -eq $true -or $LastRun -lt $4HoursAgo) { $Message = Test-CIPPAccessTenant -Headers $Request.Headers } @@ -95,7 +103,7 @@ Function Invoke-ExecAccessChecks { 'GDAP' { if (!$Request.Query.SkipCache -eq 'true' -or !$Request.Query.SkipCache -eq $true) { try { - $Cache = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'GDAPRelationships'" + $Cache = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq 'GDAPRelationships' and Timestamp ge datetime'$TimestampFilter'" $Results = $Cache.Data | ConvertFrom-Json } catch { $Results = $null 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 663468180762..0384b3e3c350 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 @@ -11,18 +11,17 @@ Function Invoke-ExecCPVPermissions { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Body.tenantFilter - # 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.Body.TenantFilter | Select-Object -First 1 + $Tenant = Get-Tenants -IncludeAll | Where-Object -Property customerId -EQ $TenantFilter | Select-Object -First 1 if ($Tenant) { Write-Host "Our tenant is $($Tenant.displayName) - $($Tenant.defaultDomainName)" - $TenantFilter = $Request.Body.TenantFilter $CPVConsentParams = @{ - TenantFilter = $Request.Body.TenantFilter + TenantFilter = $TenantFilter } if ($Request.Query.ResetSP -eq 'true') { $CPVConsentParams.ResetSP = $true diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 index 284be3d8095c..0d98b1797043 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomRole.ps1 @@ -8,6 +8,10 @@ function Invoke-ListCustomRole { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Table = Get-CippTable -tablename 'CustomRoles' $Body = Get-CIPPAzDataTableEntity @Table 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 c5c431ef50d4..d9780b9cc2cc 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 @@ -31,7 +31,9 @@ Function Invoke-ExecSAMSetup { } $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true') { $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'Secret' and RowKey eq 'Secret'" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-AddContact.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-AddContact.ps1 new file mode 100644 index 000000000000..aeb1cd33411b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-AddContact.ps1 @@ -0,0 +1,53 @@ +using namespace System.Net + +Function Invoke-AddContact { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Contact.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $ContactObject = $Request.Body + $TenantId = $ContactObject.tenantid + + try { + + $BodyToship = [pscustomobject] @{ + displayName = $ContactObject.displayName + name = $ContactObject.displayName + ExternalEmailAddress = $ContactObject.email + FirstName = $ContactObject.firstName + LastName = $ContactObject.lastName + + } + # Create the contact + $NewContact = New-ExoRequest -tenantid $TenantId -cmdlet 'New-MailContact' -cmdParams $BodyToship -UseSystemMailbox $true + $null = New-ExoRequest -tenantid $TenantId -cmdlet 'Set-MailContact' -cmdParams @{Identity = $NewContact.id; HiddenFromAddressListsEnabled = [boolean]$ContactObject.hidefromGAL } -UseSystemMailbox $true + + # Log the result + $Result = "Created contact $($ContactObject.displayName) with id $($NewContact.id)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantId -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to create contact. $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantId -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-AddSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-AddSharedMailbox.ps1 new file mode 100644 index 000000000000..797025084402 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-AddSharedMailbox.ps1 @@ -0,0 +1,83 @@ +using namespace System.Net + +Function Invoke-AddSharedMailbox { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $Results = [System.Collections.ArrayList]@() + $MailboxObject = $Request.Body + $Tenant = $MailboxObject.tenantID + $Aliases = $MailboxObject.addedAliases -Split '\n' + + try { + + $Email = "$($MailboxObject.username)@$($MailboxObject.domain)" + $BodyToShip = [pscustomobject] @{ + displayName = $MailboxObject.displayName + name = $MailboxObject.username + primarySMTPAddress = $Email + Shared = $true + } + $AddSharedRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'New-Mailbox' -cmdParams $BodyToShip + $Body = $Results.Add("Successfully created shared mailbox: $Email.") + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message "Created shared mailbox $($MailboxObject.displayName) with email $Email" -Sev 'Info' + + # Block sign-in for the mailbox + try { + $null = Set-CIPPSignInState -userid $AddSharedRequest.ExternalDirectoryObjectId -TenantFilter $Tenant -APIName $APIName -Headers $Headers -AccountEnabled $false + $Body = $Results.Add("Blocked sign-in for shared mailbox $Email") + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Message = "Failed to block sign-in for shared mailbox $Email. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -Sev 'Error' -LogData $ErrorMessage + $Body = $Results.Add($Message) + } + + # Add aliases to the mailbox if any are provided + if ($Aliases) { + try { + Start-Sleep 3 # Sleep since there is apparently a race condition with the mailbox creation if we don't delay for a lil bit + $AliasBodyToShip = [pscustomobject] @{ + Identity = $AddSharedRequest.Guid + EmailAddresses = @{'@odata.type' = '#Exchange.GenericHashTable'; Add = $Aliases } + } + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-Mailbox' -cmdParams $AliasBodyToShip -UseSystemMailbox $true + $Message = "Added aliases to $Email : $($Aliases -join ',')" + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -Sev 'Info' + $Body = $Results.Add($Message) + + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Message = "Failed to add aliases to $Email : $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -Sev 'Error' -LogData $ErrorMessage + $Body = $Results.Add($Message) + } + } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Message = "Failed to create shared mailbox. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -Sev 'Error' -LogData $ErrorMessage + $Body = $Results.Add($Message) + $StatusCode = [HttpStatusCode]::Forbidden + } + + + $Body = [pscustomobject] @{ Results = @($Results) } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditContact.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-EditContact.ps1 similarity index 87% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditContact.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-EditContact.ps1 index f08ca3c40bdf..d46143ce376c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditContact.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-EditContact.ps1 @@ -11,13 +11,13 @@ Function Invoke-EditContact { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $TenantID = $Request.body.tenantID $Headers = $Request.Headers - Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantID = $Request.Body.tenantID try { # Extract contact information from the request body - $contactInfo = $Request.body + $contactInfo = $Request.Body # Log the received contact object Write-Host "Received contact object: $($contactInfo | ConvertTo-Json)" @@ -43,21 +43,20 @@ Function Invoke-EditContact { $null = New-ExoRequest -tenantid $TenantID -cmdlet 'Set-Contact' -cmdParams $bodyForSetContact -UseSystemMailbox $true $null = New-ExoRequest -tenantid $TenantID -cmdlet 'Set-MailContact' -cmdParams @{Identity = $contactInfo.ContactID; HiddenFromAddressListsEnabled = [System.Convert]::ToBoolean($contactInfo.hidefromGAL) } -UseSystemMailbox $true $Results = "Successfully edited contact $($contactInfo.DisplayName)" - Write-LogMessage -Headers $Headers -API $APINAME -tenant $TenantID -message $Results -Sev Info + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantID -message $Results -Sev Info $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ $Results = "Failed to edit contact. $($ErrorMessage.NormalizedError)" - Write-LogMessage -Headers $Headers -API $APINAME -tenant $TenantID -message $Results -Sev Error -LogData $ErrorMessage + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantID -message $Results -Sev Error -LogData $ErrorMessage $StatusCode = [HttpStatusCode]::InternalServerError } - $Results = [pscustomobject]@{'Results' = "$Results" } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = $Results + Body = @{Results = $Results } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecConvertMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecConvertMailbox.ps1 new file mode 100644 index 000000000000..b8bd40c0915a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecConvertMailbox.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ExecConvertMailbox { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $TenantFilter = $Request.Body.tenantFilter + Write-LogMessage -Headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $UserID = $Request.Body.ID + $MailboxType = $Request.Body.MailboxType + + try { + $ConvertedMailbox = Set-CIPPMailboxType -UserID $UserID -TenantFilter $TenantFilter -APIName $APIName -Headers $Request.Headers -MailboxType $MailboxType + if ($ConvertedMailbox -like 'Could not convert*') { throw $ConvertedMailbox } + $Results = [pscustomobject]@{'Results' = "$ConvertedMailbox" } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = $_.Exception.Message + $Results = [pscustomobject]@{'Results' = "$ErrorMessage" } + $StatusCode = [HttpStatusCode]::InternalServerError + } + # 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/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 new file mode 100644 index 000000000000..4d0707ac66f9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ExecCopyForSent { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter ?? $Request.Body.TenantFilter + $UserID = $Request.Query.ID ?? $Request.Body.ID + $MessageCopyForSentAsEnabled = $Request.Query.MessageCopyForSentAsEnabled ?? $Request.Body.MessageCopyForSentAsEnabled + $MessageCopyForSentAsEnabled = [System.Convert]::ToBoolean($MessageCopyForSentAsEnabled) + + Try { + $Result = Set-CIPPMessageCopy -userid $UserID -tenantFilter $TenantFilter -APIName $APIName -Headers $Headers -MessageCopyForSentAsEnabled $MessageCopyForSentAsEnabled + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + 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/Administration/Invoke-ExecEditCalendarPermissions.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditCalendarPermissions.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditCalendarPermissions.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditMailboxPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditMailboxPermissions.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEditMailboxPermissions.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEditMailboxPermissions.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEmailForward.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEmailForward.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEmailForward.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEnableArchive.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEnableArchive.ps1 new file mode 100644 index 000000000000..bfb8cc74ad62 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEnableArchive.ps1 @@ -0,0 +1,37 @@ +using namespace System.Net + +Function Invoke-ExecEnableArchive { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $ID = $Request.Query.id ?? $Request.Body.id + $UserName = $Request.Query.username ?? $Request.Body.username + + Try { + $ResultsArch = Set-CIPPMailboxArchive -userid $ID -tenantFilter $TenantFilter -APIName $APIName -Headers $Headers -ArchiveEnabled $true -Username $UserName + if ($ResultsArch -like 'Failed to set archive*') { throw $ResultsArch } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ResultsArch = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError + } + $Results = [pscustomobject]@{'Results' = "$ResultsArch" } + # 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/Email-Exchange/Administration/Invoke-ExecEnableAutoExpandingArchive.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEnableAutoExpandingArchive.ps1 new file mode 100644 index 000000000000..47eae36f8e60 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecEnableAutoExpandingArchive.ps1 @@ -0,0 +1,32 @@ +function Invoke-ExecEnableAutoExpandingArchive { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $ID = $Request.Body.ID + $TenantFilter = $Request.Body.tenantFilter + $Username = $Request.Body.username + + try { + $Result = Set-CIPPMailboxArchive -TenantFilter $TenantFilter -UserID $ID -Username $Username -Headers $Headers -AutoExpandingArchive + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError + } + + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = "$Result" } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsDelete.ps1 new file mode 100644 index 000000000000..ec24ebf11a38 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsDelete.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecGroupsDelete { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $GroupType = $Request.Query.GroupType ?? $Request.Body.GroupType + $ID = $Request.Query.id ?? $Request.Body.id + $DisplayName = $Request.Query.displayName ?? $Request.Body.displayName + + Try { + $Result = Remove-CIPPGroup -ID $ID -Grouptype $GroupType -TenantFilter $TenantFilter -DisplayName $DisplayName -APIName $APIName -Headers $Headers + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsDeliveryManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsDeliveryManagement.ps1 new file mode 100644 index 000000000000..6966ad72c0e2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsDeliveryManagement.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecGroupsDeliveryManagement { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Group.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $GroupType = $Request.Query.GroupType ?? $Request.Body.GroupType + $OnlyAllowInternal = $Request.Query.OnlyAllowInternal ?? $Request.Body.OnlyAllowInternal + $ID = $Request.Query.ID ?? $Request.Body.ID + + Try { + $Result = Set-CIPPGroupAuthentication -ID $ID -GroupType $GroupType -OnlyAllowInternalString $OnlyAllowInternal -tenantFilter $TenantFilter -APIName $APIName -Headers $Headers + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsHideFromGAL.ps1 new file mode 100644 index 000000000000..d12ed019b26c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecGroupsHideFromGAL.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecGroupsHideFromGAL { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Group.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $GroupType = $Request.Query.GroupType ?? $Request.Body.GroupType + $GroupID = $Request.Query.ID ?? $Request.Body.ID + $HideFromGAL = $Request.Query.HideFromGAL ?? $Request.Body.HideFromGAL + + Try { + $Result = Set-CIPPGroupGAL -Id $GroupID -TenantFilter $TenantFilter -GroupType $GroupType -HiddenString $HideFromGAL -APIName $APIName -Headers $Headers + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{'Results' = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 similarity index 87% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 index 21b234e9bfd5..e926564f1f4f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHideFromGAL.ps1 @@ -18,8 +18,8 @@ Function Invoke-ExecHideFromGAL { # 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) - + $HideFromGAL = $Request.Query.HideFromGAL ?? $Request.body.HideFromGAL + $HideFromGAL = [System.Convert]::ToBoolean($HideFromGAL) Try { $HideResults = Set-CIPPHideFromGAL -tenantFilter $TenantFilter -UserID $UserId -hidefromgal $Hidden -Headers $Request.Headers -APIName $APIName diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecMailboxMobileDevices.ps1 similarity index 90% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecMailboxMobileDevices.ps1 index 5d752378f18a..2d54ba0aff50 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxMobileDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecMailboxMobileDevices.ps1 @@ -14,10 +14,6 @@ Function Invoke-ExecMailboxMobileDevices { Write-LogMessage -headers $Request.Headers -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. Try { $MobileResults = Set-CIPPMobileDevice -UserId $request.query.Userid -Guid $request.query.guid -DeviceId $request.query.deviceid -Quarantine $request.query.Quarantine -tenantFilter $request.query.tenantfilter -APIName $APINAME -Delete $Request.query.Delete -Headers $Request.Headers diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecRemoveMailboxRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecRemoveMailboxRule.ps1 new file mode 100644 index 000000000000..e06da5bc17b2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecRemoveMailboxRule.ps1 @@ -0,0 +1,38 @@ +using namespace System.Net + +Function Invoke-ExecRemoveMailboxRule { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message 'Accessed this API' -Sev 'Debug' + + # Interact with the query or body of the request + $TenantFilter = $Request.Query.TenantFilter ?? $Request.Query.TenantFilter + $RuleName = $Request.Query.ruleName ?? $Request.Body.ruleName + $RuleId = $Request.Query.ruleId ?? $Request.Body.ruleId + $Username = $Request.Query.userPrincipalName ?? $Request.Body.userPrincipalName + + # Remove the rule + $Results = Remove-CIPPMailboxRule -username $Username -TenantFilter $TenantFilter -APIName $APIName -Headers $Headers -RuleId $RuleId -RuleName $RuleName + + if ($Results -like '*Could not delete*') { + $StatusCode = [HttpStatusCode]::InternalServerError + } else { + $StatusCode = [HttpStatusCode]::OK + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ Results = $Results } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxLocale.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxLocale.ps1 new file mode 100644 index 000000000000..5d7d9e1c2392 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxLocale.ps1 @@ -0,0 +1,36 @@ +using namespace System.Net + +Function Invoke-ExecSetMailboxLocale { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $User -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $Tenant = $Request.Body.tenantFilter + $User = $Request.Body.user + $Locale = $Request.Body.locale + + try { + $Result = Set-CippMailboxLocale -username $User -locale $Locale -tenantFilter $Tenant -APIName $APIName -Headers $Headers + $StatusCode = [HttpStatusCode]::OK + } catch { + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxQuota.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxQuota.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetMailboxQuota.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 similarity index 97% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 index 1b60c5f7b8c0..952506bdc815 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetOoO.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecSetOoO.ps1 @@ -3,7 +3,9 @@ using namespace System.Net Function Invoke-ExecSetOoO { <# .FUNCTIONALITY - Entrypoint + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite #> [CmdletBinding()] param($Request, $TriggerMetadata) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 new file mode 100644 index 000000000000..6a03af82ed65 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecStartManagedFolderAssistant.ps1 @@ -0,0 +1,51 @@ +using namespace System.Net + +Function Invoke-ExecStartManagedFolderAssistant { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $Tenant = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $ID = $Request.Query.Id ?? $Request.Body.Id + $UserPrincipalName = $Request.Body.UserPrincipalName + $Identity = $ID ?? $UserPrincipalName + $ShownName = $UserPrincipalName ?? $ID + + + $ExoParams = @{ + Identity = $Identity + AggMailboxCleanup = $true + FullCrawl = $true + } + + try { + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Start-ManagedFolderAssistant' -cmdParams $ExoParams + $Result = "Successfully started Managed Folder Assistant for mailbox $($ShownName)." + $Severity = 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to start Managed Folder Assistant for mailbox $($ShownName). Error: $($ErrorMessage.NormalizedError)" + $Severity = 'Error' + $StatusCode = [HttpStatusCode]::InternalServerError + } finally { + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Result -Sev $Severity -LogData $ErrorMessage + } + + $Body = [pscustomobject] @{ 'Results' = $Result } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListCalendarPermissions.ps1 similarity index 67% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListCalendarPermissions.ps1 index a4640809048f..a13f9655c0dc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListCalendarPermissions.ps1 @@ -11,16 +11,18 @@ Function Invoke-ListCalendarPermissions { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $UserID = $request.Query.UserID - $Tenantfilter = $request.Query.tenantfilter + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $UserID = $Request.Query.UserID + $TenantFilter = $Request.Query.tenantFilter try { $GetCalParam = @{Identity = $UserID; FolderScope = 'Calendar' } - $CalendarFolder = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderStatistics' -anchor $UserID -cmdParams $GetCalParam | Select-Object -First 1 + $CalendarFolder = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MailboxFolderStatistics' -anchor $UserID -cmdParams $GetCalParam | Select-Object -First 1 -ExcludeProperty *data.type* $CalParam = @{Identity = "$($UserID):\$($CalendarFolder.name)" } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-MailboxFolderPermission' -anchor $UserID -cmdParams $CalParam -UseSystemMailbox $true | Select-Object Identity, User, AccessRights, FolderName - Write-LogMessage -API 'List Calendar Permissions' -tenant $tenantfilter -message "Calendar permissions listed for $($tenantfilter)" -sev Debug + $GraphRequest = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MailboxFolderPermission' -anchor $UserID -cmdParams $CalParam -UseSystemMailbox $true | Select-Object Identity, User, AccessRights, FolderName + Write-LogMessage -API $APIName -tenant $TenantFilter -message "Calendar permissions listed for $($TenantFilter)" -sev Debug $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListContacts.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListContacts.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListContacts.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxMobileDevices.ps1 similarity index 90% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxMobileDevices.ps1 index b09540ed117f..3e1be65549a6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxMobileDevices.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxMobileDevices.ps1 @@ -14,11 +14,8 @@ Function Invoke-ListMailboxMobileDevices { Write-LogMessage -headers $Request.Headers -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 + $TenantFilter = $Request.Query.tenantFilter $Mailbox = $Request.Query.Mailbox Write-Host $TenantFilter @@ -28,7 +25,7 @@ Function Invoke-ListMailboxMobileDevices { $base64IdentityParam = [Convert]::ToBase64String($Bytes) try { - $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline | Select-Object @{ Name = 'clientType'; Expression = { $_.ClientType } }, + $GraphRequest = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $TenantFilter -scope ExchangeOnline | Select-Object @{ Name = 'clientType'; Expression = { $_.ClientType } }, @{ Name = 'clientVersion'; Expression = { $_.ClientVersion } }, @{ Name = 'deviceAccessState'; Expression = { $_.DeviceAccessState } }, @{ Name = 'deviceFriendlyName'; Expression = { if ([string]::IsNullOrEmpty($_.DeviceFriendlyName)) { 'Unknown' }else { $_.DeviceFriendlyName } } }, diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxRules.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRules.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxRules.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 similarity index 96% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 index bcbc251c921b..deb836716d5d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxes.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListMailboxes.ps1 @@ -13,10 +13,6 @@ Function Invoke-ListMailboxes { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -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 { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListOoO.ps1 similarity index 92% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListOoO.ps1 index 3fe5c9a4a15b..2a1842db4d5b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListOoO.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListOoO.ps1 @@ -13,7 +13,7 @@ Function Invoke-ListOoO { $APIName = $Request.Params.CIPPEndpoint $Tenantfilter = $request.query.tenantFilter try { - $Body = Get-CIPPOutOfOffice -userid $Request.query.userid -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers + $Body = Get-CIPPOutOfOffice -UserID $Request.query.userid -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $Body = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListSharedMailboxStatistics.ps1 similarity index 92% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListSharedMailboxStatistics.ps1 index 996e6f13dc53..96edbf15faeb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxStatistics.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListSharedMailboxStatistics.ps1 @@ -13,9 +13,7 @@ Function Invoke-ListSharedMailboxStatistics { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # XXX Seems like an unused endpoint? -Bobby # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListmailboxPermissions.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListmailboxPermissions.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ListmailboxPermissions.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-RemoveContact.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-RemoveContact.ps1 new file mode 100644 index 000000000000..573cca5550d2 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-RemoveContact.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-RemoveContact { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Contact.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $TenantFilter = $Request.Query.tenantFilter + Write-LogMessage -Headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $GUID = $Request.query.GUID ?? $Request.body.GUID + + try { + $Params = @{ + Identity = $GUID + } + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-MailContact' -cmdParams $Params -UseSystemMailbox $true + Write-LogMessage -Headers $Request.Headers -API $APIName -tenant $TenantFilter -message "Deleted contact $GUID" -sev Debug + $Result = "Deleted $GUID" + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to delete contact $GUID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Request.Headers -API $APIName -tenant $TenantFilter -message $Result -sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::BadRequest + } + + $Results = [pscustomobject]@{'Results' = $Result } + # 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/Email-Exchange/Invoke-AddConnectionFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilter.ps1 deleted file mode 100644 index 51ea0dcc4908..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilter.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -using namespace System.Net - -Function Invoke-AddConnectionFilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.ConnectionFilter.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 -headers $Request.Headers -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 -headers $Request.Headers -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-AddContact.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddContact.ps1 deleted file mode 100644 index 454db172aab0..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddContact.ps1 +++ /dev/null @@ -1,48 +0,0 @@ -using namespace System.Net - -Function Invoke-AddContact { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Contact.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $contactobj = $Request.body - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - try { - - $BodyToship = [pscustomobject] @{ - 'displayName' = $contactobj.Displayname - 'name' = $contactobj.displayName - 'ExternalEmailAddress' = $contactobj.Email - FirstName = $contactObj.firstname - lastname = $contactobj.lastname - - } - $NewContact = New-ExoRequest -tenantid $Request.body.tenantid -cmdlet 'New-MailContact' -cmdparams $BodyToship -UseSystemMailbox $true - Write-Host ( $NewContact | ConvertTo-Json) - New-ExoRequest -tenantid $Request.body.tenantid -cmdlet 'Set-MailContact' -cmdparams @{identity = $NewContact.id; HiddenFromAddressListsEnabled = [boolean]$contactobj.hidefromGAL } -UseSystemMailbox $true - $body = [pscustomobject]@{'Results' = 'Successfully added a contact.' } - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($contactobj.tenantid) -message "Created contact $($contactobj.displayname) with id $($GraphRequest.id) for " -Sev 'Info' - - } catch { - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($contactobj.tenantid) -message "Contact creation API failed. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to create contact. $($_.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 deleted file mode 100644 index b475be078c06..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnector.ps1 +++ /dev/null @@ -1,38 +0,0 @@ -using namespace System.Net - -Function Invoke-AddExConnector { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Connector.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $ConnectorType = ($Request.body.PowerShellCommand | ConvertFrom-Json).cippConnectorType - $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, cippConnectorType, comments - - $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 -headers $Request.Headers -API $APINAME -tenant $Tenantfilter -message "Created Connector for $($Tenantfilter)" -sev 'Info' - } catch { - "Could not create created Connector for $($Tenantfilter): $($_.Exception.message)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $Tenantfilter -message "Could not create created Connector 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-AddSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 deleted file mode 100644 index d79795c18fa0..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSharedMailbox.ps1 +++ /dev/null @@ -1,83 +0,0 @@ -using namespace System.Net - -Function Invoke-AddSharedMailbox { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - - Write-LogMessage -Headers $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.' - - $Results = [System.Collections.ArrayList]@() - $MailboxObject = $Request.body - $Tenant = $MailboxObject.tenantid - $Aliases = $MailboxObject.addedAliases -Split '\n' - - try { - - $Email = "$($MailboxObject.username)@$($MailboxObject.domain)" - $BodyToShip = [pscustomobject] @{ - 'displayName' = $MailboxObject.Displayname - 'name' = $MailboxObject.username - 'primarySMTPAddress' = $Email - Shared = $true - } - $AddSharedRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'New-Mailbox' -cmdparams $BodyToShip - $Body = $Results.add("Successfully created shared mailbox: $Email.") - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Created shared mailbox $($MailboxObject.displayname) with email $Email" -Sev 'Info' - - # Block sign-in for the mailbox - try { - $null = Set-CIPPSignInState -userid $AddSharedRequest.ExternalDirectoryObjectId -TenantFilter $Tenant -APIName $APINAME -Headers $User -AccountEnabled $false - $Body = $Results.add("Blocked sign-in for shared mailbox $Email") - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Failed to block sign-in for shared mailbox $Email. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $Body = $Results.add("Failed to block sign-in for shared mailbox $Email. Error: $($ErrorMessage.NormalizedError)") - } - - # Add aliases to the mailbox if any are provided - if ($Aliases) { - try { - Start-Sleep 3 # Sleep since there is apparently a race condition with the mailbox creation if we don't delay for a lil bit - $AliasBodyToShip = [pscustomobject] @{ - 'Identity' = $AddSharedRequest.Guid - 'EmailAddresses' = @{'@odata.type' = '#Exchange.GenericHashTable'; Add = $Aliases } - } - $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-Mailbox' -cmdparams $AliasBodyToShip -UseSystemMailbox $true - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Added aliases to $Email : $($Aliases -join ',')" -Sev 'Info' - $Body = $results.add("Added Aliases to $Email : $($Aliases -join ',')") - - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Failed to add aliases to $Email : $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $Body = $results.add("ERROR: Failed to add aliases to $Email : $($ErrorMessage.NormalizedError)") - } - } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Failed to create shared mailbox. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $Body = $Results.add("Failed to create Shared Mailbox. $($ErrorMessage.NormalizedError)") - $StatusCode = [HttpStatusCode]::Forbidden - } - - - $Body = [pscustomobject] @{ 'Results' = @($results) } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Body - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 deleted file mode 100644 index 46e692cd809e..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilterTemplate.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -using namespace System.Net - -Function Invoke-AddSpamFilterTemplate { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Spamfilter.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 { - ([pscustomobject]$Request.body | Select-Object name, AddXHeaderValue, AdminDisplayName, AllowedSenderDomains, AllowedSenders, BlockedSenderDomains, BlockedSenders, BulkQuarantineTag, BulkSpamAction, BulkThreshold, Confirm, DownloadLink, EnableEndUserSpamNotifications, EnableLanguageBlockList, EnableRegionBlockList, EndUserSpamNotificationCustomFromAddress, EndUserSpamNotificationCustomFromName, EndUserSpamNotificationCustomSubject, EndUserSpamNotificationFrequency, EndUserSpamNotificationLanguage, EndUserSpamNotificationLimit, HighConfidencePhishAction, HighConfidencePhishQuarantineTag, HighConfidenceSpamAction, HighConfidenceSpamQuarantineTag, IncreaseScoreWithBizOrInfoUrls, IncreaseScoreWithImageLinks, IncreaseScoreWithNumericIps, IncreaseScoreWithRedirectToOtherPort, InlineSafetyTipsEnabled, LanguageBlockList, MarkAsSpamBulkMail, MarkAsSpamEmbedTagsInHtml, MarkAsSpamEmptyMessages, MarkAsSpamFormTagsInHtml, MarkAsSpamFramesInHtml, MarkAsSpamFromAddressAuthFail, MarkAsSpamJavaScriptInHtml, MarkAsSpamNdrBackscatter, MarkAsSpamObjectTagsInHtml, MarkAsSpamSensitiveWordList, MarkAsSpamSpfRecordHardFail, MarkAsSpamWebBugsInHtml, ModifySubjectValue, PhishQuarantineTag, PhishSpamAction, PhishZapEnabled, QuarantineRetentionPeriod, RecommendedPolicyType, RedirectToRecipients, RegionBlockList, SpamAction, SpamQuarantineTag, SpamZapEnabled, TestModeAction, TestModeBccToRecipients ) | ForEach-Object { - $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name - $_ | Select-Object -Property $NonEmptyProperties - } - } - $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 = 'SpamfilterTemplate' - } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Created Spam Filter Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' - $body = [pscustomobject]@{'Results' = 'Successfully added template' } - - } - catch { - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Failed to create Spam Filter Template: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Spamfilter 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-EditAntiPhishingFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditAntiPhishingFilter.ps1 deleted file mode 100644 index feaa27471516..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditAntiPhishingFilter.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -function Invoke-EditAntiPhishingFilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 { - $ExoRequestParam = @{ - tenantid = $TenantFilter - cmdParams = @{ - Identity = $Request.query.RuleName - } - useSystemmailbox = $true - } - - switch ($Request.query.State) { - 'Enable' { - $ExoRequestParam.Add('cmdlet', 'Enable-AntiPhishRule') - } - 'Disable' { - $ExoRequestParam.Add('cmdlet', 'Disable-AntiPhishRule') - } - Default { - throw 'Invalid state' - } - } - New-ExoRequest @ExoRequestParam - - $Result = "Sucessfully set Anti-Phishing rule $($Request.query.RuleName) to $($Request.query.State)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Result = "Failed setting Anti-Phishing rule $($Request.query.RuleName) to $($request.query.State). Error: $ErrorMessage" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -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-EditMalwareFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditMalwareFilter.ps1 deleted file mode 100644 index 315596cb252e..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditMalwareFilter.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -function Invoke-EditMalwareFilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 { - $ExoRequestParam = @{ - tenantid = $TenantFilter - cmdParams = @{ - Identity = $Request.query.RuleName - } - useSystemmailbox = $true - } - - switch ($Request.query.State) { - 'Enable' { - $ExoRequestParam.Add('cmdlet', 'Enable-MalwareFilterRule') - } - 'Disable' { - $ExoRequestParam.Add('cmdlet', 'Disable-MalwareFilterRule') - } - Default { - throw 'Invalid state' - } - } - New-ExoRequest @ExoRequestParam - - $Result = "Sucessfully set Malware Filter rule $($Request.query.RuleName) to $($Request.query.State)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Result = "Failed setting Malware Filter rule $($Request.query.RuleName) to $($request.query.State). Error: $ErrorMessage" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -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-EditSafeAttachmentsFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSafeAttachmentsFilter.ps1 deleted file mode 100644 index b552059cabf8..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSafeAttachmentsFilter.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -function Invoke-EditSafeAttachmentsFilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 { - $ExoRequestParam = @{ - tenantid = $TenantFilter - cmdParams = @{ - Identity = $Request.query.RuleName - } - useSystemmailbox = $true - } - - switch ($Request.query.State) { - 'Enable' { - $ExoRequestParam.Add('cmdlet', 'Enable-SafeAttachmentRule') - } - 'Disable' { - $ExoRequestParam.Add('cmdlet', 'Disable-SafeAttachmentRule') - } - Default { - throw 'Invalid state' - } - } - New-ExoRequest @ExoRequestParam - - $Result = "Sucessfully set SafeAttachment rule $($Request.query.RuleName) to $($Request.query.State)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Result = "Failed setting SafeAttachment rule $($Request.query.RuleName) to $($request.query.State). Error: $ErrorMessage" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -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-EditSafeLinksFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSafeLinksFilter.ps1 deleted file mode 100644 index 9d1663070e2e..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSafeLinksFilter.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -function Invoke-EditSafeLinksFilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 { - $ExoRequestParam = @{ - tenantid = $TenantFilter - cmdParams = @{ - Identity = $Request.query.RuleName - } - useSystemmailbox = $true - } - - switch ($Request.query.State) { - 'Enable' { - $ExoRequestParam.Add('cmdlet', 'Enable-SafeLinksRule') - } - 'Disable' { - $ExoRequestParam.Add('cmdlet', 'Disable-SafeLinksRule') - } - Default { - throw 'Invalid state' - } - } - New-ExoRequest @ExoRequestParam - - $Result = "Sucessfully set SafeLinks rule $($Request.query.RuleName) to $($Request.query.State)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Result = "Failed setting SafeLinks rule $($Request.query.RuleName) to $($request.query.State). Error: $ErrorMessage" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $TenantFilter -message $Result -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-EditSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 deleted file mode 100644 index f4bcef687f68..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditSpamFilter.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -using namespace System.Net - -Function Invoke-EditSpamFilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.Query.tenantfilter - - $Params = @{ - Identity = $request.query.name - } - - try { - $cmdlet = if ($request.query.state -eq 'enable') { 'Enable-HostedContentFilterRule' } else { 'Disable-HostedContentFilterRule' } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true - $Result = "Set Spamfilter rule to $($request.query.State)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $tenantfilter -message "Set Spamfilter rule $($Request.query.name) to $($request.query.State)" -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $tenantfilter -message "Failed setting Spamfilter rule $($Request.query.guid) to $($request.query.State). Error:$ErrorMessage" -Sev 'Error' - $Result = $ErrorMessage - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{Results = $Result } - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoRoomMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoRoomMailbox.ps1 deleted file mode 100644 index 0631d7afa78a..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoRoomMailbox.ps1 +++ /dev/null @@ -1,36 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecConvertToRoomMailbox { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $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. - Try { - $ConvertedMailbox = Set-CIPPMailboxType -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -Headers $User -MailboxType 'Room' - $Results = [pscustomobject]@{'Results' = "$ConvertedMailbox" } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Results = [pscustomobject]@{'Results' = "Failed to convert $($request.query.id) - $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/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 deleted file mode 100644 index b704bac3dd5b..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecConverttoSharedMailbox.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecConverttoSharedMailbox { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $Tenant = $Request.query.TenantFilter - $User = $Request.Headers - Write-LogMessage -Headers $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. - Try { - $MailboxType = if ($request.query.ConvertToUser -eq 'true') { 'Regular' } else { 'Shared' } - $ConvertedMailbox = Set-CIPPMailboxType -userid $Request.query.id -tenantFilter $Tenant -APIName $APINAME -Headers $User -MailboxType $MailboxType - $Results = [pscustomobject]@{'Results' = "$ConvertedMailbox" } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Results = [pscustomobject]@{'Results' = "Failed to convert $($request.query.id) - $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/Email-Exchange/Invoke-ExecCopyForSent.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecCopyForSent.ps1 deleted file mode 100644 index f3f9b27e6b11..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecCopyForSent.ps1 +++ /dev/null @@ -1,36 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecCopyForSent { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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. - Try { - $MessageCopyForSentAsEnabled = if ($request.query.MessageCopyForSentAsEnabled -eq 'false') { 'false' } else { 'true' } - $MessageResult = Set-CIPPMessageCopy -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -Headers $Request.Headers -MessageCopyForSentAsEnabled $MessageCopyForSentAsEnabled - $Results = [pscustomobject]@{'Results' = "$MessageResult" } - } catch { - $Results = [pscustomobject]@{'Results' = "set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled failed - $($_.Exception.Message)" } - } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 deleted file mode 100644 index 599b50ee0f34..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecEnableArchive.ps1 +++ /dev/null @@ -1,34 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecEnableArchive { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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. - Try { - $ResultsArch = Set-CIPPMailboxArchive -userid $Request.query.id -tenantFilter $Request.query.TenantFilter -APIName $APINAME -Headers $Request.Headers -ArchiveEnabled $true - $Results = [pscustomobject]@{'Results' = "$ResultsArch" } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 deleted file mode 100644 index 6dc149972be2..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDelete.ps1 +++ /dev/null @@ -1,34 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecGroupsDelete { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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. - Try { - $RemoveResults = Remove-CIPPGroup -ID $Request.query.id -GroupType $Request.query.GroupType -tenantFilter $Request.query.TenantFilter -displayName $Request.query.displayName -APIName $APINAME -Headers $Request.Headers - $Results = [pscustomobject]@{'Results' = $RemoveResults } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 deleted file mode 100644 index 5d7c0c45bc92..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsDeliveryManagement.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecGroupsDeliveryManagement { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Group.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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. - Try { - $SetResults = Set-CIPPGroupAuthentication -ID $Request.query.id -GroupType $Request.query.GroupType -OnlyAllowInternalString $Request.query.OnlyAllowInternal -tenantFilter $Request.query.TenantFilter -APIName $APINAME -Headers $Request.Headers - $Results = [pscustomobject]@{'Results' = $SetResults } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenantfilter) -message "Delivery Management failed: $($_.Exception.Message)" -Sev 'Error' - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 deleted file mode 100644 index b8bfa298cf6c..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecGroupsHideFromGAL.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecGroupsHideFromGAL { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Group.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Interact with query parameters or the body of the request. - Try { - $GroupStatus = Set-CIPPGroupGAL -Id $Request.query.id -tenantFilter $Request.query.TenantFilter -GroupType $Request.query.groupType -HiddenString $Request.query.HidefromGAL -APIName $APINAME -Headers $Request.Headers - $Results = [pscustomobject]@{'Results' = $GroupStatus } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($tenantfilter) -message "Hide/UnHide from GAL failed: $($_.Exception.Message)" -Sev 'Error' - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecRemoveMailboxRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecRemoveMailboxRule.ps1 deleted file mode 100644 index 530767520c08..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecRemoveMailboxRule.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecRemoveMailboxRule { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = 'Remove mailbox rule' - $TenantFilter = $Request.Query.TenantFilter - $RuleName = $Request.Query.ruleName - $RuleId = $Request.Query.ruleId - $Username = $Request.Query.userPrincipalName - - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -tenant $TenantFilter -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - - # Remove the rule - $Results = Remove-CIPPMailboxRule -userid $User -username $Username -TenantFilter $TenantFilter -APIName $APINAME -Headers $User -RuleId $RuleId -RuleName $RuleName - - if ($Results -like '*Could not delete*') { - $StatusCode = [HttpStatusCode]::Forbidden - } else { - $StatusCode = [HttpStatusCode]::OK - } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @{ Results = $Results } - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxLocale.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxLocale.ps1 deleted file mode 100644 index f7d1c12ba762..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecSetMailboxLocale.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecSetMailboxLocale { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $Tenant = $Request.body.TenantFilter - $User = $Request.Headers - Write-LogMessage -Headers $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. - $Results = Set-CippMailboxLocale -username $Request.Body.user -locale $Request.body.locale -tenantFilter $Tenant -APIName $APINAME -Headers $User - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = @{ Results = $Results } - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecStartManagedFolderAssistant.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecStartManagedFolderAssistant.ps1 deleted file mode 100644 index 962d6a02d316..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecStartManagedFolderAssistant.ps1 +++ /dev/null @@ -1,41 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecStartManagedFolderAssistant { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - $Tenant = $Request.query.TenantFilter - Write-LogMessage -Headers $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.' - $Results = [System.Collections.Generic.List[Object]]::new() - - # Interact with query parameters or the body of the request. - - try { - $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Start-ManagedFolderAssistant' -cmdparams @{Identity = $Request.query.id } - $Results.Add("Successfully started Managed Folder Assistant for mailbox $($Request.query.id).") - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Failed to create room: $($MailboxObject.DisplayName). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $Results.Add("Failed to start Managed Folder Assistant for mailbox $($Request.query.id). Error: $($ErrorMessage.NormalizedError)") - $StatusCode = [HttpStatusCode]::Forbidden - } - - $Body = [pscustomobject] @{ 'Results' = @($Results) } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $Body - }) -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListAntiPhishingFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListAntiPhishingFilters.ps1 deleted file mode 100644 index d6075e578313..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListAntiPhishingFilters.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -function Invoke-ListAntiPhishingFilters { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 - $Policys = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishPolicy' | Select-Object -Property * - $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishRule' | Select-Object -Property * - - $Output = $Policys | Select-Object -Property *, - @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.Name } } } }, - @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.Priority } } } }, - @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, - @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.State } } } } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Output - }) -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMalwareFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMalwareFilters.ps1 deleted file mode 100644 index 597472165fda..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMalwareFilters.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -function Invoke-ListMalwareFilters { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 - $Policys = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MalwareFilterPolicy' | Select-Object -Property * - $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MalwareFilterRule' | Select-Object -Property * - - $Output = $Policys | Select-Object -Property *, - @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.Name } } } }, - @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.Priority } } } }, - @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, - @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.State } } } } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Output - }) -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 deleted file mode 100644 index 69d049c13ae9..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListRecipients.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -using namespace System.Net - -Function Invoke-ListRecipients { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Mailbox.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 { - $Select = 'id,DisplayName,ExchangeGuid,ArchiveGuid,PrimarySmtpAddress,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses' - $ExoRequest = @{ - tenantid = $TenantFilter - cmdlet = 'Get-Recipient' - cmdParams = @{resultsize = 'unlimited' } - Select = $select - } - - $GraphRequest = (New-ExoRequest @ExoRequest) | Select-Object id, ExchangeGuid, ArchiveGuid, - @{ Name = 'UPN'; Expression = { $_.'PrimarySmtpAddress' } }, - @{ Name = 'mail'; Expression = { $_.'PrimarySmtpAddress' } }, - @{ Name = 'displayName'; Expression = { $_.'DisplayName' } } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSafeAttachmentsFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSafeAttachmentsFilters.ps1 deleted file mode 100644 index 8b71d807876f..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSafeAttachmentsFilters.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -function Invoke-ListSafeAttachmentsFilters { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 - $Policys = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeAttachmentPolicy' | Select-Object -Property * - $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeAttachmentRule' | Select-Object -Property * - - $Output = $Policys | Select-Object -Property *, - @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.Name } } } }, - @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.Priority } } } }, - @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, - @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.State } } } } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Output - }) -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSafeLinksFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSafeLinksFilters.ps1 deleted file mode 100644 index bcf5e939e498..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSafeLinksFilters.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -function Invoke-ListSafeLinksFilters { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.SpamFilter.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -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 - $Policys = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeLinksPolicy' | Select-Object -Property * - $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeLinksRule' | Select-Object -Property * - - $Output = $Policys | Select-Object -Property *, - @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.Name } } } }, - @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.Priority } } } }, - @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, - @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.State } } } } - - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Output - }) -} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListAntiPhishingFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListAntiPhishingFilters.ps1 new file mode 100644 index 000000000000..3325c114db4f --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListAntiPhishingFilters.ps1 @@ -0,0 +1,32 @@ +function Invoke-ListAntiPhishingFilters { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Policies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishPolicy' | Select-Object -Property * + $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishRule' | Select-Object -Property * + + $Output = $Policies | Select-Object -Property *, + @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.Name } } } }, + @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.Priority } } } }, + @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, + @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.AntiPhishPolicy -eq $_.Name) { $item.State } } } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Output + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListGlobalAddressList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListGlobalAddressList.ps1 similarity index 87% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListGlobalAddressList.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListGlobalAddressList.ps1 index 15d5702ce0a1..2801bb8e3a1c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListGlobalAddressList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListGlobalAddressList.ps1 @@ -12,12 +12,14 @@ Function Invoke-ListGlobalAddressList { $APIName = $Request.Params.CIPPEndpoint $Headers = $Request.Headers - Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -Headers $Headers -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* + -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 $_ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListMailboxCAS.ps1 similarity index 88% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListMailboxCAS.ps1 index c088305a95c1..7ba5b3ec7c47 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxCAS.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListMailboxCAS.ps1 @@ -11,12 +11,10 @@ Function Invoke-ListMailboxCAS { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -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 { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListMalwareFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListMalwareFilters.ps1 new file mode 100644 index 000000000000..98a4e77be2b9 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListMalwareFilters.ps1 @@ -0,0 +1,31 @@ +function Invoke-ListMalwareFilters { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter + $Policies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MalwareFilterPolicy' | Select-Object -Property * + $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MalwareFilterRule' | Select-Object -Property * + + $Output = $Policies | Select-Object -Property *, + @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.Name } } } }, + @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.Priority } } } }, + @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, + @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.MalwareFilterPolicy -eq $_.Name) { $item.State } } } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Output + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSafeAttachmentsFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSafeAttachmentsFilters.ps1 new file mode 100644 index 000000000000..6df0401229fc --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSafeAttachmentsFilters.ps1 @@ -0,0 +1,31 @@ +function Invoke-ListSafeAttachmentsFilters { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Policies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeAttachmentPolicy' | Select-Object -Property * + $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeAttachmentRule' | Select-Object -Property * + + $Output = $Policies | Select-Object -Property *, + @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.Name } } } }, + @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.Priority } } } }, + @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, + @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.SafeAttachmentPolicy -eq $_.Name) { $item.State } } } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Output + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSafeLinksFilters.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSafeLinksFilters.ps1 new file mode 100644 index 000000000000..c9e395c05de7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSafeLinksFilters.ps1 @@ -0,0 +1,31 @@ +function Invoke-ListSafeLinksFilters { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter + $Policies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeLinksPolicy' | Select-Object -Property * + $Rules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeLinksRule' | Select-Object -Property * + + $Output = $Policies | Select-Object -Property *, + @{ Name = 'RuleName'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.Name } } } }, + @{ Name = 'Priority'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.Priority } } } }, + @{ Name = 'RecipientDomainIs'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.RecipientDomainIs } } } }, + @{ Name = 'State'; Expression = { foreach ($item in $Rules) { if ($item.SafeLinksPolicy -eq $_.Name) { $item.State } } } } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Output + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 similarity index 82% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 index c7d6d401ab1f..eaea73fa0129 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharedMailboxAccountEnabled.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Reports/Invoke-ListSharedMailboxAccountEnabled.ps1 @@ -11,18 +11,16 @@ Function Invoke-ListSharedMailboxAccountEnabled { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Query.tenantFilter # Get Shared Mailbox Stuff try { $SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($TenantFilter)/Mailbox?`$filter=RecipientTypeDetails eq 'SharedMailbox'" -Tenantid $TenantFilter -scope ExchangeOnline) - $AllUsersAccountState = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?select=id,userPrincipalName,accountEnabled,displayName,givenName,surname,onPremisesSyncEnabled' -tenantid $Tenantfilter + $AllUsersAccountState = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?select=id,userPrincipalName,accountEnabled,displayName,givenName,surname,onPremisesSyncEnabled' -tenantid $TenantFilter $EnabledUsersWithSharedMailbox = foreach ($SharedMailbox in $SharedMailboxList) { # Match the User $User = $AllUsersAccountState | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -Property id, userPrincipalName, accountEnabled, displayName, givenName, surname, onPremisesSyncEnabled -First 1 @@ -38,9 +36,8 @@ Function Invoke-ListSharedMailboxAccountEnabled { } } - } - catch { - Write-LogMessage -API 'Tenant' -tenant $tenantfilter -message "Shared Mailbox Enabled Accounts on $($tenantfilter). Error: $($_.exception.message)" -sev 'Error' + } catch { + Write-LogMessage -API 'Tenant' -tenant $TenantFilter -message "Shared Mailbox Enabled Accounts on $($TenantFilter). Error: $($_.exception.message)" -sev 'Error' } $GraphRequest = $EnabledUsersWithSharedMailbox diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddRoomMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-AddRoomMailbox.ps1 similarity index 68% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddRoomMailbox.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-AddRoomMailbox.ps1 index 0951cd7a3c09..0b7f139a7832 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddRoomMailbox.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-AddRoomMailbox.ps1 @@ -9,12 +9,13 @@ Function Invoke-AddRoomMailbox { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenant = $Request.body.tenantid - $User = $Request.Headers + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $Tenant = $Request.Body.tenantid $Results = [System.Collections.Generic.List[Object]]::new() - $MailboxObject = $Request.body + $MailboxObject = $Request.Body $AddRoomParams = [pscustomobject]@{ Name = $MailboxObject.username DisplayName = $MailboxObject.displayName @@ -25,24 +26,24 @@ Function Invoke-AddRoomMailbox { } # Interact with query parameters or the body of the request. try { - $AddRoomRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'New-Mailbox' -cmdparams $AddRoomParams + $AddRoomRequest = New-ExoRequest -tenantid $Tenant -cmdlet 'New-Mailbox' -cmdParams $AddRoomParams $Results.Add("Successfully created room: $($MailboxObject.DisplayName).") - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Created room $($MailboxObject.DisplayName) with id $($AddRoomRequest.id)" -Sev 'Info' + Write-LogMessage -Headers $Headers -API $APINAME -tenant $Tenant -message "Created room $($MailboxObject.DisplayName) with id $($AddRoomRequest.id)" -Sev 'Info' # Block sign-in for the mailbox try { - $Request = Set-CIPPSignInState -userid $AddRoomRequest.ExternalDirectoryObjectId -TenantFilter $Tenant -APIName $APINAME -Headers $User -AccountEnabled $false - $Results.add("Blocked sign-in for Room mailbox; $($MailboxObject.userPrincipalName)") + $Request = Set-CIPPSignInState -userid $AddRoomRequest.ExternalDirectoryObjectId -TenantFilter $Tenant -APIName $APINAME -Headers $Headers -AccountEnabled $false + $Results.Add("Blocked sign-in for Room mailbox; $($MailboxObject.userPrincipalName)") } catch { $ErrorMessage = Get-CippException -Exception $_ - $Results.add("Failed to block sign-in for Room mailbox: $($MailboxObject.userPrincipalName). Error: $($ErrorMessage.NormalizedError)") + $Results.Add("Failed to block sign-in for Room mailbox: $($MailboxObject.userPrincipalName). Error: $($ErrorMessage.NormalizedError)") } $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -tenant $Tenant -message "Failed to create room: $($MailboxObject.DisplayName). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message "Failed to create room: $($MailboxObject.DisplayName). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage $Results.Add("Failed to create Room mailbox $($MailboxObject.userPrincipalName). $($ErrorMessage.NormalizedError)") - $StatusCode = [HttpStatusCode]::Forbidden + $StatusCode = [HttpStatusCode]::InternalServerError } $Body = [pscustomobject] @{ 'Results' = @($Results) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditRoomMailbox.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-EditRoomMailbox.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditRoomMailbox.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-EditRoomMailbox.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRoomLists.ps1 similarity index 82% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRoomLists.ps1 index 93ac7fb9041c..bf4891463fa7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRoomLists.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRoomLists.ps1 @@ -11,14 +11,10 @@ Function Invoke-ListRoomLists { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Query.tenantFilter try { $params = @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListRooms.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRooms.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListRooms.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Resources/Invoke-ListRooms.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddSpamFilter.ps1 similarity index 52% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddSpamFilter.ps1 index 88def6633399..10d902c7a9cb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddSpamFilter.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddSpamFilter.ps1 @@ -12,16 +12,17 @@ Function Invoke-AddSpamFilter { $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, comments $RequestPriority = $Request.Body.Priority $Tenants = ($Request.body.selectedTenants).value - $Result = foreach ($Tenantfilter in $tenants) { + $Result = foreach ($TenantFilter in $tenants) { try { - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-HostedContentFilterPolicy' -cmdParams $RequestParams - $Domains = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-AcceptedDomain').name + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'New-HostedContentFilterPolicy' -cmdParams $RequestParams + $Domains = (New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AcceptedDomain').name $ruleparams = @{ 'name' = "$($RequestParams.name)" 'hostedcontentfilterpolicy' = "$($RequestParams.name)" @@ -29,12 +30,13 @@ Function Invoke-AddSpamFilter { 'Enabled' = $true 'Priority' = $RequestPriority } - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'New-HostedContentFilterRule' -cmdParams $ruleparams - "Successfully created spamfilter for $tenantfilter." - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $tenantfilter -message "Created spamfilter rule for $($tenantfilter)" -sev Info + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'New-HostedContentFilterRule' -cmdParams $ruleparams + "Successfully created spamfilter for $TenantFilter." + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Successfully created spamfilter for $TenantFilter." -sev Info } catch { - "Could not create create spamfilter rule for $($tenantfilter): $($_.Exception.message)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $tenantfilter -message "Could not create create spamfilter rule for $($tenantfilter): $($_.Exception.message)" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + "Could not create spamfilter rule for $($TenantFilter): $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Could not create spamfilter rule for $($TenantFilter): $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddSpamFilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddSpamFilterTemplate.ps1 new file mode 100644 index 000000000000..721caee1e338 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddSpamFilterTemplate.ps1 @@ -0,0 +1,53 @@ +using namespace System.Net + +Function Invoke-AddSpamFilterTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + 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, AddXHeaderValue, AdminDisplayName, AllowedSenderDomains, AllowedSenders, BlockedSenderDomains, BlockedSenders, BulkQuarantineTag, BulkSpamAction, BulkThreshold, Confirm, DownloadLink, EnableEndUserSpamNotifications, EnableLanguageBlockList, EnableRegionBlockList, EndUserSpamNotificationCustomFromAddress, EndUserSpamNotificationCustomFromName, EndUserSpamNotificationCustomSubject, EndUserSpamNotificationFrequency, EndUserSpamNotificationLanguage, EndUserSpamNotificationCustomFromAddress, HighConfidencePhishAction, HighConfidencePhishQuarantineTag, HighConfidenceSpamAction, HighConfidenceSpamQuarantineTag, IncreaseScoreWithBizOrInfoUrls, IncreaseScoreWithImageLinks, IncreaseScoreWithNumericIps, IncreaseScoreWithRedirectToOtherPort, InlineSafetyTipsEnabled, LanguageBlockList, MarkAsSpamBulkMail, MarkAsSpamEmbedTagsInHtml, MarkAsSpamEmptyMessages, MarkAsSpamFormTagsInHtml, MarkAsSpamFramesInHtml, MarkAsSpamFromAddressAuthFail, MarkAsSpamJavaScriptInHtml, MarkAsSpamNdrBackscatter, MarkAsSpamObjectTagsInHtml, MarkAsSpamSensitiveWordList, MarkAsSpamSpfRecordHardFail, MarkAsSpamWebBugsInHtml, ModifySubjectValue, PhishQuarantineTag, PhishSpamAction, PhishZapEnabled, QuarantineRetentionPeriod, RecommendedPolicyType, RedirectToRecipients, RegionBlockList, SpamAction, SpamQuarantineTag, SpamZapEnabled, TestModeAction, TestModeBccToRecipients ) | ForEach-Object { + $NonEmptyProperties = $_.PSObject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name + $_ | Select-Object -Property $NonEmptyProperties + } + } + $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 = 'SpamfilterTemplate' + } + $Result = "Successfully created Spam Filter Template: $($Request.Body.name) with GUID $GUID" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Debug' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to create Spam Filter Template: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 similarity index 64% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 index 9f19cacea091..d43b14b56a9a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-AddTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-AddTenantAllowBlockList.ps1 @@ -11,12 +11,11 @@ Function Invoke-AddTenantAllowBlockList { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $blocklistobj = $Request.body - if ($Request.body.tenantId -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $Tenants = @($Request.body.tenantId) } - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + $BlockListObject = $Request.Body + if ($Request.Body.tenantId -eq 'AllTenants') { $Tenants = (Get-Tenants).defaultDomainName } else { $Tenants = @($Request.body.tenantId) } $Results = [System.Collections.Generic.List[string]]::new() foreach ($Tenant in $Tenants) { try { @@ -24,20 +23,20 @@ Function Invoke-AddTenantAllowBlockList { tenantid = $Tenant cmdlet = 'New-TenantAllowBlockListItems' cmdParams = @{ - Entries = [string[]]$blocklistobj.entries - ListType = [string]$blocklistobj.listType - Notes = [string]$blocklistobj.notes - $blocklistobj.listMethod = [bool]$true + Entries = [string[]]$BlockListObject.entries + ListType = [string]$BlockListObject.listType + Notes = [string]$BlockListObject.notes + $BlockListObject.listMethod = [bool]$true } } - if ($blocklistobj.NoExpiration -eq $true) { + if ($BlockListObject.NoExpiration -eq $true) { $ExoRequest.cmdParams.NoExpiration = $true } New-ExoRequest @ExoRequest - $results.add("Successfully added $($blocklistobj.Entries) as type $($blocklistobj.ListType) to the $($blocklistobj.listMethod) list for $tenant") + $results.add("Successfully added $($BlockListObject.Entries) as type $($BlockListObject.ListType) to the $($BlockListObject.listMethod) list for $tenant") Write-LogMessage -headers $Request.Headers -API $APIName -tenant $Tenant -message $result -Sev 'Info' } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditAntiPhishingFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditAntiPhishingFilter.ps1 new file mode 100644 index 000000000000..002f78839f1b --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditAntiPhishingFilter.ps1 @@ -0,0 +1,57 @@ +function Invoke-EditAntiPhishingFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $RuleName = $Request.Query.RuleName ?? $Request.Body.RuleName + $State = $Request.Query.State ?? $Request.Body.State + + try { + $ExoRequestParam = @{ + tenantid = $TenantFilter + cmdParams = @{ + Identity = $RuleName + } + useSystemMailbox = $true + } + + switch ($State) { + 'Enable' { + $ExoRequestParam.Add('cmdlet', 'Enable-AntiPhishRule') + } + 'Disable' { + $ExoRequestParam.Add('cmdlet', 'Disable-AntiPhishRule') + } + Default { + throw 'Invalid state' + } + } + $null = New-ExoRequest @ExoRequestParam + + $Result = "Successfully set Anti-Phishing rule $RuleName to $State" + Write-LogMessage -headers $Headers -API $APINAME -tenant $TenantFilter -message $Result -Sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed setting Anti-Phishing rule $RuleName to $State. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APINAME -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditMalwareFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditMalwareFilter.ps1 new file mode 100644 index 000000000000..bb599a80f6f3 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditMalwareFilter.ps1 @@ -0,0 +1,57 @@ +function Invoke-EditMalwareFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $RuleName = $Request.Query.RuleName ?? $Request.Body.RuleName + $State = $Request.Query.State ?? $Request.Body.State + + try { + $ExoRequestParam = @{ + tenantid = $TenantFilter + cmdParams = @{ + Identity = $RuleName + } + useSystemMailbox = $true + } + + switch ($State) { + 'Enable' { + $ExoRequestParam.Add('cmdlet', 'Enable-MalwareFilterRule') + } + 'Disable' { + $ExoRequestParam.Add('cmdlet', 'Disable-MalwareFilterRule') + } + Default { + throw 'Invalid state' + } + } + $null = New-ExoRequest @ExoRequestParam + + $Result = "Successfully set Malware Filter rule $($RuleName) to $($State)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed setting Malware Filter rule $($RuleName) to $($State). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSafeAttachmentsFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSafeAttachmentsFilter.ps1 new file mode 100644 index 000000000000..1adb00b34010 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSafeAttachmentsFilter.ps1 @@ -0,0 +1,57 @@ +function Invoke-EditSafeAttachmentsFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $RuleName = $Request.Query.RuleName ?? $Request.Body.RuleName + $State = $Request.Query.State ?? $Request.Body.State + + try { + $ExoRequestParam = @{ + tenantid = $TenantFilter + cmdParams = @{ + Identity = $RuleName + } + useSystemMailbox = $true + } + + switch ($State) { + 'Enable' { + $ExoRequestParam.Add('cmdlet', 'Enable-SafeAttachmentRule') + } + 'Disable' { + $ExoRequestParam.Add('cmdlet', 'Disable-SafeAttachmentRule') + } + Default { + throw 'Invalid state' + } + } + $null = New-ExoRequest @ExoRequestParam + + $Result = "Successfully set SafeAttachment rule $($RuleName) to $($State)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed setting SafeAttachment rule $($RuleName) to $($State). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSafeLinksFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSafeLinksFilter.ps1 new file mode 100644 index 000000000000..fd7b11144b48 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSafeLinksFilter.ps1 @@ -0,0 +1,57 @@ +function Invoke-EditSafeLinksFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $RuleName = $Request.Query.RuleName ?? $Request.Body.RuleName + $State = $Request.Query.State ?? $Request.Body.State + + try { + $ExoRequestParam = @{ + tenantid = $TenantFilter + cmdParams = @{ + Identity = $RuleName + } + useSystemMailbox = $true + } + + switch ($State) { + 'Enable' { + $ExoRequestParam.Add('cmdlet', 'Enable-SafeLinksRule') + } + 'Disable' { + $ExoRequestParam.Add('cmdlet', 'Disable-SafeLinksRule') + } + Default { + throw 'Invalid state' + } + } + $null = New-ExoRequest @ExoRequestParam + + $Result = "Successfully set SafeLinks rule $($RuleName) to $($State)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed setting SafeLinks rule $($RuleName) to $($State). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSpamFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSpamFilter.ps1 new file mode 100644 index 000000000000..7559e53ab41c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-EditSpamFilter.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-EditSpamFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.SpamFilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $TenantFilter = $request.Query.tenantFilter + $Name = $Request.Query.name ?? $Request.Body.name + $State = $State ?? $Request.Body.state + + try { + $Params = @{ + Identity = $Name + } + $Cmdlet = if ($State -eq 'enable') { 'Enable-HostedContentFilterRule' } else { 'Disable-HostedContentFilterRule' } + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet $Cmdlet -cmdParams $Params -useSystemMailbox $true + $Result = "Set Spamfilter rule $($Name) to $($State)" + Write-LogMessage -headers $Request.Headers -API $APIName -tenant $TenantFilter -message $Result -sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed setting Spamfilter rule $($Name) to $($State). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Request.Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ExecQuarantineManagement.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecQuarantineManagement.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ExecQuarantineManagement.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListConnectionFilter.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilter.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListConnectionFilter.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilterTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListConnectionFilterTemplates.ps1 similarity index 89% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilterTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListConnectionFilterTemplates.ps1 index 08d32756da2f..b799ab74a6e1 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListConnectionFilterTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListConnectionFilterTemplates.ps1 @@ -11,7 +11,8 @@ Function Invoke-ListConnectionFilterTemplates { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $Table = Get-CippTable -tablename 'templates' #List new policies diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantine.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantine.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantine.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantine.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantineMessage.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantineMessage.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMailQuarantineMessage.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantineMessage.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamFilterTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListSpamFilterTemplates.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamFilterTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListSpamFilterTemplates.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamfilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListSpamfilter.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListSpamfilter.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListSpamfilter.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveConnectionfilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveConnectionfilterTemplate.ps1 new file mode 100644 index 000000000000..c472b44a4382 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveConnectionfilterTemplate.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-RemoveConnectionfilterTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -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 + $Result = "Removed Connection Filter template with ID $($ID)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove Connection Filter template with ID $ID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{'Results' = $Result } + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveSpamfilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveSpamfilter.ps1 new file mode 100644 index 000000000000..802139a386d7 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveSpamfilter.ps1 @@ -0,0 +1,43 @@ +using namespace System.Net + +Function Invoke-RemoveSpamfilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Query.tenantFilter + $Name = $Request.Query.name ?? $Request.Body.name + + + try { + $Params = @{ + Identity = $Name + } + $Cmdlet = 'Remove-HostedContentFilterRule' + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet $Cmdlet -cmdParams $Params -useSystemMailbox $true + $Cmdlet = 'Remove-HostedContentFilterPolicy' + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet $Cmdlet -cmdParams $Params -useSystemMailbox $true + $Result = "Deleted Spam filter rule $($Name)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Info + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to delete Spam filter rule $($Name) - $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{Results = $Result } + }) + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveSpamfilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveSpamfilterTemplate.ps1 new file mode 100644 index 000000000000..e21d916ec5ee --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-RemoveSpamfilterTemplate.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-RemoveSpamfilterTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Spamfilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $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 + $Result = "Removed Spamfilter template with ID $ID" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove Spam filter Rule template $ID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{'Results' = $Result } + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ExecMailTest.ps1 similarity index 97% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ExecMailTest.ps1 index 52281c5e24d4..e537a7d6ebdc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailTest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ExecMailTest.ps1 @@ -12,9 +12,6 @@ Function Invoke-ExecMailTest { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - try { switch ($Request.Query.Action) { 'CheckConfig' { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ExecMailboxRestore.ps1 similarity index 97% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ExecMailboxRestore.ps1 index b80c2fc0c750..8e46b2d163bb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ExecMailboxRestore.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ExecMailboxRestore.ps1 @@ -8,7 +8,8 @@ function Invoke-ExecMailboxRestore { Param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' try { switch ($Request.Query.Action) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListExoRequest.ps1 similarity index 95% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListExoRequest.ps1 index 6e31de2403ce..c64c99a7ee92 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListExoRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListExoRequest.ps1 @@ -1,6 +1,10 @@ function Invoke-ListExoRequest { param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + try { $AllowedVerbs = @( 'Get' @@ -12,6 +16,7 @@ function Invoke-ListExoRequest { $Verb = ($Cmdlet -split '-')[0] $AllowedTenants = Test-CIPPAccess -Request $Request -TenantList + $TenantFilter = $Request.Body.TenantFilter $Tenants = Get-Tenants -IncludeErrors $Tenant = $Tenants | Where-Object { $_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRestores.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListMailboxRestores.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListMailboxRestores.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListMailboxRestores.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListMessageTrace.ps1 similarity index 95% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListMessageTrace.ps1 index c2f51fd1d89e..13f1f68a5fde 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListMessageTrace.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Tools/Invoke-ListMessageTrace.ps1 @@ -10,6 +10,10 @@ Function Invoke-ListMessageTrace { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + try { $TenantFilter = $Request.Body.tenantFilter diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddConnectionFilter.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddConnectionFilter.ps1 new file mode 100644 index 000000000000..c5443c3f5010 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddConnectionFilter.ps1 @@ -0,0 +1,41 @@ +using namespace System.Net + +Function Invoke-AddConnectionFilter { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.ConnectionFilter.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -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 { + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-HostedConnectionFilterPolicy' -cmdParams $RequestParams + "Successfully created Connection filter for $TenantFilter." + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Successfully created Connection filter for $TenantFilter." -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + "Failed to create Connection Filter rule for $($TenantFilter): $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to create connection filter rule for $($TenantFilter): $($ErrorMessage.NormalizedError)" -sev Error -LogData $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-AddConnectionFilterTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddConnectionFilterTemplate.ps1 similarity index 65% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilterTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddConnectionFilterTemplate.ps1 index a6d509c168cf..3b4230d3dd70 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddConnectionFilterTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddConnectionFilterTemplate.ps1 @@ -11,7 +11,9 @@ Function Invoke-AddConnectionFilterTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + Write-Host ($request | ConvertTo-Json -Compress) try { @@ -19,8 +21,7 @@ Function Invoke-AddConnectionFilterTemplate { $JSON = if ($request.body.PowerShellCommand) { Write-Host 'PowerShellCommand' $request.body.PowerShellCommand | ConvertFrom-Json - } - else { + } 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 @@ -35,20 +36,21 @@ Function Invoke-AddConnectionFilterTemplate { RowKey = "$GUID" PartitionKey = 'ConnectionfilterTemplate' } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Created Connection Filter Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' - $body = [pscustomobject]@{'Results' = 'Successfully added template' } - - } - catch { - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Failed to create Connection Filter Template: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "ConnectionFilter Template Deployment failed: $($_.Exception.Message)" } + $Result = "Successfully created Connection Filter Template: $($Request.Body.name) with GUID $GUID" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Debug' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to create Connection Filter Template: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{Results = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 new file mode 100644 index 000000000000..4991eebd0a8a --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnector.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-AddExConnector { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Connector.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + + $ConnectorType = ($Request.Body.PowerShellCommand | ConvertFrom-Json).cippConnectorType + $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, cippConnectorType, comments + + $Tenants = ($Request.Body.selectedTenants).value + $Result = foreach ($TenantFilter in $Tenants) { + try { + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet "New-$($ConnectorType)connector" -cmdParams $RequestParams + "Successfully created Connector for $TenantFilter." + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Successfully created Connector for $TenantFilter." -sev 'Info' + } catch { + $ErrorMessage = Get-CippException -Exception $_ + "Could not create Connector for $($TenantFilter): $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Could not create Connector for $($TenantFilter): $($ErrorMessage.NormalizedError)" -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-AddExConnectorTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnectorTemplate.ps1 similarity index 63% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnectorTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnectorTemplate.ps1 index a91f35176339..f8580410ed3a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddExConnectorTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddExConnectorTemplate.ps1 @@ -11,24 +11,24 @@ Function Invoke-AddExConnectorTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - Write-Host ($request | ConvertTo-Json -Compress) + Write-Host ($Request | ConvertTo-Json -Compress) try { $GUID = (New-Guid).GUID - $Select = if ($Request.body.cippconnectortype -eq 'outbound') { + $Select = if ($Request.Body.cippconnectortype -eq 'outbound') { @( 'name', 'AllAcceptedDomains', 'CloudServicesMailEnabled', 'Comment', 'Confirm', 'ConnectorSource', 'ConnectorType', 'Enabled', 'IsTransportRuleScoped', 'RecipientDomains', 'RouteAllMessagesViaOnPremises', 'SenderRewritingEnabled', 'SmartHosts', 'TestMode', 'TlsDomain', 'TlsSettings', 'UseMXRecord' ) - } - else { + } else { @( 'name', 'SenderDomains', 'ConnectorSource', 'ConnectorType', 'EFSkipIPs', 'EFSkipLastIP', 'EFSkipMailGateway', 'EFTestMode', 'EFUsers', 'Enabled ', 'RequireTls', 'RestrictDomainsToCertificate', 'RestrictDomainsToIPAddresses', 'ScanAndDropRecipients', 'SenderIPAddresses', 'TlsSenderCertificateName', 'TreatMessagesAsInternal', 'TrustedOrganizations' ) } - $JSON = ([pscustomobject]$Request.body | Select-Object $Select) | ForEach-Object { + $JSON = ([pscustomobject]$Request.Body | Select-Object $Select) | ForEach-Object { $NonEmptyProperties = $_.psobject.Properties | Where-Object { $null -ne $_.Value } | Select-Object -ExpandProperty Name $_ | Select-Object -Property $NonEmptyProperties } @@ -36,24 +36,26 @@ Function Invoke-AddExConnectorTemplate { $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ - JSON = "$json" + JSON = "$JSON" RowKey = "$GUID" - direction = $request.body.cippconnectortype + direction = $Request.Body.cippconnectortype PartitionKey = 'ExConnectorTemplate' } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Created Connector Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' - $body = [pscustomobject]@{'Results' = 'Successfully added template' } - } - catch { - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Failed to create Connector Template: $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Connector Template creation failed: $($_.Exception.Message)" } + $Result = "Successfully created Connector Template: $($Request.Body.name) with GUID $GUID" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Debug' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to create Connector Template: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{Results = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportRule.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportRule.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportRule.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportTemplate.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-AddTransportTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportTemplate.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-EditExConnector.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditExConnector.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-EditExConnector.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-EditTransportRule.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-EditTransportRule.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-EditTransportRule.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListExConnectorTemplates.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListExConnectorTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListExConnectorTemplates.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListExchangeConnectors.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListExchangeConnectors.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListExchangeConnectors.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 similarity index 82% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 index 702247ac6b3e..aeb9f976be35 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRules.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRules.ps1 @@ -11,11 +11,11 @@ Function Invoke-ListTransportRules { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.Query.tenantfilter + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $request.Query.tenantFilter try { - $GraphRequest = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-TransportRule' + $GraphRequest = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-TransportRule' $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRulesTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRulesTemplates.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Invoke-ListTransportRulesTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-ListTransportRulesTemplates.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveExConnector.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-RemoveExConnector.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveExConnector.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveExConnectorTemplate.ps1 similarity index 50% rename from Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveExConnectorTemplate.ps1 index 72eb798e3930..9a0174ca718e 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveExConnectorTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveExConnectorTemplate.ps1 @@ -11,28 +11,30 @@ Function Invoke-RemoveExConnectorTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $ID = $Request.Query.ID ?? $Request.Body.ID try { $Table = Get-CippTable -tablename 'templates' $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 -Headers $User -API $APINAME -message "Removed Exchange Connector Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Exchange Connector Template' } + Remove-AzDataTableEntity -Force @Table -Entity $ClearRow + $Result = "Removed Exchange Connector Template with ID $ID." + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove Exchange Connector Template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($ErrorMessage.NormalizedError)" } + $Result = "Failed to remove Exchange Connector Template $($ID): $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{'Results' = $Result } }) diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveTransportRule.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-RemoveTransportRule.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveTransportRule.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveTransportRuleTemplate.ps1 similarity index 55% rename from Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveTransportRuleTemplate.ps1 index a5b744b89b7f..7e24d5453f54 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-RemoveTransportRuleTemplate.ps1 @@ -14,25 +14,27 @@ Function Invoke-RemoveTransportRuleTemplate { $User = $Request.Headers Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $ID = $request.query.id ?? $request.body.id + $ID = $request.query.ID ?? $request.body.ID try { $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'TransportTemplate' and RowKey eq '$id'" $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -Headers $User -API $APINAME -message "Removed Transport Rule Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Transport Rule Template' } + Remove-AzDataTableEntity -Force @Table -Entity $ClearRow + $Result = "Removed Transport Rule Template with ID $ID." + Write-LogMessage -Headers $User -API $APINAME -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove Transport Rule template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($ErrorMessage.NormalizedError)" } + $Result = "Failed to remove Transport Rule template with ID $ID. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $User -API $APINAME -message $Result -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 - Body = $body + StatusCode = $StatusCode + Body = @{ Results = $Result } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 index 9fc4e3200ea5..a1109f79386a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListApplicationQueue.ps1 @@ -11,11 +11,10 @@ Function Invoke-ListApplicationQueue { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' $Table = Get-CippTable -tablename 'apps' $QueuedApps = (Get-CIPPAzDataTableEntity @Table) @@ -24,7 +23,7 @@ Function Invoke-ListApplicationQueue { $ApplicationFile = $QueueFile.JSON | ConvertFrom-Json -Depth 10 [PSCustomObject]@{ tenantName = $ApplicationFile.tenant - applicationName = $ApplicationFile.Applicationname + applicationName = $ApplicationFile.applicationName cmdLine = $ApplicationFile.IntuneBody.installCommandLine assignTo = $ApplicationFile.assignTo id = $($QueueFile.RowKey) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 index 685d06eacf37..3048b6789138 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ListAppsRepository.ps1 @@ -11,7 +11,8 @@ Function Invoke-ListAppsRepository { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $Search = $Request.Body.Search $Repository = $Request.Body.Repository diff --git a/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-RemoveApp.ps1 similarity index 53% rename from Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-RemoveApp.ps1 index b38057ad16ee..3f9f1b3596f4 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-RemoveApp.ps1 @@ -11,29 +11,31 @@ Function Invoke-RemoveApp { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $policyId = $Request.Query.ID + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $policyId = $Request.Query.ID ?? $Request.Body.ID + if (!$policyId) { exit } try { #$unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($policyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($policyId)" -type DELETE -tenant $TenantFilter - Write-LogMessage -Headers $User -API $APINAME -message "Deleted $policyId" -Sev 'Info' -tenant $TenantFilter - $body = [pscustomobject]@{'Results' = 'Successfully deleted the application' } + $Result = "Successfully deleted app with $policyId" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev Info -tenant $TenantFilter + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Could not delete app $policyId. $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Could not delete this application: $($ErrorMessage.NormalizedError)" } - + $Result = "Failed to delete app with $policyId. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev Error -tenant $TenantFilter -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{'Results' = "$Result" } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSyncAPDevices.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecSyncAPDevices.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ExecSyncAPDevices.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ExecSyncAPDevices.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ListAutopilotconfig.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListAutopilotconfig.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-ListAutopilotconfig.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-RemoveAPDevice.ps1 similarity index 64% rename from Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-RemoveAPDevice.ps1 index c04a4c40b4ed..839a5410bb22 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveAPDevice.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Autopilot/Invoke-RemoveAPDevice.ps1 @@ -12,12 +12,10 @@ Function Invoke-RemoveAPDevice { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -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 - $Deviceid = $Request.Query.ID + $TenantFilter = $Request.Query.tenantFilter ?? $Request.body.tenantFilter + $Deviceid = $Request.Query.ID ?? $Request.body.ID try { if ($null -eq $TenantFilter -or $TenantFilter -eq 'null') { @@ -25,19 +23,22 @@ Function Invoke-RemoveAPDevice { } else { $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities/$Deviceid" -tenantid $TenantFilter -type DELETE } - Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APINAME -message "Deleted autopilot device $Deviceid" -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully deleted the autopilot device' } + $Result = "Deleted autopilot device $Deviceid" + Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APINAME -message "Autopilot Delete API failed for $deviceid. The error is: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Failed to delete device: $($ErrorMessage.NormalizedError)" } + $Result = "Failed to delete device $($Deviceid): $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } - #force a sync, this can give "too many requests" if deleleting a bunch of devices though. + # Force a sync, this can give "too many requests" if deleting a bunch of devices though. $null = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotSettings/sync' -tenantid $TenantFilter -type POST -body '{}' + $Body = [pscustomobject]@{'Results' = "$Result" } # 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/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddDefenderDeployment.ps1 index 95de673985c4..b355013cdb96 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 @@ -14,7 +14,7 @@ Function Invoke-AddDefenderDeployment { Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' $Tenants = ($Request.body.selectedTenants).value - if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants).defaultDomainName } + if ('AllTenants' -in $Tenants) { $Tenants = (Get-Tenants -IncludeErrors).defaultDomainName } $Compliance = $request.body.Compliance $PolicySettings = $request.body.Policy $ASR = $request.body.ASR @@ -35,7 +35,12 @@ Function Invoke-AddDefenderDeployment { iosMobileApplicationManagementEnabled = [bool]$Compliance.appSync microsoftDefenderForEndpointAttachEnabled = [bool]$true } | ConvertTo-Json -Compress - $ExistingSettings = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/fc780465-2017-40d4-a0c5-307022471b92' -tenantid $tenant + try { + $ExistingSettings = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/mobileThreatDefenseConnectors/fc780465-2017-40d4-a0c5-307022471b92' -tenantid $tenant + } catch { + $ExistingSettings = $false + } + if ($ExistingSettings) { "Defender Intune Configuration already active for $($Tenant). Skipping" } else { @@ -81,9 +86,9 @@ Function Invoke-AddDefenderDeployment { @{ '@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) { + $CheckExisting = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant + Write-Host ($CheckExisting | ConvertTo-Json) + if ('Default AV Policy' -in $CheckExisting.Name) { "$($Tenant): AV Policy already exists. Skipping" } else { $PolBody = ConvertTo-Json -Depth 10 -Compress -InputObject @{ @@ -93,8 +98,11 @@ Function Invoke-AddDefenderDeployment { technologies = 'mdm,microsoftSense' roleScopeTagIds = @('0') templateReference = @{templateId = '804339ad-1553-4478-a742-138fb5807418_1' } - settings = $Settings + settings = @($Settings) } + + Write-Information ($PolBody) + $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"}}]}' } @@ -123,8 +131,6 @@ Function Invoke-AddDefenderDeployment { { $_.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 = '' @@ -147,14 +153,16 @@ Function Invoke-AddDefenderDeployment { "$($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 -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + if (($ASRSettings | Measure-Object).Count -gt 0) { + $ASRRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies' -tenantid $tenant -type POST -body $ASRbody + Write-Host ($ASRRequest.id) + if ($ASR.AssignTo -and $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 -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + } + "$($Tenant): Successfully added ASR Settings" } - "$($Tenant): Successfully added ASR Settings" } } if ($EDR) { @@ -209,27 +217,29 @@ Function Invoke-AddDefenderDeployment { } } - $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 -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned EDR policy $($Displayname) to $($ASR.AssignTo)" -Sev 'Info' + if (($EDRSettings | Measure-Object).Count -gt 0) { + $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 -and $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 -headers $Request.Headers -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 { 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 24c00cf0adff..d85863fbbe41 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 @@ -11,7 +11,8 @@ Function Invoke-AddIntuneTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' $GUID = (New-Guid).GUID try { 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 5cf66fec102d..67fcdae69680 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 @@ -18,6 +18,7 @@ Function Invoke-AddPolicy { $displayname = $Request.Body.displayName $description = $Request.Body.Description $AssignTo = if ($Request.Body.AssignTo -ne 'on') { $Request.Body.AssignTo } + $ExcludeGroup = $Request.Body.excludeGroup $Request.body.customGroup ? ($AssignTo = $Request.body.customGroup) : $null $RawJSON = $Request.Body.RAWJson @@ -27,7 +28,7 @@ Function Invoke-AddPolicy { } try { Write-Host 'Calling Adding policy' - Set-CIPPIntunePolicy -TemplateType $Request.body.TemplateType -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $AssignTo -tenantFilter $Tenant -Headers $Request.Headers + Set-CIPPIntunePolicy -TemplateType $Request.body.TemplateType -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $AssignTo -ExcludeGroup $ExcludeGroup -tenantFilter $Tenant -Headers $Request.Headers Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Added policy $($Displayname)" -Sev 'Info' } catch { "$($_.Exception.Message)" 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 6c1b711d7c4d..e4db5b138966 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 @@ -11,31 +11,33 @@ Function Invoke-ExecAssignPolicy { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenant = $request.body.tenantfilter - $ID = $request.body.id - $displayname = $request.body.Displayname - $AssignTo = if ($request.body.Assignto -ne 'on') { $request.body.Assignto } + # Interact with the body of the request + $TenantFilter = $Request.Body.tenantFilter + $ID = $request.Body.ID + $Type = $Request.Body.Type + $AssignTo = $Request.Body.AssignTo + + $AssignTo = if ($AssignTo -ne 'on') { $AssignTo } $results = try { if ($AssignTo) { - $assign = Set-CIPPAssignedPolicy -PolicyId $ID -TenantFilter $tenant -GroupName $AssignTo -Type $Request.body.Type -Headers $Request.Headers - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Assigned policy $($Displayname) to $AssignTo" -Sev 'Info' + $null = Set-CIPPAssignedPolicy -PolicyId $ID -TenantFilter $TenantFilter -GroupName $AssignTo -Type $Type -Headers $Headers } - "Successfully edited policy for $($Tenant)" + "Successfully edited policy for $($TenantFilter)" + $StatusCode = [HttpStatusCode]::OK } catch { - "Failed to add policy for $($Tenant): $($_.Exception.Message)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Failed editing policy $($Displayname). Error:$($_.Exception.Message)" -Sev 'Error' - continue + "Failed to add policy for $($TenantFilter): $($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError } - $body = [pscustomobject]@{'Results' = $results } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{Results = $results } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 index 9d7eed11b7fb..2ab268e9a852 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ExecGetRecoveryKey.ps1 @@ -11,28 +11,25 @@ Function Invoke-ExecGetRecoveryKey { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - try { - $GraphRequest = Get-CIPPBitlockerKey -device $Request.query.GUID -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers - $Body = [pscustomobject]@{'Results' = $GraphRequest } + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $GUID = $Request.Query.GUID ?? $Request.Body.GUID + try { + $Result = Get-CIPPBitLockerKey -device $GUID -tenantFilter $TenantFilter -APIName $APIName -Headers $Headers + $StatusCode = [HttpStatusCode]::OK } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Body = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } - + $Result = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body + StatusCode = $StatusCode + Body = @{Results = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListDefenderState.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderState.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListDefenderState.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListDefenderTVM.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListDefenderTVM.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListDefenderTVM.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 new file mode 100644 index 000000000000..a54285faeef4 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntunePolicy.ps1 @@ -0,0 +1,124 @@ + +Function Invoke-ListIntunePolicy { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Endpoint.MEM.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -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 + $id = $Request.Query.ID + $URLName = $Request.Query.URLName + try { + if ($ID) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($URLName)('$ID')" -tenantid $TenantFilter + } else { + $Groups = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$top=999' -tenantid $TenantFilter | Select-Object -Property id, displayName + + $BulkRequests = [PSCustomObject]@( + @{ + id = 'DeviceConfigurations' + method = 'GET' + url = "/deviceManagement/deviceConfigurations?`$select=id,displayName,lastModifiedDateTime,roleScopeTagIds,microsoft.graph.unsupportedDeviceConfiguration/originalEntityTypeName,description&`$expand=assignments&top=1000" + } + @{ + id = 'WindowsDriverUpdateProfiles' + method = 'GET' + url = "/deviceManagement/windowsDriverUpdateProfiles?`$expand=assignments&top=200" + } + @{ + id = 'WindowsFeatureUpdateProfiles' + method = 'GET' + url = "/deviceManagement/windowsFeatureUpdateProfiles?`$expand=assignments&top=200" + } + @{ + id = 'GroupPolicyConfigurations' + method = 'GET' + url = "/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=1000" + } + @{ + id = 'MobileAppConfigurations' + method = 'GET' + url = "/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" + } + @{ + id = 'ConfigurationPolicies' + method = 'GET' + url = "/deviceManagement/configurationPolicies?`$expand=assignments&top=1000" + } + ) + + $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' } + '*windowsFeatureUpdateProfiles*' { 'Feature Update' } + 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 ($null -eq $_.displayname) { $_ | 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 { $null -ne $_.DisplayName } + } + } + + # Filter the results to sort out linux scripts + $GraphRequest = $GraphRequest | Where-Object { $_.platforms -ne 'linux' -and $_.templateReference.templateFamily -ne 'deviceConfigurationScripts' } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $StatusCode = [HttpStatusCode]::Forbidden + $GraphRequest = $ErrorMessage + } + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @($GraphRequest) + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntuneTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneScript.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneScript.ps1 index 4770fbe1638a..d88f03a9f998 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneScript.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneScript.ps1 @@ -14,12 +14,11 @@ function Invoke-RemoveIntuneScript { $Headers = $Request.Headers Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev Debug - Write-Host 'PowerShell HTTP trigger function processed a request.' - - $TenantFilter = $Request.body.TenantFilter - $ID = $Request.body.ID - $ScriptType = $Request.body.ScriptType - $DisplayName = $Request.body.DisplayName + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Body.TenantFilter + $ID = $Request.Body.ID + $ScriptType = $Request.Body.ScriptType + $DisplayName = $Request.Body.DisplayName try { @@ -41,10 +40,12 @@ function Invoke-RemoveIntuneScript { $null = New-GraphPOSTRequest -uri $URI -type DELETE -tenantid $TenantFilter $Result = "Deleted $($ScriptType) script $($DisplayName) with ID: $($ID)" + Write-LogMessage -headers $.Headers -API $APINAME -tenant $Tenant -message $Result -Sev 'Info' $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ $Result = "Failed to delete $($ScriptType) script $($DisplayName). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APINAME -tenant $Tenant -message $Result -Sev 'Error' $StatusCode = [HttpStatusCode]::Forbidden } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneTemplate.ps1 similarity index 52% rename from Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneTemplate.ps1 index 636cf3fe7cfc..ab5fc1a85cb2 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemoveIntuneTemplate.ps1 @@ -11,30 +11,32 @@ Function Invoke-RemoveIntuneTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -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' - Write-Host $id + Write-Host $ID - $Filter = "PartitionKey eq 'IntuneTemplate' and RowKey eq '$id'" + $Filter = "PartitionKey eq 'IntuneTemplate' and RowKey eq '$ID'" Write-Host $Filter $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -Headers $User -API $APINAME -message "Removed Intune Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Intune Template' } + $Result = "Removed Intune Template with ID $ID" + Write-LogMessage -Headers $Headers -API $APINAME -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove intune template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($ErrorMessage.NormalizedError)" } + $Result = "Failed to remove Intune template $($ID): $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APINAME -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{'Results' = $Result } }) diff --git a/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemovePolicy.ps1 similarity index 84% rename from Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemovePolicy.ps1 index 2720fda34755..af0206cc0619 100644 --- a/Modules/CIPPCore/Public/Invoke-RemovePolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemovePolicy.ps1 @@ -22,7 +22,7 @@ Function Invoke-RemovePolicy { if (!$PolicyId) { exit } try { - #$unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($PolicyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter + # $unAssignRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies('$($PolicyId)')/assign" -type POST -Body '{"assignments":[]}' -tenant $TenantFilter $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($UrlName)('$($PolicyId)')" -type DELETE -tenant $TenantFilter $Results = "Successfully deleted the policy with ID: $($PolicyId)" Write-LogMessage -headers $Headers -API $APINAME -message $Results -Sev Info -tenant $TenantFilter @@ -35,11 +35,11 @@ Function Invoke-RemovePolicy { $StatusCode = [HttpStatusCode]::Forbidden } - $body = [pscustomobject]@{'Results' = "$Results" } + $Body = [pscustomobject]@{'Results' = "$Results" } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = $body + Body = $Body }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupSenderAuthentication.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupSenderAuthentication.ps1 index 11d70a0f2f8a..70672eb22229 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupSenderAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupSenderAuthentication.ps1 @@ -6,11 +6,8 @@ Function Invoke-ListGroupSenderAuthentication { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -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 $groupid = $Request.query.groupid $GroupType = $Request.query.Type @@ -28,7 +25,7 @@ Function Invoke-ListGroupSenderAuthentication { } 'Microsoft 365' { Write-Host 'Checking M365 Group' - $State = (New-ExoRequest -tenantid $TenantFilter -cmdlet 'get-unifiedgroup' -cmdParams $params -UseSystemMailbox $true).RequireSenderAuthenticationEnabled + $State = (New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-UnifiedGroup' -cmdParams $params -UseSystemMailbox $true).RequireSenderAuthenticationEnabled } default { $state = $true } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupTemplates.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroupTemplates.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroupTemplates.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListGroups.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-ListGroups.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-RemoveGroupTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-RemoveGroupTemplate.ps1 new file mode 100644 index 000000000000..a639ce683b81 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-RemoveGroupTemplate.ps1 @@ -0,0 +1,44 @@ +using namespace System.Net + +Function Invoke-RemoveGroupTemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.Group.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $ID = $request.Query.ID ?? $Request.Body.ID + try { + $Table = Get-CippTable -tablename 'templates' + Write-Host $ID + + $Filter = "PartitionKey eq 'GroupTemplate' and RowKey eq '$ID'" + Write-Host $Filter + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity -Force @Table -Entity $ClearRow + $Result = "Removed Group Template with ID $ID" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove group template $($ID): $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{'Results' = $Result } + }) + + +} 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 31cae1bd1f10..d84dd6bc8bcb 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 @@ -11,47 +11,51 @@ Function Invoke-AddGuest { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $TenantFilter = $Request.Body.tenantFilter $Results = [System.Collections.ArrayList]@() - $userobj = $Request.body - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + $UserObject = $Request.Body try { - if ($userobj.RedirectURL) { + if ($UserObject.RedirectURL) { $BodyToship = [pscustomobject] @{ - 'InvitedUserDisplayName' = $userobj.Displayname - 'InvitedUserEmailAddress' = $($userobj.mail) - 'inviteRedirectUrl' = $($userobj.RedirectURL) - 'sendInvitationMessage' = [boolean]$userobj.SendInvite + 'InvitedUserDisplayName' = $UserObject.DisplayName + 'InvitedUserEmailAddress' = $($UserObject.mail) + 'inviteRedirectUrl' = $($UserObject.RedirectURL) + 'sendInvitationMessage' = [bool]$UserObject.SendInvite } } else { $BodyToship = [pscustomobject] @{ - 'InvitedUserDisplayName' = $userobj.Displayname - 'InvitedUserEmailAddress' = $($userobj.mail) - 'sendInvitationMessage' = [boolean]$userobj.SendInvite + 'InvitedUserDisplayName' = $UserObject.DisplayName + 'InvitedUserEmailAddress' = $($UserObject.mail) + 'sendInvitationMessage' = [bool]$UserObject.SendInvite 'inviteRedirectUrl' = 'https://myapps.microsoft.com' } } $bodyToShip = ConvertTo-Json -Depth 10 -InputObject $BodyToship -Compress - $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/invitations' -tenantid $Userobj.tenantFilter -type POST -body $BodyToship -verbose - if ($Userobj.sendInvite -eq 'true') { - $results.add('Invited Guest. Invite Email sent') - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($userobj.tenantFilter) -message "Invited Guest $($userobj.displayname) with Email Invite " -Sev 'Info' + $null = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/invitations' -tenantid $TenantFilter -type POST -body $BodyToship -verbose + if ($UserObject.SendInvite -eq $true) { + $Results.Add('Invited Guest. Invite Email sent') + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message "Invited Guest $($UserObject.DisplayName) with Email Invite " -Sev 'Info' } else { - $results.add('Invited Guest. No Invite Email was sent') - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($userobj.tenantFilter) -message "Invited Guest $($userobj.displayname) with no Email Invite " -Sev 'Info' + $Results.Add('Invited Guest. No Invite Email was sent') + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message "Invited Guest $($UserObject.DisplayName) with no Email Invite " -Sev 'Info' } + $StatusCode = [HttpStatusCode]::OK } catch { - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($userobj.tenantFilter) -message "Guest Invite API failed. $($_.Exception.Message)" -Sev 'Error' - $body = $results.add("Failed to Invite Guest. $($_.Exception.Message)" ) + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to Invite Guest. $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Error' -LogData $ErrorMessage + $Results.Add($Result) + $StatusCode = [HttpStatusCode]::BadRequest } - $body = @{'Results' = @($results) } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body + StatusCode = $StatusCode + Body = @{Results = @($Results) } }) } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 similarity index 69% rename from Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 index 02d2d21114ea..3bb2fc720957 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 @@ -1,4 +1,3 @@ - function Invoke-CIPPOffboardingJob { [CmdletBinding()] param ( @@ -12,64 +11,67 @@ function Invoke-CIPPOffboardingJob { if ($Options -is [string]) { $Options = $Options | ConvertFrom-Json } - $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)?`$select=id" -tenantid $Tenantfilter).id + $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)?`$select=id" -tenantid $TenantFilter).id Write-Host "Running offboarding job for $username with options: $($Options | ConvertTo-Json -Depth 10)" $Return = switch ($Options) { - { $_.'ConvertToShared' -eq $true } { - Set-CIPPMailboxType -Headers $Headers -tenantFilter $tenantFilter -userid $username -username $username -MailboxType 'Shared' -APIName $APIName + { $_.ConvertToShared -eq $true } { + Set-CIPPMailboxType -Headers $Headers -tenantFilter $TenantFilter -userid $username -username $username -MailboxType 'Shared' -APIName $APIName } { $_.RevokeSessions -eq $true } { - Revoke-CIPPSessions -tenantFilter $tenantFilter -username $username -userid $userid -Headers $Headers -APIName $APIName + Revoke-CIPPSessions -tenantFilter $TenantFilter -username $username -userid $userid -Headers $Headers -APIName $APIName } { $_.ResetPass -eq $true } { - Set-CIPPResetPassword -tenantFilter $tenantFilter -UserID $username -Headers $Headers -APIName $APIName + Set-CIPPResetPassword -tenantFilter $TenantFilter -UserID $username -Headers $Headers -APIName $APIName } { $_.RemoveGroups -eq $true } { - Remove-CIPPGroups -userid $userid -tenantFilter $Tenantfilter -Headers $Headers -APIName $APIName -Username "$Username" + Remove-CIPPGroups -userid $userid -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName -Username "$Username" } - { $_.'HideFromGAL' -eq $true } { - Set-CIPPHideFromGAL -tenantFilter $tenantFilter -UserID $username -hidefromgal $true -Headers $Headers -APIName $APIName + { $_.HideFromGAL -eq $true } { + Set-CIPPHideFromGAL -tenantFilter $TenantFilter -UserID $username -hidefromgal $true -Headers $Headers -APIName $APIName } - { $_.'DisableSignIn' -eq $true } { - Set-CIPPSignInState -TenantFilter $tenantFilter -userid $username -AccountEnabled $false -Headers $Headers -APIName $APIName + { $_.DisableSignIn -eq $true } { + Set-CIPPSignInState -TenantFilter $TenantFilter -userid $username -AccountEnabled $false -Headers $Headers -APIName $APIName } - { $_.'OnedriveAccess' } { - $Options.OnedriveAccess | ForEach-Object { Set-CIPPSharePointPerms -tenantFilter $tenantFilter -userid $username -OnedriveAccessUser $_.value -Headers $Headers -APIName $APIName } + { $_.OnedriveAccess } { + $Options.OnedriveAccess | ForEach-Object { Set-CIPPSharePointPerms -tenantFilter $TenantFilter -userid $username -OnedriveAccessUser $_.value -Headers $Headers -APIName $APIName } } - { $_.'AccessNoAutomap' } { - $Options.AccessNoAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $false -AccessRights @('FullAccess') -Headers $Headers -APIName $APIName } + { $_.AccessNoAutomap } { + $Options.AccessNoAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $TenantFilter -userid $username -AccessUser $_.value -Automap $false -AccessRights @('FullAccess') -Headers $Headers -APIName $APIName } } - { $_.'AccessAutomap' } { - $Options.AccessAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $tenantFilter -userid $username -AccessUser $_.value -Automap $true -AccessRights @('FullAccess') -Headers $Headers -APIName $APIName } + { $_.AccessAutomap } { + $Options.AccessAutomap | ForEach-Object { Set-CIPPMailboxAccess -tenantFilter $TenantFilter -userid $username -AccessUser $_.value -Automap $true -AccessRights @('FullAccess') -Headers $Headers -APIName $APIName } } - { $_.'OOO' } { - Set-CIPPOutOfOffice -tenantFilter $tenantFilter -userid $username -InternalMessage $Options.OOO -ExternalMessage $Options.OOO -Headers $Headers -APIName $APIName -state 'Enabled' + { $_.OOO } { + Set-CIPPOutOfOffice -tenantFilter $TenantFilter -userid $username -InternalMessage $Options.OOO -ExternalMessage $Options.OOO -Headers $Headers -APIName $APIName -state 'Enabled' } - { $_.'forward' } { + { $_.forward } { if (!$Options.keepCopy) { - Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward.value -Headers $Headers -APIName $APIName + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $TenantFilter -Forward $Options.forward.value -Headers $Headers -APIName $APIName } else { $KeepCopy = [boolean]$Options.keepCopy - Set-CIPPForwarding -userid $userid -username $username -tenantFilter $Tenantfilter -Forward $Options.forward.value -KeepCopy $KeepCopy -Headers $Headers -APIName $APIName + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $TenantFilter -Forward $Options.forward.value -KeepCopy $KeepCopy -Headers $Headers -APIName $APIName } } - { $_.'RemoveLicenses' -eq $true } { - Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $Tenantfilter -Headers $Headers -APIName $APIName -Schedule + { $_.disableForwarding } { + Set-CIPPForwarding -userid $userid -username $username -tenantFilter $TenantFilter -Disable $true -Headers $Headers -APIName $APIName + } + { $_.RemoveLicenses -eq $true } { + Remove-CIPPLicense -userid $userid -username $Username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName -Schedule } - { $_.'deleteuser' -eq $true } { - Remove-CIPPUser -userid $userid -username $Username -tenantFilter $Tenantfilter -Headers $Headers -APIName $APIName + { $_.DeleteUser -eq $true } { + Remove-CIPPUser -userid $userid -username $Username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName } - { $_.'removeRules' -eq $true } { + { $_.RemoveRules -eq $true } { Write-Host "Removing rules for $username" - Remove-CIPPMailboxRule -userid $userid -username $Username -tenantFilter $Tenantfilter -Headers $Headers -APIName $APIName -RemoveAllRules + Remove-CIPPMailboxRule -userid $userid -username $Username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName -RemoveAllRules } - { $_.'removeMobile' -eq $true } { - Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $Tenantfilter -Headers $Headers -APIName $APIName + { $_.RemoveMobile -eq $true } { + Remove-CIPPMobileDevice -userid $userid -username $Username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName } - { $_.'removeCalendarInvites' -eq $true } { - Remove-CIPPCalendarInvites -userid $userid -username $Username -tenantFilter $Tenantfilter -Headers $Headers -APIName $APIName + { $_.removeCalendarInvites -eq $true } { + Remove-CIPPCalendarInvites -userid $userid -username $Username -tenantFilter $TenantFilter -Headers $Headers -APIName $APIName } - { $_.'removePermissions' } { + { $_.removePermissions } { if ($RunScheduled) { Remove-CIPPMailboxPermissions -PermissionsLevel @('FullAccess', 'SendAs', 'SendOnBehalf') -userid 'AllUsers' -AccessUser $UserName -TenantFilter $TenantFilter -APIName $APINAME -Headers $Headers 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 aaf0fd5f0a15..7c88fa1588fd 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 @@ -34,7 +34,7 @@ Function Invoke-EditUser { #Edit the user try { Write-Host "$([boolean]$UserObj.MustChangePass)" - $UserPrincipalName = "$($UserObj.Username ? $UserObj.username :$UserObj.mailNickname)@$($UserObj.Domain ? $UserObj.Domain : $UserObj.primDomain.value)" + $UserPrincipalName = "$($UserObj.username)@$($UserObj.Domain ? $UserObj.Domain : $UserObj.primDomain.value)" $BodyToship = [pscustomobject] @{ 'givenName' = $UserObj.givenName 'surname' = $UserObj.surname @@ -140,15 +140,14 @@ Function Invoke-EditUser { if ($AddToGroups) { $AddToGroups | ForEach-Object { - $GroupType = $_.value.groupType -join ',' - $GroupID = $_.value.groupid - $GroupName = $_.value.groupName + $GroupType = $_.addedFields.calculatedGroupType + $GroupID = $_.value + $GroupName = $_.label Write-Host "About to add $($UserObj.userPrincipalName) to $GroupName. Group ID is: $GroupID and type is: $GroupType" try { if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { - Write-Host 'Adding to group via Add-DistributionGroupMember ' $Params = @{ Identity = $GroupID; Member = $UserObj.id; BypassSecurityGroupManagerCheck = $true } $null = New-ExoRequest -tenantid $UserObj.tenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true @@ -182,6 +181,14 @@ Function Invoke-EditUser { $null = $results.Add("Success. Set $($UserObj.DisplayName)'s manager to $($Request.body.setManager.label)") } + if ($Request.body.setSponsor.value) { + $SponsorBody = [PSCustomObject]@{'@odata.id' = "https://graph.microsoft.com/beta/users/$($Request.body.setSponsor.value)" } + $SponsorBodyJSON = ConvertTo-Json -Compress -Depth 10 -InputObject $SponsorBody + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserObj.id)/sponsors/`$ref" -tenantid $UserObj.tenantFilter -type POST -body $SponsorBodyJSON -Verbose + Write-LogMessage -headers $Request.Headers -API $ApiName -tenant $UserObj.tenantFilter -message "Set $($UserObj.DisplayName)'s sponsor to $($Request.body.setSponsor.label)" -Sev Info + $null = $results.Add("Success. Set $($UserObj.DisplayName)'s sponsor to $($Request.body.setSponsor.label)") + } + if ($RemoveFromGroups) { $RemoveFromGroups | ForEach-Object { 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 4fc76d7300a6..c4e205aaa480 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 @@ -11,20 +11,25 @@ Function Invoke-ExecCreateTAP { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $UserID = $Request.Query.ID ?? $Request.Body.ID + try { - $TAP = New-CIPPTAP -userid $Request.query.ID -TenantFilter $Request.query.tenantfilter -APIName $APINAME -Headers $Request.Headers - $Results = [pscustomobject]@{'Results' = $TAP } + $Result = New-CIPPTAP -userid $UserID -TenantFilter $TenantFilter -APIName $APIName -Headers $Headers + $StatusCode = [HttpStatusCode]::OK } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results + StatusCode = $StatusCode + Body = @{'Results' = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 index 31aeb9f5d45f..67a2b036cffb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDisableUser.ps1 @@ -11,17 +11,28 @@ Function Invoke-ExecDisableUser { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $ID = $Request.Query.ID ?? $Request.Body.ID + $Enable = $Request.Query.Enable ?? $Request.Body.Enable + $Enable = [System.Convert]::ToBoolean($Enable) + try { - $State = Set-CIPPSignInState -userid $Request.query.ID -TenantFilter $Request.Query.TenantFilter -APIName $APINAME -Headers $Request.Headers -AccountEnabled ([System.Convert]::ToBoolean($Request.Query.Enable)) - $Results = [pscustomobject]@{'Results' = "$State" } + $Result = Set-CIPPSignInState -UserID $ID -TenantFilter $TenantFilter -APIName $APIName -Headers $Headers -AccountEnabled $Enable + if ($Result -like 'Could not disable*' -or $Result -like 'WARNING: User is AD Sync enabled*') { throw $Result } + $StatusCode = [HttpStatusCode]::OK } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $Results = [pscustomobject]@{'Results' = "Failed. $ErrorMessage" } + $Result = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError } + $Results = [pscustomobject]@{'Results' = "$Result" } # 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/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 index 53cdc664fa6c..d2b0e4efce53 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecDismissRiskyUser.ps1 @@ -9,36 +9,39 @@ function Invoke-ExecDismissRiskyUser { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - Write-Host 'PowerShell HTTP trigger function processed a request.' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $Request.Query.tenantfilter - $SuspectUser = $Request.Query.userid - $userDisplayName = $Request.Query.userDisplayName + # Interact with the query or body of the request + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $SuspectUser = $Request.Query.userId ?? $Request.Body.userId + $userDisplayName = $Request.Query.userDisplayName ?? $Request.Body.userDisplayName $GraphRequest = @{ - 'uri' = 'https://graph.microsoft.com/beta/riskyUsers/dismiss' - 'tenantid' = $TenantFilter - 'type' = 'POST' - 'contentType' = 'application/json; charset=utf-8' - 'body' = @{ + 'uri' = 'https://graph.microsoft.com/beta/riskyUsers/dismiss' + 'tenantid' = $TenantFilter + 'type' = 'POST' + 'contentType' = 'application/json; charset=utf-8' + 'body' = @{ 'userIds' = @($SuspectUser) } | ConvertTo-Json } try { $GraphResults = New-GraphPostRequest @GraphRequest - Write-LogMessage -API 'DismissRiskyUser' -tenant $TenantFilter -message "Dismissed user risk for $userDisplayName" -sev 'Info' - - $ResponseBody = [pscustomobject]@{ 'Results' = "Successfully dismissed User Risk for user $userDisplayName. $GraphResults" } + Write-LogMessage -API $APIName -tenant $TenantFilter -message "Dismissed user risk for $userDisplayName" -sev 'Info' + $Result = "Successfully dismissed User Risk for user $userDisplayName. $GraphResults" + $StatusCode = [HttpStatusCode]::OK } catch { - $ResponseBody = [pscustomobject]@{ 'Results' = "Failed to execute dismissal. $($_.Exception.Message)" } - Write-LogMessage -API 'DismissRiskyUser' -tenant $TenantFilter -message "Failed to dismiss user risk for $userDisplayName" -sev 'Error' + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to dismiss user risk for $userDisplayName. $($ErrorMessage.NormalizedError)" + Write-LogMessage -API $APIName -tenant $TenantFilter -message $Result -sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $ResponseBody - }) + StatusCode = $StatusCode + Body = @{ 'Results' = $Result } + }) } 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 f7ecd21d59e9..4cb4c25db418 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 @@ -11,25 +11,25 @@ Function Invoke-ExecResetMFA { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $UserID = $Request.Query.ID + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $UserID = $Request.Query.ID ?? $Request.Body.ID try { - - $Body = @{ - Results = Remove-CIPPUserMFA -UserPrincipalName $UserID -TenantFilter $TenantFilter -Headers $Request.Headers - } + $Result = Remove-CIPPUserMFA -UserPrincipalName $UserID -TenantFilter $TenantFilter -Headers $Headers + if ($Result -match 'Failed') { throw $Result } + $StatusCode = [HttpStatusCode]::OK } catch { - $Body = [pscustomobject]@{'Results' = "Failed to reset MFA methods for $($Request.Query.ID): $(Get-NormalizedError -message $_.Exception.Message)" } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Failed to reset MFA for user $($Request.Query.ID): $($_.Exception.Message)" -Sev 'Error' -LogData (Get-CippException -Exception $_) + $Result = "$($_.Exception.Message)" + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Body + StatusCode = $StatusCode + Body = @{ 'Results' = $Result } }) } 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 60f78066ef3b..53f86a6975c5 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 @@ -14,25 +14,28 @@ Function Invoke-ExecResetPass { Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - Write-Host "$($Request.query.ID)" # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $mustChange = [System.Convert]::ToBoolean($request.query.MustChange) + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $ID = $Request.Query.ID ?? $Request.Body.ID + $DisplayName = $Request.Query.displayName ?? $Request.Body.displayName + $MustChange = $Request.Query.MustChange ?? $Request.Body.MustChange + $MustChange = [System.Convert]::ToBoolean($MustChange) try { - $Reset = Set-CIPPResetPassword -userid $Request.query.ID -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -forceChangePasswordNextSignIn $mustChange - $Results = [pscustomobject]@{'Results' = $Reset } + $Result = Set-CIPPResetPassword -UserID $ID -tenantFilter $TenantFilter -APIName $APINAME -Headers $Request.Headers -forceChangePasswordNextSignIn $MustChange -DisplayName $DisplayName + if ($Result.state -eq 'Error') { throw $Result.resultText } + $StatusCode = [HttpStatusCode]::OK } catch { - $Results = [pscustomobject]@{'Results' = "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Failed to reset password for $($Request.query.displayName): $($_.Exception.Message)" -Sev 'Error' + $Result = $_.Exception.Message + Write-LogMessage -headers $Request.Headers -API $APINAME -message $Result -Sev 'Error' + $StatusCode = [HttpStatusCode]::InternalServerError } + $Results = [pscustomobject]@{'Results' = $Result } # 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/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 new file mode 100644 index 000000000000..e2d85fae5706 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRestoreDeleted.ps1 @@ -0,0 +1,39 @@ +using namespace System.Net + +Function Invoke-ExecRestoreDeleted { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.Directory.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.TenantFilter ?? $Request.Body.TenantFilter + $RequestID = $Request.Query.ID ?? $Request.Body.ID + + try { + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($RequestID)/restore" -tenantid $TenantFilter -type POST -body '{}' -Verbose + $Result = "Successfully restored deleted item with ID: $($RequestID)" + Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to restore deleted item with ID: $($RequestID). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Request.Headers -tenant $TenantFilter -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + $Results = [pscustomobject]@{'Results' = $Result } + # 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-ExecRevokeSessions.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 index 0c1b8bc5210d..b09d8a09fa4b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecRevokeSessions.ps1 @@ -14,17 +14,23 @@ Function Invoke-ExecRevokeSessions { Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $ID = $Request.Query.id ?? $Request.Body.id + $Username = $Request.Query.Username ?? $Request.Body.Username + try { - $RevokeSessions = Revoke-CIPPSessions -userid $Request.Query.id -tenantFilter $TenantFilter -username $Request.Query.Username -APIName $APINAME -Headers $Request.Headers - $Results = [pscustomobject]@{'Results' = $RevokeSessions } + $Result = Revoke-CIPPSessions -UserID $ID -TenantFilter $TenantFilter -Username $Username -APIName $APIName -Headers $Request.Headers + if ($Result -like 'Revoke Session Failed*') { throw $Result } + $StatusCode = [HttpStatusCode]::OK } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } + $Result = $_.Exception.Message + $StatusCode = [HttpStatusCode]::InternalServerError } + $Results = [pscustomobject]@{'Results' = $Result } # 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/Identity/Administration/Users/Invoke-ExecSendPush.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSendPush.ps1 index d077f97949bb..9eb13dbf1bfc 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 @@ -18,7 +18,7 @@ Function Invoke-ExecSendPush { $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 - function get-clientaccess { + function Get-ClientAccess { param( $uri, $body, @@ -31,7 +31,7 @@ Function Invoke-ExecSendPush { $count++ Start-Sleep 1 - $ClientToken = get-clientaccess -uri $uri -body $body -count $count + $ClientToken = Get-ClientAccess -uri $uri -body $body -count $count } else { Throw "Could not get Client Token: $_" } @@ -46,7 +46,7 @@ Function Invoke-ExecSendPush { # Check if we have one for the MFA App $SPID = ($SPResult | Where-Object { $_.appId -eq $MFAAppID }).id - # Create a serivce principal if needed + # Create a service principal if needed if (!$SPID) { $SPBody = [pscustomobject]@{ @@ -59,8 +59,8 @@ Function Invoke-ExecSendPush { $PassReqBody = @{ 'passwordCredential' = @{ 'displayName' = 'MFA Temporary Password' - 'endDateTime' = $(((Get-Date).addminutes(5))) - 'startDateTime' = $((Get-Date).addminutes(-5)) + 'endDateTime' = $((Get-Date).AddMinutes(5)) + 'startDateTime' = $((Get-Date).AddMinutes(-5)) } } | ConvertTo-Json -Depth 5 @@ -90,7 +90,7 @@ Function Invoke-ExecSendPush { # Attempt to get a token using the temp password $ClientUri = "https://login.microsoftonline.com/$TenantFilter/oauth2/token" try { - $ClientToken = get-clientaccess -Uri $ClientUri -Body $body + $ClientToken = Get-ClientAccess -Uri $ClientUri -Body $body } catch { $Body = 'Failed to create temporary token for MFA Application. Error: ' + $_.Exception.Message } @@ -107,7 +107,7 @@ Function Invoke-ExecSendPush { $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)" + $Body = "Authentication Failed! Does the user have Push/Phone call MFA configured? ErrorCode: $($obj.BeginTwoWayAuthenticationResponse.result.value | Out-String)" $colour = 'error' } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListDeletedItems.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeletedItems.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListDeletedItems.ps1 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 512ca633f54f..cac7e39d7514 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 @@ -11,13 +11,12 @@ Function Invoke-ListUserMailboxDetails { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -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 + $TenantFilter = $Request.Query.tenantFilter $UserID = $Request.Query.UserID try { @@ -76,15 +75,15 @@ Function Invoke-ListUserMailboxDetails { $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 + $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 + if ($MailboxDetailedRequest.ArchiveGuid -ne '00000000-0000-0000-0000-000000000000') { + $ArchiveEnabled = $true } else { - $ArchiveEnabled = $False + $ArchiveEnabled = $false } # Get organization config of auto-expanding archive if it's disabled on user level @@ -94,7 +93,7 @@ Function Invoke-ListUserMailboxDetails { $AutoExpandingArchiveEnabled = $MailboxDetailedRequest.AutoExpandingArchiveEnabled } } catch { - $ArchiveEnabled = $False + $ArchiveEnabled = $false $ArchiveSizeRequest = @{ TotalItemSize = '0' ItemCount = '0' @@ -155,9 +154,9 @@ Function Invoke-ListUserMailboxDetails { $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) + if ($ArchiveEnabled -eq $true) { + $TotalArchiveItemSize = try { [math]::Round([float]($TotalArchiveItemSizeString[0]), 2) } catch { 0 } + $TotalArchiveItemCount = try { [math]::Round($ArchiveSizeRequest.ItemCount, 2) } catch { 0 } } # Build the GraphRequest object @@ -177,8 +176,8 @@ Function Invoke-ListUserMailboxDetails { 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 } + TotalArchiveItemSize = $TotalArchiveItemSize + TotalArchiveItemCount = $TotalArchiveItemCount BlockedForSpam = $BlockedForSpam ArchiveMailBox = $ArchiveEnabled AutoExpandingArchive = $AutoExpandingArchiveEnabled 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 0f6ff909234f..a132268e8390 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 @@ -10,10 +10,9 @@ Function Invoke-ListUsers { [CmdletBinding()] param($Request, $TriggerMetadata) - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $Request.Params.CIPPEndpoint + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - # 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 # Interact with query parameters or the body of the request. $TenantFilter = $Request.Query.TenantFilter @@ -21,7 +20,7 @@ Function Invoke-ListUsers { $userid = $Request.Query.UserID $GraphRequest = if ($TenantFilter -ne 'AllTenants') { - New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)?`$top=999&`$filter=$GraphFilter&`$count=true" -tenantid $TenantFilter -ComplexFilter | ForEach-Object { + New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($userid)?`$top=999&`$filter=$GraphFilter&`$count=true&`$expand=manager(`$select=id,userPrincipalName,displayName)" -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 @@ -38,11 +37,11 @@ Function Invoke-ListUsers { Message = 'This function has been deprecated for all users, please use ListGraphRequest instead' } } else { - $Rows.Data | ConvertFrom-Json | Select-Object $selectlist | ForEach-Object { + $Rows.Data | ConvertFrom-Json | Select-Object $SelectList | ForEach-Object { $_.onPremisesSyncEnabled = [bool]($_.onPremisesSyncEnabled) - $_.Aliases = $_.Proxyaddresses -join ', ' + $_.Aliases = $_.proxyAddresses -join ', ' $SkuID = $_.AssignedLicenses.skuid - $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $skuid }).'Product_Display_Name' -join ', ' + $_.LicJoined = ($ConvertTable | Where-Object { $_.guid -in $SkuID }).'Product_Display_Name' -join ', ' $_.primDomain = @{value = ($_.userPrincipalName -split '@' | Select-Object -Last 1) } $_ } @@ -62,8 +61,9 @@ Function Invoke-ListUsers { endDate = $endDate UserIds = @($GraphRequest.userPrincipalName) } - $AuditlogsLogon = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam | Sort-Object -Property CreationDate | Select-Object -Last 1).auditdata | ConvertFrom-Json - $Appname = '[{"Application Name":"ACOM Azure Website","Application IDs":"23523755-3a2b-41ca-9315-f81f3f566a95"},{"Application Name":"AEM-DualAuth","Application IDs":"69893ee3-dd10-4b1c-832d-4870354be3d8"},{"Application Name":"ASM Campaign Servicing","Application IDs":"0cb7b9ec-5336-483b-bc31-b15b5788de71"},{"Application Name":"Azure Advanced Threat Protection","Application IDs":"7b7531ad-5926-4f2d-8a1d-38495ad33e17"},{"Application Name":"Azure Data Lake","Application IDs":"e9f49c6b-5ce5-44c8-925d-015017e9f7ad"},{"Application Name":"Azure Lab Services Portal","Application IDs":"835b2a73-6e10-4aa5-a979-21dfda45231c"},{"Application Name":"Azure Portal","Application IDs":"c44b4083-3bb0-49c1-b47d-974e53cbdf3c"},{"Application Name":"AzureSupportCenter","Application IDs":"37182072-3c9c-4f6a-a4b3-b3f91cacffce"},{"Application Name":"Bing","Application IDs":"9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7"},{"Application Name":"CPIM Service","Application IDs":"bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4"},{"Application Name":"CRM Power BI Integration","Application IDs":"e64aa8bc-8eb4-40e2-898b-cf261a25954f"},{"Application Name":"Dataverse","Application IDs":"00000007-0000-0000-c000-000000000000"},{"Application Name":"Enterprise Roaming and Backup","Application IDs":"60c8bde5-3167-4f92-8fdb-059f6176dc0f"},{"Application Name":"IAM Supportability","Application IDs":"a57aca87-cbc0-4f3c-8b9e-dc095fdc8978"},{"Application Name":"IrisSelectionFrontDoor","Application IDs":"16aeb910-ce68-41d1-9ac3-9e1673ac9575"},{"Application Name":"MCAPI Authorization Prod","Application IDs":"d73f4b35-55c9-48c7-8b10-651f6f2acb2e"},{"Application Name":"Media Analysis and Transformation Service","Application IDs":"944f0bd1-117b-4b1c-af26-804ed95e767e
0cd196ee-71bf-4fd6-a57c-b491ffd4fb1e"},{"Application Name":"Microsoft 365 Support Service","Application IDs":"ee272b19-4411-433f-8f28-5c13cb6fd407"},{"Application Name":"Microsoft App Access Panel","Application IDs":"0000000c-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Approval Management","Application IDs":"65d91a3d-ab74-42e6-8a2f-0add61688c74
38049638-cc2c-4cde-abe4-4479d721ed44"},{"Application Name":"Microsoft Authentication Broker","Application IDs":"29d9ed98-a469-4536-ade2-f981bc1d605e"},{"Application Name":"Microsoft Azure CLI","Application IDs":"04b07795-8ddb-461a-bbee-02f9e1bf7b46"},{"Application Name":"Microsoft Azure PowerShell","Application IDs":"1950a258-227b-4e31-a9cf-717495945fc2"},{"Application Name":"Microsoft Bing Search","Application IDs":"cf36b471-5b44-428c-9ce7-313bf84528de"},{"Application Name":"Microsoft Bing Search for Microsoft Edge","Application IDs":"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8"},{"Application Name":"Microsoft Bing Default Search Engine","Application IDs":"1786c5ed-9644-47b2-8aa0-7201292175b6"},{"Application Name":"Microsoft Defender for Cloud Apps","Application IDs":"3090ab82-f1c1-4cdf-af2c-5d7a6f3e2cc7"},{"Application Name":"Microsoft Docs","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Dynamics ERP","Application IDs":"00000015-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Edge Insider Addons Prod","Application IDs":"6253bca8-faf2-4587-8f2f-b056d80998a7"},{"Application Name":"Microsoft Exchange Online Protection","Application IDs":"00000007-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Forms","Application IDs":"c9a559d2-7aab-4f13-a6ed-e7e9c52aec87"},{"Application Name":"Microsoft Graph","Application IDs":"00000003-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Intune Web Company Portal","Application IDs":"74bcdadc-2fdc-4bb3-8459-76d06952a0e9"},{"Application Name":"Microsoft Intune Windows Agent","Application IDs":"fc0f3af4-6835-4174-b806-f7db311fd2f3"},{"Application Name":"Microsoft Learn","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Office","Application IDs":"d3590ed6-52b3-4102-aeff-aad2292ab01c"},{"Application Name":"Microsoft Office 365 Portal","Application IDs":"00000006-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Office Web Apps Service","Application IDs":"67e3df25-268a-4324-a550-0de1c7f97287"},{"Application Name":"Microsoft Online Syndication Partner Portal","Application IDs":"d176f6e7-38e5-40c9-8a78-3998aab820e7"},{"Application Name":"Microsoft password reset service","Application IDs":"93625bc8-bfe2-437a-97e0-3d0060024faa"},{"Application Name":"Microsoft Power BI","Application IDs":"871c010f-5e61-4fb1-83ac-98610a7e9110"},{"Application Name":"Microsoft Storefronts","Application IDs":"28b567f6-162c-4f54-99a0-6887f387bbcc"},{"Application Name":"Microsoft Stream Portal","Application IDs":"cf53fce8-def6-4aeb-8d30-b158e7b1cf83"},{"Application Name":"Microsoft Substrate Management","Application IDs":"98db8bd6-0cc0-4e67-9de5-f187f1cd1b41"},{"Application Name":"Microsoft Support","Application IDs":"fdf9885b-dd37-42bf-82e5-c3129ef5a302"},{"Application Name":"Microsoft Teams","Application IDs":"1fec8e78-bce4-4aaf-ab1b-5451cc387264"},{"Application Name":"Microsoft Teams Services","Application IDs":"cc15fd57-2c6c-4117-a88c-83b1d56b4bbe"},{"Application Name":"Microsoft Teams Web Client","Application IDs":"5e3ce6c0-2b1f-4285-8d4b-75ee78787346"},{"Application Name":"Microsoft Whiteboard Services","Application IDs":"95de633a-083e-42f5-b444-a4295d8e9314"},{"Application Name":"O365 Suite UX","Application IDs":"4345a7b9-9a63-4910-a426-35363201d503"},{"Application Name":"Office 365 Exchange Online","Application IDs":"00000002-0000-0ff1-ce00-000000000000"},{"Application Name":"Office 365 Management","Application IDs":"00b41c95-dab0-4487-9791-b9d2c32c80f2"},{"Application Name":"Office 365 Search Service","Application IDs":"66a88757-258c-4c72-893c-3e8bed4d6899"},{"Application Name":"Office 365 SharePoint Online","Application IDs":"00000003-0000-0ff1-ce00-000000000000"},{"Application Name":"Office Delve","Application IDs":"94c63fef-13a3-47bc-8074-75af8c65887a"},{"Application Name":"Office Online Add-in SSO","Application IDs":"93d53678-613d-4013-afc1-62e9e444a0a5"},{"Application Name":"Office Online Client AAD- Augmentation Loop","Application IDs":"2abdc806-e091-4495-9b10-b04d93c3f040"},{"Application Name":"Office Online Client AAD- Loki","Application IDs":"b23dd4db-9142-4734-867f-3577f640ad0c"},{"Application Name":"Office Online Client AAD- Maker","Application IDs":"17d5e35f-655b-4fb0-8ae6-86356e9a49f5"},{"Application Name":"Office Online Client MSA- Loki","Application IDs":"b6e69c34-5f1f-4c34-8cdf-7fea120b8670"},{"Application Name":"Office Online Core SSO","Application IDs":"243c63a3-247d-41c5-9d83-7788c43f1c43"},{"Application Name":"Office Online Search","Application IDs":"a9b49b65-0a12-430b-9540-c80b3332c127"},{"Application Name":"Office.com","Application IDs":"4b233688-031c-404b-9a80-a4f3f2351f90"},{"Application Name":"Office365 Shell WCSS-Client","Application IDs":"89bee1f7-5e6e-4d8a-9f3d-ecd601259da7"},{"Application Name":"OfficeClientService","Application IDs":"0f698dd4-f011-4d23-a33e-b36416dcb1e6"},{"Application Name":"OfficeHome","Application IDs":"4765445b-32c6-49b0-83e6-1d93765276ca"},{"Application Name":"OfficeShredderWacClient","Application IDs":"4d5c2d63-cf83-4365-853c-925fd1a64357"},{"Application Name":"OMSOctopiPROD","Application IDs":"62256cef-54c0-4cb4-bcac-4c67989bdc40"},{"Application Name":"OneDrive SyncEngine","Application IDs":"ab9b8c07-8f02-4f72-87fa-80105867a763"},{"Application Name":"OneNote","Application IDs":"2d4d3d8e-2be3-4bef-9f87-7875a61c29de"},{"Application Name":"Outlook Mobile","Application IDs":"27922004-5251-4030-b22d-91ecd9a37ea4"},{"Application Name":"Partner Customer Delegated Admin Offline Processor","Application IDs":"a3475900-ccec-4a69-98f5-a65cd5dc5306"},{"Application Name":"Password Breach Authenticator","Application IDs":"bdd48c81-3a58-4ea9-849c-ebea7f6b6360"},{"Application Name":"Power BI Service","Application IDs":"00000009-0000-0000-c000-000000000000"},{"Application Name":"SharedWithMe","Application IDs":"ffcb16e8-f789-467c-8ce9-f826a080d987"},{"Application Name":"SharePoint Online Web Client Extensibility","Application IDs":"08e18876-6177-487e-b8b5-cf950c1e598c"},{"Application Name":"Signup","Application IDs":"b4bddae8-ab25-483e-8670-df09b9f1d0ea"},{"Application Name":"Skype for Business Online","Application IDs":"00000004-0000-0ff1-ce00-000000000000"},{"Application Name":"Sway","Application IDs":"905fcf26-4eb7-48a0-9ff0-8dcc7194b5ba"},{"Application Name":"Universal Store Native Client","Application IDs":"268761a2-03f3-40df-8a8b-c3db24145b6b"},{"Application Name":"Vortex [wsfed enabled]","Application IDs":"5572c4c0-d078-44ce-b81c-6cbf8d3ed39e"},{"Application Name":"Windows Azure Active Directory","Application IDs":"00000002-0000-0000-c000-000000000000"},{"Application Name":"Windows Azure Service Management API","Application IDs":"797f4846-ba00-4fd7-ba43-dac1f8f63013"},{"Application Name":"WindowsDefenderATP Portal","Application IDs":"a3b79187-70b2-4139-83f9-6016c58cd27b"},{"Application Name":"Windows Search","Application IDs":"26a7ee05-5602-4d76-a7ba-eae8b7b67941"},{"Application Name":"Windows Spotlight","Application IDs":"1b3c667f-cde3-4090-b60b-3d2abd0117f0"},{"Application Name":"Windows Store for Business","Application IDs":"45a330b1-b1ec-4cc1-9161-9f03992aa49f"},{"Application Name":"Yammer","Application IDs":"00000005-0000-0ff1-ce00-000000000000"},{"Application Name":"Yammer Web","Application IDs":"c1c74fed-04c9-4704-80dc-9f79a2e515cb"},{"Application Name":"Yammer Web Embed","Application IDs":"e1ef36fd-b883-4dbf-97f0-9ece4b576fc6"}]' | ConvertFrom-Json | Where-Object -Property 'Application IDs' -EQ $AuditlogsLogon.applicationId + $AuditlogsLogon = (New-ExoRequest -tenantid $TenantFilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam | Sort-Object -Property CreationDate | Select-Object -Last 1).auditdata | ConvertFrom-Json + $AppName = '[{"Application Name":"ACOM Azure Website","Application IDs":"23523755-3a2b-41ca-9315-f81f3f566a95"},{"Application Name":"AEM-DualAuth","Application IDs":"69893ee3-dd10-4b1c-832d-4870354be3d8"},{"Application Name":"ASM Campaign Servicing","Application IDs":"0cb7b9ec-5336-483b-bc31-b15b5788de71"},{"Application Name":"Azure Advanced Threat Protection","Application IDs":"7b7531ad-5926-4f2d-8a1d-38495ad33e17"},{"Application Name":"Azure Data Lake","Application IDs":"e9f49c6b-5ce5-44c8-925d-015017e9f7ad"},{"Application Name":"Azure Lab Services Portal","Application IDs":"835b2a73-6e10-4aa5-a979-21dfda45231c"},{"Application Name":"Azure Portal","Application IDs":"c44b4083-3bb0-49c1-b47d-974e53cbdf3c"},{"Application Name":"AzureSupportCenter","Application IDs":"37182072-3c9c-4f6a-a4b3-b3f91cacffce"},{"Application Name":"Bing","Application IDs":"9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7"},{"Application Name":"CPIM Service","Application IDs":"bb2a2e3a-c5e7-4f0a-88e0-8e01fd3fc1f4"},{"Application Name":"CRM Power BI Integration","Application IDs":"e64aa8bc-8eb4-40e2-898b-cf261a25954f"},{"Application Name":"Dataverse","Application IDs":"00000007-0000-0000-c000-000000000000"},{"Application Name":"Enterprise Roaming and Backup","Application IDs":"60c8bde5-3167-4f92-8fdb-059f6176dc0f"},{"Application Name":"IAM Supportability","Application IDs":"a57aca87-cbc0-4f3c-8b9e-dc095fdc8978"},{"Application Name":"IrisSelectionFrontDoor","Application IDs":"16aeb910-ce68-41d1-9ac3-9e1673ac9575"},{"Application Name":"MCAPI Authorization Prod","Application IDs":"d73f4b35-55c9-48c7-8b10-651f6f2acb2e"},{"Application Name":"Media Analysis and Transformation Service","Application IDs":"944f0bd1-117b-4b1c-af26-804ed95e767e
0cd196ee-71bf-4fd6-a57c-b491ffd4fb1e"},{"Application Name":"Microsoft 365 Support Service","Application IDs":"ee272b19-4411-433f-8f28-5c13cb6fd407"},{"Application Name":"Microsoft App Access Panel","Application IDs":"0000000c-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Approval Management","Application IDs":"65d91a3d-ab74-42e6-8a2f-0add61688c74
38049638-cc2c-4cde-abe4-4479d721ed44"},{"Application Name":"Microsoft Authentication Broker","Application IDs":"29d9ed98-a469-4536-ade2-f981bc1d605e"},{"Application Name":"Microsoft Azure CLI","Application IDs":"04b07795-8ddb-461a-bbee-02f9e1bf7b46"},{"Application Name":"Microsoft Azure PowerShell","Application IDs":"1950a258-227b-4e31-a9cf-717495945fc2"},{"Application Name":"Microsoft Bing Search","Application IDs":"cf36b471-5b44-428c-9ce7-313bf84528de"},{"Application Name":"Microsoft Bing Search for Microsoft Edge","Application IDs":"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8"},{"Application Name":"Microsoft Bing Default Search Engine","Application IDs":"1786c5ed-9644-47b2-8aa0-7201292175b6"},{"Application Name":"Microsoft Defender for Cloud Apps","Application IDs":"3090ab82-f1c1-4cdf-af2c-5d7a6f3e2cc7"},{"Application Name":"Microsoft Docs","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Dynamics ERP","Application IDs":"00000015-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Edge Insider Addons Prod","Application IDs":"6253bca8-faf2-4587-8f2f-b056d80998a7"},{"Application Name":"Microsoft Exchange Online Protection","Application IDs":"00000007-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Forms","Application IDs":"c9a559d2-7aab-4f13-a6ed-e7e9c52aec87"},{"Application Name":"Microsoft Graph","Application IDs":"00000003-0000-0000-c000-000000000000"},{"Application Name":"Microsoft Intune Web Company Portal","Application IDs":"74bcdadc-2fdc-4bb3-8459-76d06952a0e9"},{"Application Name":"Microsoft Intune Windows Agent","Application IDs":"fc0f3af4-6835-4174-b806-f7db311fd2f3"},{"Application Name":"Microsoft Learn","Application IDs":"18fbca16-2224-45f6-85b0-f7bf2b39b3f3"},{"Application Name":"Microsoft Office","Application IDs":"d3590ed6-52b3-4102-aeff-aad2292ab01c"},{"Application Name":"Microsoft Office 365 Portal","Application IDs":"00000006-0000-0ff1-ce00-000000000000"},{"Application Name":"Microsoft Office Web Apps Service","Application IDs":"67e3df25-268a-4324-a550-0de1c7f97287"},{"Application Name":"Microsoft Online Syndication Partner Portal","Application IDs":"d176f6e7-38e5-40c9-8a78-3998aab820e7"},{"Application Name":"Microsoft password reset service","Application IDs":"93625bc8-bfe2-437a-97e0-3d0060024faa"},{"Application Name":"Microsoft Power BI","Application IDs":"871c010f-5e61-4fb1-83ac-98610a7e9110"},{"Application Name":"Microsoft Storefronts","Application IDs":"28b567f6-162c-4f54-99a0-6887f387bbcc"},{"Application Name":"Microsoft Stream Portal","Application IDs":"cf53fce8-def6-4aeb-8d30-b158e7b1cf83"},{"Application Name":"Microsoft Substrate Management","Application IDs":"98db8bd6-0cc0-4e67-9de5-f187f1cd1b41"},{"Application Name":"Microsoft Support","Application IDs":"fdf9885b-dd37-42bf-82e5-c3129ef5a302"},{"Application Name":"Microsoft Teams","Application IDs":"1fec8e78-bce4-4aaf-ab1b-5451cc387264"},{"Application Name":"Microsoft Teams Services","Application IDs":"cc15fd57-2c6c-4117-a88c-83b1d56b4bbe"},{"Application Name":"Microsoft Teams Web Client","Application IDs":"5e3ce6c0-2b1f-4285-8d4b-75ee78787346"},{"Application Name":"Microsoft Whiteboard Services","Application IDs":"95de633a-083e-42f5-b444-a4295d8e9314"},{"Application Name":"O365 Suite UX","Application IDs":"4345a7b9-9a63-4910-a426-35363201d503"},{"Application Name":"Office 365 Exchange Online","Application IDs":"00000002-0000-0ff1-ce00-000000000000"},{"Application Name":"Office 365 Management","Application IDs":"00b41c95-dab0-4487-9791-b9d2c32c80f2"},{"Application Name":"Office 365 Search Service","Application IDs":"66a88757-258c-4c72-893c-3e8bed4d6899"},{"Application Name":"Office 365 SharePoint Online","Application IDs":"00000003-0000-0ff1-ce00-000000000000"},{"Application Name":"Office Delve","Application IDs":"94c63fef-13a3-47bc-8074-75af8c65887a"},{"Application Name":"Office Online Add-in SSO","Application IDs":"93d53678-613d-4013-afc1-62e9e444a0a5"},{"Application Name":"Office Online Client AAD- Augmentation Loop","Application IDs":"2abdc806-e091-4495-9b10-b04d93c3f040"},{"Application Name":"Office Online Client AAD- Loki","Application IDs":"b23dd4db-9142-4734-867f-3577f640ad0c"},{"Application Name":"Office Online Client AAD- Maker","Application IDs":"17d5e35f-655b-4fb0-8ae6-86356e9a49f5"},{"Application Name":"Office Online Client MSA- Loki","Application IDs":"b6e69c34-5f1f-4c34-8cdf-7fea120b8670"},{"Application Name":"Office Online Core SSO","Application IDs":"243c63a3-247d-41c5-9d83-7788c43f1c43"},{"Application Name":"Office Online Search","Application IDs":"a9b49b65-0a12-430b-9540-c80b3332c127"},{"Application Name":"Office.com","Application IDs":"4b233688-031c-404b-9a80-a4f3f2351f90"},{"Application Name":"Office365 Shell WCSS-Client","Application IDs":"89bee1f7-5e6e-4d8a-9f3d-ecd601259da7"},{"Application Name":"OfficeClientService","Application IDs":"0f698dd4-f011-4d23-a33e-b36416dcb1e6"},{"Application Name":"OfficeHome","Application IDs":"4765445b-32c6-49b0-83e6-1d93765276ca"},{"Application Name":"OfficeShredderWacClient","Application IDs":"4d5c2d63-cf83-4365-853c-925fd1a64357"},{"Application Name":"OMSOctopiPROD","Application IDs":"62256cef-54c0-4cb4-bcac-4c67989bdc40"},{"Application Name":"OneDrive SyncEngine","Application IDs":"ab9b8c07-8f02-4f72-87fa-80105867a763"},{"Application Name":"OneNote","Application IDs":"2d4d3d8e-2be3-4bef-9f87-7875a61c29de"},{"Application Name":"Outlook Mobile","Application IDs":"27922004-5251-4030-b22d-91ecd9a37ea4"},{"Application Name":"Partner Customer Delegated Admin Offline Processor","Application IDs":"a3475900-ccec-4a69-98f5-a65cd5dc5306"},{"Application Name":"Password Breach Authenticator","Application IDs":"bdd48c81-3a58-4ea9-849c-ebea7f6b6360"},{"Application Name":"Power BI Service","Application IDs":"00000009-0000-0000-c000-000000000000"},{"Application Name":"SharedWithMe","Application IDs":"ffcb16e8-f789-467c-8ce9-f826a080d987"},{"Application Name":"SharePoint Online Web Client Extensibility","Application IDs":"08e18876-6177-487e-b8b5-cf950c1e598c"},{"Application Name":"Signup","Application IDs":"b4bddae8-ab25-483e-8670-df09b9f1d0ea"},{"Application Name":"Skype for Business Online","Application IDs":"00000004-0000-0ff1-ce00-000000000000"},{"Application Name":"Sway","Application IDs":"905fcf26-4eb7-48a0-9ff0-8dcc7194b5ba"},{"Application Name":"Universal Store Native Client","Application IDs":"268761a2-03f3-40df-8a8b-c3db24145b6b"},{"Application Name":"Vortex [wsfed enabled]","Application IDs":"5572c4c0-d078-44ce-b81c-6cbf8d3ed39e"},{"Application Name":"Windows Azure Active Directory","Application IDs":"00000002-0000-0000-c000-000000000000"},{"Application Name":"Windows Azure Service Management API","Application IDs":"797f4846-ba00-4fd7-ba43-dac1f8f63013"},{"Application Name":"WindowsDefenderATP Portal","Application IDs":"a3b79187-70b2-4139-83f9-6016c58cd27b"},{"Application Name":"Windows Search","Application IDs":"26a7ee05-5602-4d76-a7ba-eae8b7b67941"},{"Application Name":"Windows Spotlight","Application IDs":"1b3c667f-cde3-4090-b60b-3d2abd0117f0"},{"Application Name":"Windows Store for Business","Application IDs":"45a330b1-b1ec-4cc1-9161-9f03992aa49f"},{"Application Name":"Yammer","Application IDs":"00000005-0000-0ff1-ce00-000000000000"},{"Application Name":"Yammer Web","Application IDs":"c1c74fed-04c9-4704-80dc-9f79a2e515cb"},{"Application Name":"Yammer Web Embed","Application IDs":"e1ef36fd-b883-4dbf-97f0-9ece4b576fc6"}]' | + ConvertFrom-Json | Where-Object -Property 'Application IDs' -EQ $AuditlogsLogon.applicationId $LastSignIn = [PSCustomObject]@{ AppDisplayName = if ($AppName) { $AppName.'Application Name' } else { "$($AuditlogsLogon.Workload) - $($AuditlogsLogon.ApplicationId) " } CreatedDateTime = $AuditlogsLogon.CreationTime @@ -75,7 +75,7 @@ Function Invoke-ListUsers { @{ Name = 'LastSigninDate'; Expression = { $($LastSignIn.CreatedDateTime | Out-String) } }, @{ Name = 'LastSigninStatus'; Expression = { $AuditlogsLogon.operation } }, @{ Name = 'LastSigninResult'; Expression = { $LastSignIn.status } }, - @{ Name = 'LastSigninFailureReason'; Expression = { if ($LastSignIn.Id -eq 0) { 'Sucessfully signed in' } else { $LastSignIn.Id } } } + @{ Name = 'LastSigninFailureReason'; Expression = { if ($LastSignIn.Id -eq 0) { 'Successfully signed in' } else { $LastSignIn.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/Identity/Administration/Users/Invoke-RemoveUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUser.ps1 new file mode 100644 index 000000000000..dc21f41c14ac --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUser.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-RemoveUser { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.User.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $UserID = $Request.Query.ID ?? $Request.Body.ID + + if (!$UserID) { exit } + try { + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserID)" -type DELETE -tenant $TenantFilter + $Result = "Successfully deleted $UserID." + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' -tenant $TenantFilter + $StatusCode = [HttpStatusCode]::OK + + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Could not delete user $($UserID). $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ 'Results' = $Result } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListAzureADConnectStatus.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListAzureADConnectStatus.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListAzureADConnectStatus.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListInactiveAccounts.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListInactiveAccounts.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListInactiveAccounts.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListMFAUsers.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListMFAUsers.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListMFAUsers.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListSignIns.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListSignIns.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Reports/Invoke-ListSignIns.ps1 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 8f6e939440fb..e2c91f14a12e 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 @@ -16,32 +16,40 @@ Function Invoke-ExecSharePointPerms { Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev Debug + Write-Host '====================================' + Write-Host 'Request Body:' + Write-Host (ConvertTo-Json $Request.body -Depth 10) + Write-Host '====================================' + + # The UPN or ID of the users OneDrive we are changing permissions on - $UserId = $Request.body.UPN + $UserId = $Request.Body.UPN # The UPN of the user we are adding or removing permissions for - $OnedriveAccessUser = $Request.body.onedriveAccessUser.value + $OnedriveAccessUser = $Request.Body.onedriveAccessUser.value ?? $Request.Body.user.value + $URL = $Request.Body.URL + $RemovePermission = $Request.Body.RemovePermission try { $State = Set-CIPPSharePointPerms -tenantFilter $tenantFilter ` -UserId $UserId ` -OnedriveAccessUser $OnedriveAccessUser ` - -Headers $Request.Headers ` + -Headers $Headers ` -APIName $APIName ` - -RemovePermission $Request.body.RemovePermission ` - -URL $Request.Body.URL - $Results = [pscustomobject]@{'Results' = "$State" } + -RemovePermission $RemovePermission ` + -URL $URL + $Result = "$State" $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - $Results = [pscustomobject]@{'Results' = "Failed. $($ErrorMessage.NormalizedError)" } + $Result = "Failed. $($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' = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSharepointQuota.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListSharepointQuota.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSharepointQuota.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsLisLocation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsLisLocation.ps1 index d8b0f95656dd..a801c93077b0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsLisLocation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListTeamsLisLocation.ps1 @@ -11,7 +11,9 @@ Function Invoke-ListTeamsLisLocation { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.TenantFilter try { 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 460a36ad70a5..8d4436ef3412 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 @@ -11,11 +11,10 @@ Function Invoke-ListAlertsQueue { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' $WebhookTable = Get-CIPPTable -TableName 'WebhookRules' $WebhookRules = Get-CIPPAzDataTableEntity @WebhookTable diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogSearches.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogSearches.ps1 index 561384504174..4468443aece3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogSearches.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-ListAuditLogSearches.ps1 @@ -7,36 +7,48 @@ function Invoke-ListAuditLogSearches { #> Param($Request, $TriggerMetadata) - if ($Request.Query.TenantFilter) { - switch ($Request.Query.Type) { + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with the query parameters + $TenantFilter = $Request.Query.tenantFilter + $SearchId = $Request.Query.SearchId + $Days = $Request.Query.Days + $Type = $Request.Query.Type + + + if ($TenantFilter) { + switch ($Type) { 'Searches' { - $Results = Get-CippAuditLogSearches -TenantFilter $Request.Query.TenantFilter + $Results = Get-CippAuditLogSearches -TenantFilter $TenantFilter $Body = @{ Results = @($Results) Metadata = @{ - TenantFilter = $Request.Query.TenantFilter + TenantFilter = $TenantFilter TotalSearches = $Results.Count } } | ConvertTo-Json -Depth 10 -Compress } 'SearchResults' { try { - $Results = Get-CippAuditLogSearchResults -TenantFilter $Request.Query.TenantFilter -QueryId $Request.Query.SearchId + $Results = Get-CippAuditLogSearchResults -TenantFilter $TenantFilter -QueryId $SearchId } catch { $Results = @{ Error = $_.Exception.Message } } $Body = @{ Results = @($Results) Metadata = @{ - SearchId = $Request.Query.SearchId - TenantFilter = $Request.Query.TenantFilter + SearchId = $SearchId + TenantFilter = $TenantFilter TotalResults = $Results.Count } } | ConvertTo-Json -Depth 10 -Compress } default { - if ($Request.Query.Days) { - $Days = $Request.Query.Days + if ($Days) { + $Days = $Days } else { $Days = 1 } @@ -62,7 +74,7 @@ function Invoke-ListAuditLogSearches { Results = @($Results) Metadata = @{ StartTime = $StartTime - TenantFilter = $Request.Query.TenantFilter + TenantFilter = $TenantFilter } } | ConvertTo-Json -Depth 10 -Compress } 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 9915eef063b7..a41726c72e57 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 @@ -8,26 +8,31 @@ function Invoke-ListAuditLogs { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = 'ListAuditLogs' - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $TenantFilter = $Request.Query.TenantFilter + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter + $LogID = $Request.Query.LogId + $StartDate = $Request.Query.StartDate + $EndDate = $Request.Query.EndDate + $RelativeTime = $Request.Query.RelativeTime $FilterConditions = [System.Collections.Generic.List[string]]::new() - if ($Request.Query.LogId) { - $FilterConditions.Add("RowKey eq '$($Request.Query.LogId)'") + if ($LogID) { + $FilterConditions.Add("RowKey eq '$($LogID)'") } else { if ($TenantFilter -and $TenantFilter -ne 'AllTenants') { $FilterConditions.Add("Tenant eq '$TenantFilter'") } - if (!$Request.Query.StartDate -and !$Request.Query.EndDate -and !$Request.Query.RelativeTime) { - $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') + if (!$StartDate -and !$EndDate -and !$RelativeTime) { + $StartDate = (Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $EndDate = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } - if ($Request.Query.RelativeTime) { - $RelativeTime = $Request.Query.RelativeTime + if ($RelativeTime) { if ($RelativeTime -match '(\d+)([dhm])') { $EndDate = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') @@ -40,19 +45,19 @@ function Invoke-ListAuditLogs { } $FilterConditions.Add("Timestamp ge datetime'$StartDate' and Timestamp le datetime'$EndDate'") } else { - if ($Request.Query.StartDate) { - if ($Request.Query.StartDate -match '^\d+$') { - $StartDate = [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.Query.StartDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + if ($StartDate) { + if ($StartDate -match '^\d+$') { + $StartDate = [DateTimeOffset]::FromUnixTimeSeconds([int]$StartDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } else { - $StartDate = (Get-Date $Request.Query.StartDate).ToString('yyyy-MM-ddTHH:mm:ssZ') + $StartDate = (Get-Date $StartDate).ToString('yyyy-MM-ddTHH:mm:ssZ') } $FilterConditions.Add("Timestamp ge datetime'$StartDate'") - if ($Request.Query.EndDate) { - if ($Request.Query.EndDate -match '^\d+$') { - $EndDate = [DateTimeOffset]::FromUnixTimeSeconds([int]$Request.Query.EndDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + if ($EndDate) { + if ($EndDate -match '^\d+$') { + $EndDate = [DateTimeOffset]::FromUnixTimeSeconds([int]$EndDate).DateTime.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } else { - $EndDate = (Get-Date $Request.Query.EndDate).ToString('yyyy-MM-ddTHH:mm:ssZ') + $EndDate = (Get-Date $EndDate).ToString('yyyy-MM-ddTHH:mm:ssZ') } $FilterConditions.Add("Timestamp le datetime'$EndDate'") } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 index 2442dbcf934a..1ee3c7dcb788 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-RemoveQueuedAlert.ps1 @@ -11,32 +11,38 @@ Function Invoke-RemoveQueuedAlert { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - if ($Request.query.EventType -eq 'Audit log Alert') { + # Interact with the query or body of the request + $EventType = $Request.Query.EventType ?? $Request.Body.EventType + $ID = $Request.Query.ID ?? $Request.Body.ID + + if ($EventType -eq 'Audit log Alert') { $Table = 'WebhookRules' } else { $Table = 'ScheduledTasks' } $Table = Get-CIPPTable -TableName $Table - $ID = $request.query.id try { $Filter = "RowKey eq '{0}'" -f $ID $Alert = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey Remove-AzDataTableEntity -Force @Table -Entity $Alert - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' - - $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } + $Result = "Successfully removed alert $ID from queue" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Failed to remove from queue $ID. $($_.Exception.Message)" -Sev 'Error' - $body = [pscustomobject]@{'Results' = "Failed to remove alert from queue $($_.Exception.Message)" } + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove alert from queue $ID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{ 'Results' = $Result } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListDomains.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListDomains.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-ListDomains.ps1 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 8fee5dbf56f8..843248a2d2ff 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 @@ -5,10 +5,14 @@ function Invoke-ListTenantOnboarding { .ROLE Tenant.Administration.Read #> - Param( - $Request, - $TriggerMetadata - ) + Param($Request, $TriggerMetadata) + + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + try { $OnboardTable = Get-CIPPTable -TableName 'TenantOnboarding' $TenantOnboardings = Get-CIPPAzDataTableEntity @OnboardTable diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-SetAuthMethod.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-SetAuthMethod.ps1 index 26653bf43648..9e089ff3f77c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-SetAuthMethod.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Invoke-SetAuthMethod.ps1 @@ -8,11 +8,17 @@ function Invoke-SetAuthMethod { Param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. $State = if ($Request.Body.state -eq 'enabled') { $true } else { $false } $TenantFilter = $Request.Body.tenantFilter + $AuthenticationMethodId = $Request.Body.Id + try { - $Result = Set-CIPPAuthenticationPolicy -Tenant $TenantFilter -APIName $APIName -AuthenticationMethodId $($Request.Body.Id) -Enabled $State -Headers $Request.Headers + $Result = Set-CIPPAuthenticationPolicy -Tenant $TenantFilter -APIName $APIName -AuthenticationMethodId $AuthenticationMethodId -Enabled $State -Headers $Headers $StatusCode = [HttpStatusCode]::OK } catch { $Result = $_ 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 1fd2fd8f97a8..73ada77a4e13 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 @@ -23,8 +23,8 @@ Function Invoke-ListTenants { } # Clear Cache - if ($Request.Query.ClearCache -eq $true) { - Remove-CIPPCache -tenantsOnly $Request.Query.TenantsOnly + if ($Request.Body.ClearCache -eq $true) { + $Results = Remove-CIPPCache -tenantsOnly $Request.Body.TenantsOnly $InputObject = [PSCustomObject]@{ Batch = @( @@ -40,7 +40,12 @@ Function Invoke-ListTenants { $GraphRequest = [pscustomobject]@{'Results' = 'Cache has been cleared and a tenant refresh is queued.' } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = $GraphRequest + Body = @{ + Results = @($GraphRequest) + Metadata = @{ + Details = $Results + } + } }) #Get-Tenants -IncludeAll -TriggerRefresh return @@ -88,6 +93,19 @@ Function Invoke-ListTenants { } else { $Body = $Tenants } + if ($Request.Query.Mode -eq 'TenantList') { + # add portal link properties + $Body = $Body | Select-Object *, @{Name = 'portal_m365'; Expression = { "https://admin.microsoft.com/Partner/BeginClientSession.aspx?CTID=$($_.customerId)&CSDEST=o365admincenter" } }, + @{Name = 'portal_exchange'; Expression = { "https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=$($_.defaultDomainName)" } }, + @{Name = 'portal_entra'; Expression = { "https://entra.microsoft.com/$($_.defaultDomainName)" } }, + @{Name = 'portal_teams'; Expression = { "https://admin.teams.microsoft.com/?delegatedOrg=$($_.defaultDomainName)" } }, + @{Name = 'portal_azure'; Expression = { "https://portal.azure.com/$($_.defaultDomainName)" } }, + @{Name = 'portal_intune'; Expression = { "https://intune.microsoft.com/$($_.defaultDomainName)" } }, + @{Name = 'portal_security'; Expression = { "https://security.microsoft.com/?tid=$($_.customerId)" } }, + @{Name = 'portal_compliance'; Expression = { "https://purview.microsoft.com/?tid=$($_.customerId)" } }, + @{Name = 'portal_sharepoint'; Expression = { "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=$($_.customerId)&CSDEST=SharePoint" } } + } + } else { $body = $Tenants | Where-Object -Property defaultDomainName -EQ $Tenantfilter } 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 1e8d5662663a..e8d3d5692a54 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 @@ -11,26 +11,31 @@ Function Invoke-EditCAPolicy { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $Tenant = $request.query.tenantFilter - $ID = $request.query.guid - $results = try { - $EditBody = "{`"state`": `"$($request.query.state)`"}" - $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta//identity/conditionalAccess/policies/$($id)" -tenantid $tenant -type PATCH -body $EditBody -asapp $true - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Edited CA policy: $($ID)" -Sev 'Info' - "Successfully edited CA policy: $($ID)" + # Interact with the request + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $ID = $Request.Query.GUID ?? $Request.Body.GUID + $State = $Request.Query.State ?? $Request.Body.State + + try { + $EditBody = "{`"state`": `"$($State)`"}" + $Request = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta//identity/conditionalAccess/policies/$($ID)" -tenantid $TenantFilter -type PATCH -body $EditBody -asapp $true + $Result = "Successfully set CA policy $($ID) to $($State)" + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { - "Failed to add CA policy: $($_.Exception.Message)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $($Tenant) -message "Failed editing CA policy $($ID). Error: $($_.Exception.Message)" -Sev 'Error' + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to set CA policy $($ID) to $($State): $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } - $body = [pscustomobject]@{'Results' = $results } - # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{ 'Results' = $Result } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicies.ps1 index 25b28cc46a09..c96c3b99f044 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 @@ -11,7 +11,7 @@ Function Invoke-ListConditionalAccessPolicies { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' function Get-LocationNameFromId { @@ -114,11 +114,8 @@ Function Invoke-ListConditionalAccessPolicies { return $return } - # 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 + $TenantFilter = $Request.Query.tenantFilter try { $Requests = @( @{ @@ -158,7 +155,7 @@ Function Invoke-ListConditionalAccessPolicies { } ) - $GraphRequest = New-GraphBulkRequest -Requests $Requests -tenantid $tenantfilter -asapp $true + $GraphRequest = New-GraphBulkRequest -Requests $Requests -tenantid $TenantFilter -asapp $true $ConditionalAccessPolicyOutput = ($GraphRequest | Where-Object { $_.id -eq 'policies' }).body.value $AllNamedLocations = ($GraphRequest | Where-Object { $_.id -eq 'namedLocations' }).body.value diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 index b21fbe522b11..b144805a6670 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ListConditionalAccessPolicyChanges.ps1 @@ -11,39 +11,36 @@ Function Invoke-ListConditionalAccessPolicyChanges { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $policyId = $Request.body.id - $policyDisplayName = $Request.body.displayName + $TenantFilter = $Request.Query.tenantFilter + $PolicyId = $Request.Query.id + $PolicyDisplayName = $Request.Query.displayName try { - [array]$changes = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?`$filter=targetResources/any(s:s/id eq '$($policyId)')" -tenantid $TenantFilter | ForEach-Object { + [array]$Changes = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?`$filter=targetResources/any(s:s/id eq '$($PolicyId)')" -tenantid $TenantFilter | ForEach-Object { [pscustomobject]@{ - policy = $policyDisplayName - policyId = $policyId + policy = $PolicyDisplayName + policyId = $PolicyId typeFriendlyName = $_.activityDisplayName - type = $_.operationType - initiatedBy = if ($_.initiatedBy.user.userPrincipalName) { $_.initiatedBy.user.userPrincipalName } else { $_.initiatedBy.app.displayName } - date = $_.activityDateTime - oldValue = ($_.targetResources[0].modifiedProperties.oldValue | ConvertFrom-Json) # targetResources is an array, can we ever get more than 1 object in it? - newValue = ($_.targetResources[0].modifiedProperties.newValue | ConvertFrom-Json) + type = $_.operationType + initiatedBy = if ($_.initiatedBy.user.userPrincipalName) { $_.initiatedBy.user.userPrincipalName } else { $_.initiatedBy.app.displayName } + date = $_.activityDateTime + oldValue = ($_.targetResources[0].modifiedProperties.oldValue | ConvertFrom-Json) # targetResources is an array, can we ever get more than 1 object in it? + newValue = ($_.targetResources[0].modifiedProperties.newValue | ConvertFrom-Json) } } $StatusCode = [HttpStatusCode]::OK } catch { $StatusCode = [HttpStatusCode]::BadRequest - Write-Host $($_.Exception.message) - Write-LogMessage -headers $Request.Headers -API $APIName -message "Failed to request audit logs for policy $($policyDisplayName): $($_.Exception.message)" -Sev "Error" -tenant $TenantFilter + $Changes = "Failed to request audit logs for policy $($PolicyDisplayName): $($_.Exception.message)" } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = $changes - }) + StatusCode = $StatusCode + Body = @($Changes) + }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-RemoveCAPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-RemoveCAPolicy.ps1 new file mode 100644 index 000000000000..7c894788f257 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-RemoveCAPolicy.ps1 @@ -0,0 +1,40 @@ +using namespace System.Net + +Function Invoke-RemoveCAPolicy { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $policyId = $Request.Query.GUID ?? $Request.Body.GUID + if (!$policyId) { exit } + try { + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($policyId)" -type DELETE -tenant $TenantFilter -asapp $true + $Result = "Deleted CA Policy $($policyId)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' -tenant $TenantFilter + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Could not delete CA policy with ID $($policyId) : $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden + } + + $body = [pscustomobject]@{'Results' = $Result } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $body + }) + + +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-RemoveCATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-RemoveCATemplate.ps1 new file mode 100644 index 000000000000..e800d423fc90 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-RemoveCATemplate.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-RemoveCATemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $ID = $request.Query.ID ?? $Request.Body.ID + Write-LogMessage -Headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + try { + $Table = Get-CippTable -tablename 'templates' + + $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$ID'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity -Force @Table -Entity $ClearRow + $Result = "Removed Conditional Access Template with ID $ID" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove Conditional Access template $($ID): $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{'Results' = $Result } + }) + + +} 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 04e76f5997d0..cdfc60021116 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 @@ -82,7 +82,14 @@ Function Invoke-ExecGDAPInvite { } catch { $Message = 'Error creating GDAP relationship, failed at step: ' + $Step Write-Host "GDAP ERROR: $($_.InvocationInfo.PositionMessage)" - Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $env:TenantID -message "$($Message): $($_.Exception.Message)" -Sev 'Error' -LogData (Get-CippException -Exception $_) + + if ($Step -eq 'Creating GDAP relationship' -and $_.Exception.Message -match 'The user (principal) does not have the required permissions to perform the specified action on the resource.') { + $Message = 'Error creating GDAP relationship, ensure that all users have MFA enabled and enforced without exception. Please see the Microsoft Partner Security Requirements documentation for more information. https://learn.microsoft.com/en-us/partner-center/security/partner-security-requirements' + } else { + $Message = "$($Message): $($_.Exception.Message)" + } + + Write-LogMessage -headers $Request.Headers -API $APINAME -tenant $env:TenantID -message $Message -Sev 'Error' -LogData (Get-CippException -Exception $_) } $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 index 83fae86a70ea..953e87831000 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPAccessAssignments.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPAccessAssignments.ps1 @@ -6,6 +6,10 @@ function Invoke-ListGDAPAccessAssignments { [CmdletBinding()] param($Request, $TriggerMetadata) + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $Id = $Request.Query.Id $TenantFilter = $env:TenantID 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 62fbb532c26c..578a0cc2db93 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 @@ -14,12 +14,12 @@ Function Invoke-ListGDAPInvite { Write-LogMessage -headers $Request.Headers -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. + $RelationshipId = $Request.Query.RelationshipId $Table = Get-CIPPTable -TableName 'GDAPInvites' - if (![string]::IsNullOrEmpty($Request.Query.RelationshipId)) { - $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($Request.Query.RelationshipId)'" + if (![string]::IsNullOrEmpty($RelationshipId)) { + $Invite = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$($RelationshipId)'" } else { $Invite = Get-CIPPAzDataTableEntity @Table | ForEach-Object { $_.RoleMappings = @(try { $_.RoleMappings | ConvertFrom-Json } catch { $_.RoleMappings }) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 index f99e814e04a8..cc2d40b78077 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ListGDAPQueue.ps1 @@ -13,9 +13,8 @@ Function Invoke-ListGDAPQueue { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + # XXX Seems to be an unused endpoint? -Bobby - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' $Table = Get-CIPPTable -TableName 'GDAPMigration' $QueuedApps = Get-CIPPAzDataTableEntity @Table diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListLicenses.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListLicenses.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListLicenses.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListOAuthApps.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListOAuthApps.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListOAuthApps.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListServiceHealth.ps1 similarity index 80% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListServiceHealth.ps1 index a7213fbf18b9..160533a5d1f9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListServiceHealth.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Reports/Invoke-ListServiceHealth.ps1 @@ -10,12 +10,13 @@ Function Invoke-ListServiceHealth { [CmdletBinding()] param($Request, $TriggerMetadata) - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $TenantFilter = $Request.Query.tenantFilter + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' - if ($Request.query.tenantFilter -eq 'AllTenants') { + if ($TenantFilter -eq 'AllTenants') { $ResultHealthSummary = Get-Tenants | ForEach-Object -Parallel { Import-Module '.\Modules\AzBobbyTables' Import-Module '.\Modules\CIPPCore' @@ -27,10 +28,9 @@ Function Invoke-ListServiceHealth { $prop } } else { - $TenantName = $Request.query.displayName - $TenantID = $Request.query.tenantFilter - $DefaultDomainName = $Request.query.defaultDomainName - $ResultHealthSummary = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/admin/serviceAnnouncement/issues?`$filter=endDateTime eq null" -tenantid $TenantID + $TenantName = $Request.Query.displayName + $DefaultDomainName = $Request.Query.defaultDomainName + $ResultHealthSummary = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/admin/serviceAnnouncement/issues?`$filter=endDateTime eq null" -tenantid $TenantFilter $ResultHealthSummary | Add-Member -NotePropertyName 'tenant' -NotePropertyValue $TenantName $ResultHealthSummary | Add-Member -NotePropertyName 'defaultDomainName' -NotePropertyValue $DefaultDomainName Write-Host "Processed Service Health for $TenantName" diff --git a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1 similarity index 98% rename from Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1 index 2b2016230ad6..6828a6da71ca 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPStandardsRun.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-CIPPStandardsRun.ps1 @@ -34,6 +34,7 @@ function Invoke-CIPPStandardsRun { runManually = $runManually } } + SkipLog = $true } if ($TemplateID) { $InputObject.QueueFunction.StandardParams['TemplateId'] = $TemplateID diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListStandards.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Entrypoints/Invoke-ListStandards.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListStandards.ps1 diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveBPATemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveBPATemplate.ps1 new file mode 100644 index 000000000000..9282d94a4e30 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveBPATemplate.ps1 @@ -0,0 +1,42 @@ +using namespace System.Net + +Function Invoke-RemoveBPATemplate { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + + $ID = $request.Query.TemplateName ?? $request.Body.TemplateName + try { + $Table = Get-CippTable -tablename 'templates' + + $Filter = "PartitionKey eq 'BPATemplate' and RowKey eq '$ID'" + $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey + Remove-AzDataTableEntity -Force @Table -Entity $ClearRow + $Result = "Removed BPA Template with ID $ID" + Write-LogMessage -Headers $Headers -API $APINAME -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove BPA template with ID $ID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APINAME -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{'Results' = $Result } + }) + + +} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveStandard.ps1 similarity index 100% rename from Modules/CIPPCore/Public/Invoke-RemoveStandard.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveStandard.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveStandardTemplate.ps1 similarity index 55% rename from Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 rename to Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveStandardTemplate.ps1 index 42f436018037..697c4e53a46a 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveStandardTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-RemoveStandardTemplate.ps1 @@ -11,8 +11,8 @@ Function Invoke-RemoveStandardTemplate { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -Headers $Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' $ID = $Request.Body.ID ?? $Request.Query.ID try { @@ -20,19 +20,21 @@ Function Invoke-RemoveStandardTemplate { $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 -Headers $User -API $APINAME -message "Removed Standards Template named $($ClearRow.name) and id $($id)" -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Template' } + $Result = "Removed Standards Template named $($ClearRow.name) and id $($id)" + Write-LogMessage -Headers $Headers -API $APINAME -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove Standards template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Failed to remove template: $($ErrorMessage.NormalizedError)" } + $Result = "Failed to remove Standards template $ID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APINAME -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body + StatusCode = $StatusCode + Body = @{'Results' = $Result } }) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 index c701bd475f40..0ba09a9db3ee 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecCSPLicense.ps1 @@ -14,35 +14,36 @@ Function Invoke-ExecCSPLicense { Write-LogMessage -headers $Request.Headers -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 + $TenantFilter = $Request.Body.TenantFilter + $Action = $Request.Body.Action + $SKU = $Request.Body.SKU + try { if ($Action -eq 'Add') { - $GraphRequest = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $Request.body.sku -add $Request.body.Add + $null = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $SKU -add $Request.Body.Add } if ($Action -eq 'Remove') { - $GraphRequest = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $Request.body.sku -remove $Request.body.Remove + $null = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $SKU -remove $Request.Body.Remove } if ($Action -eq 'NewSub') { - $GraphRequest = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $Request.body.sku.value -Quantity $Request.body.Quantity + $null = Set-SherwebSubscription -tenantFilter $TenantFilter -SKU $SKU -Quantity $Request.Body.Quantity } if ($Action -eq 'Cancel') { - $GraphRequest = Remove-SherwebSubscription -tenantFilter $TenantFilter -SubscriptionIds $Request.body.SubscriptionIds + $null = Remove-SherwebSubscription -tenantFilter $TenantFilter -SubscriptionIds $Request.Body.SubscriptionIds } - $Message = 'License change executed successfully.' + $Result = 'License change executed successfully.' + $StatusCode = [HttpStatusCode]::OK } catch { - $Message = "Failed to execute license change. Error: $_" + $Result = "Failed to execute license change. Error: $_" + $StatusCode = [HttpStatusCode]::InternalServerError } - #If #GraphRequest is a GUID, the subscription was edited succesfully, and return that its done. + # If $GraphRequest is a GUID, the subscription was edited successfully, and return that it's done. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Message + StatusCode = $StatusCode + Body = $Result }) -Clobber } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 deleted file mode 100644 index 3547e651798d..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecRestoreDeleted.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -using namespace System.Net - -Function Invoke-ExecRestoreDeleted { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Tenant.Directory.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - - try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/directory/deletedItems/$($Request.query.ID)/restore" -tenantid $TenantFilter -type POST -body '{}' -verbose - $Results = [pscustomobject]@{'Results' = 'Successfully completed request.' } - } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.Exception.Message)" } - } - - # 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-ExecUserSettings.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 index 82d1cb25041a..ee1b63556b4d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecUserSettings.ps1 @@ -10,7 +10,8 @@ function Invoke-ExecUserSettings { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' try { $object = $request.body.currentSettings | Select-Object * -ExcludeProperty CurrentTenant, pageSizes, sidebarShow, sidebarUnfoldable, _persist | ConvertTo-Json -Compress -Depth 10 diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 index 10e0590e24c1..baac00b5b28a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListAppStatus.ps1 @@ -14,18 +14,15 @@ Function Invoke-ListAppStatus { Write-LogMessage -headers $Request.Headers -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 + $TenantFilter = $Request.Query.TenantFilter $appFilter = $Request.Query.AppFilter Write-Host "Using $appFilter" $body = @" {"select":["DeviceName","UserPrincipalName","Platform","AppVersion","InstallState","InstallStateDetail","LastModifiedDateTime","DeviceId","ErrorCode","UserName","UserId","ApplicationId","AssignmentFilterIdsList","AppInstallState","AppInstallStateDetails","HexErrorCode"],"skip":0,"top":999,"filter":"(ApplicationId eq '$Appfilter')","orderBy":[]} "@ try { - $GraphRequest = New-Graphpostrequest -uri 'https://graph.microsoft.com/beta/deviceManagement/reports/getDeviceInstallStatusReport' -tenantid $TenantFilter -body $body + $GraphRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/reports/getDeviceInstallStatusReport' -tenantid $TenantFilter -body $body $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 index 812a8c46b272..5e6104b3fdf3 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListBreachesTenant.ps1 @@ -10,7 +10,11 @@ Function Invoke-ListBreachesTenant { [CmdletBinding()] param($Request, $TriggerMetadata) - $TenantFilter = $Request.query.TenantFilter + $APIName = $Request.Params.CIPPEndpoint + Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + $TenantFilter = $Request.query.tenantFilter + $Table = Get-CIPPTable -TableName UserBreaches if ($TenantFilter -ne 'AllTenants') { $filter = "PartitionKey eq '$TenantFilter'" @@ -22,7 +26,7 @@ Function Invoke-ListBreachesTenant { } catch { $usersResults = $null } - if ($usersResults -eq $null) { + if ($null -eq $usersResults) { $usersResults = @() } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 index 4782121321b5..6753e0053477 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListCSPsku.ps1 @@ -12,11 +12,12 @@ Function Invoke-ListCSPsku { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.tenantFilter if ($Request.Query.currentSkuOnly) { - $GraphRequest = Get-SherwebCurrentSubscription -TenantFilter $Request.Query.TenantFilter + $GraphRequest = Get-SherwebCurrentSubscription -TenantFilter $TenantFilter } else { - $GraphRequest = Get-SherwebCatalog -TenantFilter $Request.Query.TenantFilter + $GraphRequest = Get-SherwebCatalog -TenantFilter $TenantFilter } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 index 2e1aa667bd40..83dfbdaf9002 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListDeviceDetails.ps1 @@ -13,36 +13,34 @@ Function Invoke-ListDeviceDetails { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + # XXX Seems to be an unused endpoint? -Bobby # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Query.tenantFilter $DeviceID = $Request.Query.DeviceID $DeviceName = $Request.Query.DeviceName $DeviceSerial = $Request.Query.DeviceSerial try { if ($DeviceID) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceID" -Tenantid $tenantfilter + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices/$DeviceID" -Tenantid $TenantFilter } elseif ($DeviceSerial -or $DeviceName) { $Found = $False - if ($SeriaNumber -and $DeviceName) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial' and deviceName eq '$DeviceName'" -Tenantid $tenantfilter + if ($DeviceSerial -and $DeviceName) { + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial' and deviceName eq '$DeviceName'" -Tenantid $TenantFilter if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { $Found = $True } } if ($DeviceSerial -and $Found -eq $False) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial'" -Tenantid $tenantfilter + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=serialnumber eq '$DeviceSerial'" -Tenantid $TenantFilter if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { $Found = $True } } if ($DeviceName -and $Found -eq $False) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=deviceName eq '$DeviceName'" -Tenantid $tenantfilter + $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=deviceName eq '$DeviceName'" -Tenantid $TenantFilter if (($GraphRequest | Measure-Object).count -eq 1 -and $GraphRequest.'@odata.count' -ne 0 ) { $Found = $True } @@ -80,7 +78,7 @@ Function Invoke-ListDeviceDetails { $DetectedApps = Get-GraphBulkResultByID -Results $BulkResults -ID 'DetectedApps' $Null = $GraphRequest | Add-Member -NotePropertyName 'DetectedApps' -NotePropertyValue ($DetectedApps.DetectedApps | Select-Object id, displayName, version) - $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue ($CompliancePolicies | Select-Object id, displayname, UserPrincipalName, state) + $Null = $GraphRequest | Add-Member -NotePropertyName 'CompliancePolicies' -NotePropertyValue ($CompliancePolicies | Select-Object id, displayName, UserPrincipalName, state) $Null = $GraphRequest | Add-Member -NotePropertyName 'DeviceGroups' -NotePropertyValue ($DeviceGroups | Select-Object id, displayName, description) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 index 26c014d0c8d5..9bcb80aca64e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListFunctionStats.ps1 @@ -13,24 +13,22 @@ Function Invoke-ListFunctionStats { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -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. - try { - $TenantFilter = $Request.Query.TenantFilter + $TenantFilter = $Request.Query.tenantFilter $PartitionKey = $Request.Query.FunctionType + $Time = $Request.Query.Time + $Interval = $Request.Query.Interval - $Timestamp = if (![string]::IsNullOrEmpty($Request.Query.Interval) -and ![string]::IsNullOrEmpty($Request.Query.Time)) { - switch ($Request.Query.Interval) { + $Timestamp = if (![string]::IsNullOrEmpty($Interval) -and ![string]::IsNullOrEmpty($Time)) { + switch ($Interval) { 'Days' { - (Get-Date).AddDays(-$Request.Query.Time).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') + (Get-Date).AddDays(-$Time).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') } 'Hours' { - (Get-Date).AddHours(-$Request.Query.Time).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') + (Get-Date).AddHours(-$Time).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') } 'Minutes' { - (Get-Date).AddMinutes(-$Request.Query.Time).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') + (Get-Date).AddMinutes(-$Time).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') } } } else { @@ -69,7 +67,7 @@ Function Invoke-ListFunctionStats { 'AvgSeconds' = $Stats.Average } } - $Status = [HttpStatusCode]::OK + $StatusCode = [HttpStatusCode]::OK $Body = @{ Results = @{ Functions = @($FunctionStats) @@ -80,7 +78,7 @@ Function Invoke-ListFunctionStats { } } } catch { - $Status = [HttpStatusCode]::BadRequest + $StatusCode = [HttpStatusCode]::BadRequest $Body = @{ Results = @() Metadata = @{ @@ -91,7 +89,7 @@ Function Invoke-ListFunctionStats { } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $Status + StatusCode = $StatusCode Body = $Body }) -Clobber diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 deleted file mode 100644 index f579777b5607..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericAllTenants.ps1 +++ /dev/null @@ -1,51 +0,0 @@ -using namespace System.Net - -Function Invoke-ListGenericAllTenants { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - CIPP.Core.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $TableURLName = ($QueueItem.tolower().split('?').Split('/') | Select-Object -First 1).toString() - $QueueKey = (Invoke-ListCippQueue | Where-Object -Property Name -EQ $TableURLName | Select-Object -Last 1).RowKey - Update-CippQueueEntry -RowKey $QueueKey -Status 'Started' - $Table = Get-CIPPTable -TableName "cache$TableURLName" - $fullUrl = "https://graph.microsoft.com/beta/$QueueItem" - Get-CIPPAzDataTableEntity @Table | Remove-AzDataTableEntity -Force @table - - $RawGraphRequest = Get-Tenants | ForEach-Object -Parallel { - $domainName = $_.defaultDomainName - Import-Module '.\Modules\AzBobbyTables' - Import-Module '.\Modules\CIPPCore' - try { - Write-Host $using:fullUrl - New-GraphGetRequest -uri $using:fullUrl -tenantid $_.defaultDomainName -ComplexFilter -ErrorAction Stop | Select-Object *, @{l = 'Tenant'; e = { $domainName } }, @{l = 'CippStatus'; e = { 'Good' } } - } catch { - [PSCustomObject]@{ - Tenant = $domainName - CippStatus = "Could not connect to tenant. $($_.Exception.message)" - } - } - } - - Update-CippQueueEntry -RowKey $QueueKey -Status 'Processing' - foreach ($Request in $RawGraphRequest) { - $Json = ConvertTo-Json -Compress -InputObject $request - $GraphRequest = [PSCustomObject]@{ - Tenant = [string]$Request.tenant - RowKey = [string](New-Guid) - PartitionKey = [string]$URL - Data = [string]$Json - - } - Add-CIPPAzDataTableEntity @Table -Entity $GraphRequest -Force | Out-Null - } - - - Update-CippQueueEntry -RowKey $QueueKey -Status 'Completed' - -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 index cea9da93182e..bb2172b2ec95 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGenericTestFunction.ps1 @@ -11,8 +11,9 @@ Function Invoke-ListGenericTestFunction { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $graphRequest = ($request.headers.'x-ms-original-url').split('/api') | Select-Object -First 1 + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $graphRequest = ($Headers.'x-ms-original-url').split('/api') | Select-Object -First 1 Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 deleted file mode 100644 index d8febbcf029b..000000000000 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListIntunePolicy.ps1 +++ /dev/null @@ -1,118 +0,0 @@ - -Function Invoke-ListIntunePolicy { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Endpoint.MEM.Read - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $Headers = $Request.Headers - Write-LogMessage -Headers $Headers -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 - $id = $Request.Query.ID - $URLName = $Request.Query.URLName - try { - if ($ID) { - $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($URLName)('$ID')" -tenantid $TenantFilter - } else { - $Groups = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$top=999' -tenantid $TenantFilter | Select-Object -Property id, displayName - - $BulkRequests = [PSCustomObject]@( - @{ - id = 'DeviceConfigurations' - method = 'GET' - url = "/deviceManagement/deviceConfigurations?`$select=id,displayName,lastModifiedDateTime,roleScopeTagIds,microsoft.graph.unsupportedDeviceConfiguration/originalEntityTypeName,description&`$expand=assignments&top=1000" - } - @{ - id = 'WindowsDriverUpdateProfiles' - method = 'GET' - url = "/deviceManagement/windowsDriverUpdateProfiles?`$expand=assignments&top=200" - } - @{ - id = 'GroupPolicyConfigurations' - method = 'GET' - url = "/deviceManagement/groupPolicyConfigurations?`$expand=assignments&top=1000" - } - @{ - id = 'MobileAppConfigurations' - method = 'GET' - url = "/deviceAppManagement/mobileAppConfigurations?`$expand=assignments&`$filter=microsoft.graph.androidManagedStoreAppConfiguration/appSupportsOemConfig%20eq%20true" - } - @{ - id = 'ConfigurationPolicies' - method = 'GET' - url = "/deviceManagement/configurationPolicies?`$expand=assignments&top=1000" - } - ) - - $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.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 ($null -eq $_.displayname) { $_ | 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 { $null -ne $_.DisplayName } - } - } - - # Filter the results to sort out linux scripts - $GraphRequest = $GraphRequest | Where-Object { $_.platforms -ne 'linux' -and $_.templateReference.templateFamily -ne 'deviceConfigurationScripts' } - $StatusCode = [HttpStatusCode]::OK - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $StatusCode = [HttpStatusCode]::Forbidden - $GraphRequest = $ErrorMessage - } - # Associate values to output bindings by calling 'Push-OutputBinding'. - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = $StatusCode - Body = @($GraphRequest) - }) -} diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 index e336eddbc938..0f666d3fce64 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListKnownIPDb.ps1 @@ -16,7 +16,7 @@ Function Invoke-ListKnownIPDb { # Write to the Azure Functions log stream. Write-Host 'PowerShell HTTP trigger function processed a request.' - $Table = Get-CIPPTable -TableName 'knownlocationdb' + $Table = Get-CIPPTable -TableName 'knownlocationdbv2' $Filter = "Tenant eq '$($Request.Query.TenantFilter)'" $KnownIPDb = Get-CIPPAzDataTableEntity @Table -Filter $Filter diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 index ddad3aa638a7..e344ac10776e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListPendingWebhooks.ps1 @@ -13,8 +13,6 @@ Function Invoke-ListPendingWebhooks { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' try { $Table = Get-CIPPTable -TableName 'WebhookIncoming' $Webhooks = Get-CIPPAzDataTableEntity @Table diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 index 01dcabaf6174..84c536889682 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListTenantAllowBlockList.ps1 @@ -13,32 +13,26 @@ Function Invoke-ListTenantAllowBlockList { $APIName = $Request.Params.CIPPEndpoint Write-LogMessage -headers $Request.Headers -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 + $TenantFilter = $Request.Query.tenantFilter $ListTypes = 'Sender', 'Url', 'FileHash' try { - $cmdletArray = $ListTypes | ForEach-Object { - @{ - CmdletInput = @{ - CmdletName = 'Get-TenantAllowBlockListItems' - Parameters = @{ListType = $_ } - } - } - } - $BatchResults = New-ExoBulkRequest -tenantid $TenantFilter -cmdletArray @($cmdletArray) + $Results = $ListTypes | ForEach-Object -Parallel { + Import-Module CIPPCore + $TempResults = New-ExoRequest -tenantid $using:TenantFilter -cmdlet 'Get-TenantAllowBlockListItems' -cmdParams @{ListType = $_ } + $TempResults | Add-Member -MemberType NoteProperty -Name ListType -Value $_ + $TempResults | Select-Object -ExcludeProperty *'@data.type'*, *'(DateTime])'* + } -ThrottleLimit 5 $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden - $BatchResults = $ErrorMessage + $Results = $ErrorMessage } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @($BatchResults) + Body = @($Results) }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 index 84a81ea0f4cd..70b4d553949b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-RemoveTenantAllowBlockList.ps1 @@ -11,23 +11,22 @@ Function Invoke-RemoveTenantAllowBlockList { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - Write-LogMessage -headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Body.tenantFilter + $Headers = $Request.Headers + Write-LogMessage -headers $Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' + + # Interact with query parameters or the body of the request. + $Entries = $Request.Body.Entries + $ListType = $Request.Body.ListType - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' try { - $listType = switch -Wildcard ($request.body.entries) { - '*@*' { 'Sender'; break } - '*.*' { 'Url'; break } - default { 'FileHash' } - } Write-Host "List type is $listType" $ExoRequest = @{ - tenantid = $Request.body.tenantfilter + tenantid = $TenantFilter cmdlet = 'Remove-TenantAllowBlockListItems' cmdParams = @{ - Entries = @($Request.body.entries) + Entries = @($Entries) ListType = $ListType } } @@ -35,20 +34,22 @@ Function Invoke-RemoveTenantAllowBlockList { $Results = New-ExoRequest @ExoRequest Write-Host $Results - $result = "Successfully removed $($Request.body.entries) from Block/Allow list" - Write-LogMessage -headers $Request.Headers -API $APIName -tenant $Request.query.tenantfilter -message $result -Sev 'Info' + $Result = "Successfully removed $($Entries) with type $ListType from Block/Allow list" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - $result = "Failed to remove $($Request.body.entries). Error: $ErrorMessage" - Write-LogMessage -headers $Request.Headers -API $APIName -tenant $Request.query.tenantfilter -message $result -Sev 'Error' + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to remove $($Entries) type $ListType. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Result -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' = $result - 'Request' = $ExoRequest + 'Results' = $Result + # 'Request' = $ExoRequest } }) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 index 25deaf238213..e7010fd8fa0a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogOrchestrator.ps1 @@ -19,13 +19,12 @@ function Start-AuditLogOrchestrator { } elseif (($WebhookRules | Measure-Object).Count -eq 0) { Write-Information 'No webhook rules defined' } else { - Write-Information "Audit Logs: Processing $($AuditLogSearches.Count) searches" + Write-Information "Audit Logs: Downloading $($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' } } - + $Queue = New-CippQueueEntry -Name 'Audit Logs Download' -Reference 'AuditLogsDownload' -TotalTasks ($AuditLogSearches).Count + $Batch = $AuditLogSearches | Sort-Object -Property Tenant -Unique | Select-Object @{Name = 'TenantFilter'; Expression = { $_.Tenant } }, @{Name = 'QueueId'; Expression = { $Queue.RowKey } }, @{Name = 'FunctionName'; Expression = { 'AuditLogTenantDownload' } } $InputObject = [PSCustomObject]@{ - OrchestratorName = 'AuditLogs' + OrchestratorName = 'AuditLogsDownload' Batch = @($Batch) SkipLog = $true } diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 new file mode 100644 index 000000000000..e4eb7b779ddf --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 @@ -0,0 +1,42 @@ +function Start-AuditLogProcessingOrchestrator { + <# + .SYNOPSIS + Start the Audit Log Processing Orchestrator + #> + [CmdletBinding(SupportsShouldProcess = $true)] + param() + Write-Information 'Starting audit log processing in batches of 1000, per tenant' + $WebhookCacheTable = Get-CippTable -TableName 'CacheWebhooks' + $WebhookCache = Get-CIPPAzDataTableEntity @WebhookCacheTable + $TenantGroups = $WebhookCache | Group-Object -Property PartitionKey + + if ($TenantGroups) { + Write-Information "Processing webhook cache for $($TenantGroups.Count) tenants" + #Write-Warning "AuditLogJobs are: $($TenantGroups.Count) tenants. Tenants: $($TenantGroups.name | ConvertTo-Json -Compress) " + #Write-Warning "Here are the groups: $($TenantGroups | ConvertTo-Json -Compress)" + $ProcessQueue = New-CippQueueEntry -Name 'Audit Logs Process' -Reference 'AuditLogsProcess' -TotalTasks ($TenantGroups | Measure-Object -Property Count -Sum).Sum + $ProcessBatch = foreach ($TenantGroup in $TenantGroups) { + $TenantFilter = $TenantGroup.Name + $RowIds = @($TenantGroup.Group.RowKey) + for ($i = 0; $i -lt $RowIds.Count; $i += 1000) { + Write-Host "Processing $TenantFilter with $($RowIds.Count) row IDs. We're processing id $($RowIds[$i]) to $($RowIds[[Math]::Min($i + 999, $RowIds.Count - 1)])" + $BatchRowIds = $RowIds[$i..([Math]::Min($i + 999, $RowIds.Count - 1))] + [PSCustomObject]@{ + TenantFilter = $TenantFilter + RowIds = $BatchRowIds + QueueId = $ProcessQueue.RowKey + FunctionName = 'AuditLogTenantProcess' + } + } + } + if ($ProcessBatch) { + $ProcessInputObject = [PSCustomObject]@{ + OrchestratorName = 'AuditLogTenantProcess' + Batch = @($ProcessBatch) + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($ProcessInputObject | ConvertTo-Json -Depth 5 -Compress) + Write-Information "Started audit log processing orchestration with $($ProcessBatch.Count) batches" + } + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ExtensionOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ExtensionOrchestrator.ps1 index 55126c5080ca..9d6fa6a119b7 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ExtensionOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ExtensionOrchestrator.ps1 @@ -15,7 +15,7 @@ function Start-ExtensionOrchestrator { Write-Host 'Started Scheduler for Extensions' # NinjaOne Extension - if ($Configuration.NinjaOne.Enabled -eq $True) { + if ($Configuration.NinjaOne.Enabled -eq $true) { if ($PSCmdlet.ShouldProcess('Invoke-NinjaOneExtensionScheduler')) { Invoke-NinjaOneExtensionScheduler } diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 index ff635480a672..ba15c02add60 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 @@ -17,7 +17,7 @@ function Start-TableCleanup { @{ DataTableProps = @{ Context = (Get-CIPPTable -tablename 'AuditLogSearches').Context - Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-7).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'" + Filter = "Timestamp lt datetime'$((Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'" First = 10000 Property = @('PartitionKey', 'RowKey', 'ETag') } @@ -48,7 +48,27 @@ function Start-TableCleanup { } ) + $DeleteTables = @( + 'knownlocationdb' + ) + if ($PSCmdlet.ShouldProcess('Start-TableCleanup', 'Starting Table Cleanup')) { + foreach ($Table in $DeleteTables) { + try { + $Table = Get-CIPPTable -tablename $Table + if ($Table) { + Write-Information "Deleting table $($Table.Context.TableName)" + try { + Remove-AzDataTable -Context $Table.Context -Force + } catch { + Write-LogMessage -API 'TableCleanup' -message "Failed to delete table $($Table.Context.TableName)" -sev Error -LogData (Get-CippException -Exception $_) + } + } + } catch { + Write-Information "Table $Table not found" + } + } + Write-Information 'Starting table cleanup' foreach ($Rule in $CleanupRules) { if ($Rule.Where) { diff --git a/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 b/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 index f7f6362b8e22..27c4002fb814 100644 --- a/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPAzDatatableEntity.ps1 @@ -23,10 +23,10 @@ function Get-CIPPAzDataTableEntity { } if (-not $mergedResults[$partitionKey].ContainsKey($entityId)) { $mergedResults[$partitionKey][$entityId] = @{ - Parts = New-Object 'System.Collections.ArrayList' + Parts = [System.Collections.Generic.List[object]]::new() } } - $mergedResults[$partitionKey][$entityId]['Parts'].Add($entity) > $null + $mergedResults[$partitionKey][$entityId]['Parts'].Add($entity) } else { $partitionKey = $entity.PartitionKey if (-not $mergedResults.ContainsKey($partitionKey)) { @@ -34,16 +34,16 @@ function Get-CIPPAzDataTableEntity { } $mergedResults[$partitionKey][$entity.RowKey] = @{ Entity = $entity - Parts = New-Object 'System.Collections.ArrayList' + Parts = [System.Collections.Generic.List[object]]::new() } } } - $finalResults = @() + $finalResults = [System.Collections.Generic.List[object]]::new() foreach ($partitionKey in $mergedResults.Keys) { foreach ($entityId in $mergedResults[$partitionKey].Keys) { $entityData = $mergedResults[$partitionKey][$entityId] - if ($entityData.Parts.Count -gt 0) { + if (($entityData.Parts | Measure-Object).Count -gt 0) { $fullEntity = [PSCustomObject]@{} $parts = $entityData.Parts | Sort-Object PartIndex foreach ($part in $parts) { @@ -60,9 +60,9 @@ 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) + $finalResults.Add($fullEntity) } else { - $finalResults = $finalResults + @($entityData.Entity) + $FinalResults.Add($entityData.Entity) } } } diff --git a/Modules/CIPPCore/Public/Get-CIPPBitlockerKey.ps1 b/Modules/CIPPCore/Public/Get-CIPPBitlockerKey.ps1 index b7d8b1646468..291d5b06f63e 100644 --- a/Modules/CIPPCore/Public/Get-CIPPBitlockerKey.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPBitlockerKey.ps1 @@ -4,7 +4,7 @@ function Get-CIPPBitlockerKey { param ( $device, $TenantFilter, - $APIName = 'Get Bitlocker key', + $APIName = 'Get BitLocker key', $Headers ) @@ -14,8 +14,9 @@ function Get-CIPPBitlockerKey { } return $GraphRequest } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -headers $Headers -API $APIName -message "Could not retrieve bitlocker recovery key for $($device)" -Sev 'Error' -tenant $TenantFilter -LogData (Get-CippException -Exception $_) - return "Could not retrieve bitlocker recovery key for $($device). Error: $ErrorMessage" + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Could not retrieve BitLocker recovery key for $($device). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + throw $Result } } diff --git a/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 b/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 index 68b9e03ae1a3..77a9af81e609 100644 --- a/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPMFAState.ps1 @@ -17,10 +17,12 @@ function Get-CIPPMFAState { } } + $Errors = [System.Collections.Generic.List[object]]::new() try { $SecureDefaultsState = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $TenantFilter ).IsEnabled } catch { Write-Host "Secure Defaults not available: $($_.Exception.Message)" + $Errors.Add(@{Step = 'SecureDefaults'; Message = $_.Exception.Message }) } $CAState = [System.Collections.Generic.List[object]]::new() @@ -29,6 +31,9 @@ function Get-CIPPMFAState { } catch { $CAState.Add('Not Licensed for Conditional Access') | Out-Null $MFARegistration = $null + if ($_.Exception.Message -ne "Tenant is not a B2C tenant and doesn't have premium licenses") { + $Errors.Add(@{Step = 'MFARegistration'; Message = $_.Exception.Message }) + } Write-Host "User registration details not available: $($_.Exception.Message)" } @@ -58,6 +63,7 @@ function Get-CIPPMFAState { } catch { $CASuccess = $false $CAError = "CA policies not available: $($_.Exception.Message)" + $Errors.Add(@{Step = 'CAPolicies'; Message = $_.Exception.Message }) } } @@ -113,7 +119,15 @@ function Get-CIPPMFAState { RowKey = [string]($_.UserPrincipalName).replace('#', '') PartitionKey = 'users' } - + } + $ErrorCount = ($Errors | Measure-Object).Count + if ($ErrorCount -gt 0) { + if ($ErrorCount -gt 1) { + $Text = 'errors' + } else { + $Text = 'an error' + } + Write-LogMessage -headers $Headers -API $APIName -Tenant $TenantFilter -message "The MFA report encountered $Text, see log data for details." -Sev 'Error' -LogData @($Errors.Message) } return $GraphRequest } diff --git a/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 b/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 index ced968960b4b..58cb338240bc 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Read-JwtAccessDetails.ps1 @@ -18,6 +18,7 @@ function Read-JwtAccessDetails { IPAddress = '' Name = '' Scope = '' + Roles = '' TenantId = '' UserPrincipalName = '' } @@ -43,8 +44,9 @@ function Read-JwtAccessDetails { $TokenDetails.IPAddress = $TokenObj.ipaddr $TokenDetails.Name = $TokenObj.name $TokenDetails.Scope = $TokenObj.scp -split ' ' + $TokenDetails.Roles = $TokenObj.roles $TokenDetails.TenantId = $TokenObj.tid $TokenDetails.UserPrincipalName = $TokenObj.upn return $TokenDetails -} \ No newline at end of file +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 index e9e7380906dd..9dca6bdc7b1f 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Remove-CIPPCache.ps1 @@ -13,28 +13,36 @@ function Remove-CIPPCache { if ($ClearIncludedTenants) { Remove-AzDataTableEntity -Force @TenantsTable -Entity $ClearIncludedTenants } + "Removed $($ClearIncludedTenants.Count) tenants" - if ($TenantsOnly -eq 'false') { - Write-Host 'Clearing all' + if ($TenantsOnly -eq $false) { + 'Clearing all cached table data' + $Context = New-AzDataTableContext -ConnectionString $env:AzureWebJobsStorage + $Tables = Get-AzDataTable -Context $Context + foreach ($Table in $Tables) { + if ($Table -match '^cache') { + "Removing cache table $Table" + $TableContext = Get-CIPPTable -TableName $Table + Remove-AzDataTable @TableContext + } + } + + 'Clearing domain analyser results' # Remove Domain Analyser cached results $DomainsTable = Get-CippTable -tablename 'Domains' $Filter = "PartitionKey eq 'TenantDomains'" $ClearDomainAnalyserRows = Get-CIPPAzDataTableEntity @DomainsTable -Filter $Filter | ForEach-Object { - $_.DomainAnalyser = '' + $_ | Add-Member -MemberType NoteProperty -Name DomainAnalyser -Value '' -Force $_ } if ($ClearDomainAnalyserRows) { Update-AzDataTableEntity -Force @DomainsTable -Entity $ClearDomainAnalyserRows } - #Clear BPA - $BPATable = Get-CippTable -tablename 'cachebpav2' - $ClearBPARows = Get-CIPPAzDataTableEntity @BPATable - if ($ClearBPARows) { - Remove-AzDataTableEntity -Force @BPATable -Entity $ClearBPARows - } + $ENV:SetFromProfile = $null $Script:SkipListCache = $Null $Script:SkipListCacheEmpty = $Null $Script:IncludedTenantsCache = $Null } + 'Cache cleanup complete' } diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index 98d09f7507c9..b66d9565e7fb 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -138,9 +138,9 @@ function Get-GraphRequestList { $Table = Get-CIPPTable -TableName $TableName $Timestamp = (Get-Date).AddHours(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffK') if ($TenantFilter -eq 'AllTenants') { - $Filter = "PartitionKey eq '{0}' and QueueType eq 'AllTenants' and Timestamp ge datetime'{1}'" -f $PartitionKey, $Timestamp + $Filter = "PartitionKey eq '{0}' and Timestamp ge datetime'{1}'" -f $PartitionKey, $Timestamp } else { - $Filter = "PartitionKey eq '{0}' and Tenant eq '{1}' and Timestamp ge datetime'{2}'" -f $PartitionKey, $TenantFilter, $Timestamp + $Filter = "PartitionKey eq '{0}' and (RowKey eq '{1}' or OriginalEntityId eq '{1}') and Timestamp ge datetime'{2}'" -f $PartitionKey, $TenantFilter, $Timestamp } $Rows = Get-CIPPAzDataTableEntity @Table -Filter $Filter $Type = 'Cache' @@ -337,8 +337,16 @@ function Get-GraphRequestList { } } } else { - $Rows | ForEach-Object { - $_.Data | ConvertFrom-Json + foreach ($Row in $Rows) { + if ($Row.Data) { + try { + $Row.Data | ConvertFrom-Json -ErrorAction Stop + } catch { + Write-Warning "Could not convert data to JSON: $($_.Exception.Message)" + #Write-Information ($Row | ConvertTo-Json) + continue + } + } } } } diff --git a/Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 deleted file mode 100644 index 376e2a02918e..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveBPATemplate.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveBPATemplate { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Tenant.ConditionalAccess.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $ID = $request.query.TemplateName - try { - $Table = Get-CippTable -tablename 'templates' - - $Filter = "PartitionKey eq 'BPATemplate' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -Headers $User -API $APINAME -message "Removed BPA Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed BPA Template' } - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove BPA 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-RemoveCAPolicy.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 deleted file mode 100644 index 9d5a9380afcb..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveCAPolicy.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveCAPolicy { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Tenant.ConditionalAccess.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $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 -asapp $true - Write-LogMessage -Headers $User -API $APINAME -message "Deleted CA Policy $policyId" -Sev 'Info' -tenant $TenantFilter - $body = [pscustomobject]@{'Results' = 'Successfully deleted the policy' } - - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Could not delete CA policy $policyId. $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Could not delete policy: $($ErrorMessage.NormalizedError)" } - - } - - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $body - }) - - -} diff --git a/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 deleted file mode 100644 index d355cf2a2235..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveCATemplate.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveCATemplate { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Tenant.ConditionalAccess.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - $ID = $request.query.id - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - try { - $Table = Get-CippTable -tablename 'templates' - - $Filter = "PartitionKey eq 'CATemplate' and RowKey eq '$id'" - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -Headers $User -API $APINAME -message "Removed Conditional Access Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Conditional Access Template' } - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove Conditional Access template $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' - $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-RemoveConnectionfilterTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveConnectionfilterTemplate.ps1 deleted file mode 100644 index a36d7a66d94e..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveConnectionfilterTemplate.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveConnectionfilterTemplate { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.ConnectionFilter.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $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 -Headers $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 -Headers $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-RemoveContact.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 deleted file mode 100644 index 1494650832e9..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveContact.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveContact { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Contact.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $Tenantfilter = $request.Query.tenantfilter - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - - $Params = @{ - Identity = $request.query.guid - } - - try { - $Params = @{ Identity = $request.query.GUID } - - $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Remove-MailContact' -cmdParams $params -UseSystemMailbox $true - $Result = "Deleted $($Request.query.guid)" - Write-LogMessage -Headers $User -API $APIName -tenant $tenantfilter -message "Deleted contact $($Request.query.guid)" -sev Debug - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APIName -tenant $tenantfilter -message "Failed to delete contact $($Request.query.guid). $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage - $Result = $ErrorMessage.NormalizedError - } - # 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/Invoke-RemoveGroupTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 deleted file mode 100644 index bf0c45d1f90d..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveGroupTemplate.ps1 +++ /dev/null @@ -1,42 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveGroupTemplate { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Identity.Group.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $ID = $request.query.id - try { - $Table = Get-CippTable -tablename 'templates' - Write-Host $id - - $Filter = "PartitionKey eq 'GroupTemplate' and RowKey eq '$id'" - Write-Host $Filter - $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -Headers $User -API $APINAME -message "Removed Intune Template with ID $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed Template' } - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove intune 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-RemoveQueuedApp.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 index d4714f12dc55..4cbe632f33f3 100644 --- a/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 +++ b/Modules/CIPPCore/Public/Invoke-RemoveQueuedApp.ps1 @@ -11,26 +11,28 @@ Function Invoke-RemoveQueuedApp { param($Request, $TriggerMetadata) $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -Headers $Request.Headers -API $APIName -message 'Accessed this API' -Sev 'Debug' - $ID = $request.body.id + $ID = $request.body.ID try { $Table = Get-CippTable -tablename 'apps' - $Filter = "PartitionKey eq 'apps' and RowKey eq '$id'" + $Filter = "PartitionKey eq 'apps' and RowKey eq '$ID'" $ClearRow = Get-CIPPAzDataTableEntity @Table -Filter $Filter -Property PartitionKey, RowKey - Remove-AzDataTableEntity -Force @Table -Entity $clearRow - Write-LogMessage -Headers $User -API $APINAME -message "Removed application queue for $ID." -Sev 'Info' - $body = [pscustomobject]@{'Results' = 'Successfully removed from queue.' } + Remove-AzDataTableEntity -Force @Table -Entity $ClearRow + $Message = "Removed application queue for $ID." + Write-LogMessage -Headers $Request.Headers -API $APIName -message $Message -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Failed to remove application queue for $ID. $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Failed to remove item. $(Get-NormalizedError -message $_.Exception.Message)" } + $Message = "Failed to remove application queue for $ID. $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Request.Headers -API $APIName -message $Message -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::Forbidden } + $body = [pscustomobject]@{'Results' = $Message } # 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/Invoke-RemoveSpamfilter.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 deleted file mode 100644 index c67bf676a579..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilter.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveSpamfilter { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Spamfilter.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - $Tenantfilter = $request.Query.tenantfilter - - $Params = @{ - Identity = $request.query.name - } - - try { - $cmdlet = 'Remove-HostedContentFilterRule' - $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true - $cmdlet = 'Remove-HostedContentFilterPolicy' - $null = New-ExoRequest -tenantid $Tenantfilter -cmdlet $cmdlet -cmdParams $params -useSystemmailbox $true - $Result = "Deleted $($Request.query.name)" - Write-LogMessage -Headers $User -API 'TransportRules' -tenant $tenantfilter -message "Deleted transport rule $($Request.query.name)" -sev Debug - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API 'TransportRules' -tenant $tenantfilter -message "Failed deleting transport rule $($Request.query.name). Error:$($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage - $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/Invoke-RemoveSpamfilterTemplate.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 deleted file mode 100644 index c66447217bff..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveSpamfilterTemplate.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveSpamfilterTemplate { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Exchange.Spamfilter.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - $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 -Headers $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 -Headers $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)" } - } - - - # 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-RemoveUser.ps1 b/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 deleted file mode 100644 index 264aeaf9ec9f..000000000000 --- a/Modules/CIPPCore/Public/Invoke-RemoveUser.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -using namespace System.Net - -Function Invoke-RemoveUser { - <# - .FUNCTIONALITY - Entrypoint - .ROLE - Identity.User.ReadWrite - #> - [CmdletBinding()] - param($Request, $TriggerMetadata) - - $APIName = $Request.Params.CIPPEndpoint - $User = $Request.Headers - Write-LogMessage -Headers $User -API $APINAME -message 'Accessed this API' -Sev 'Debug' - - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $userid = $Request.Query.ID - if (!$userid) { exit } - try { - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter - Write-LogMessage -Headers $User -API $APINAME -message "Deleted $userid" -Sev 'Info' -tenant $TenantFilter - $body = [pscustomobject]@{'Results' = 'Successfully deleted the user.' } - - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -message "Could not delete user $userid. $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - $body = [pscustomobject]@{'Results' = "Could not delete user: $($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/New-CIPPIntuneTemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 index 25595a59eb51..6b89083b332b 100644 --- a/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPIntuneTemplate.ps1 @@ -97,6 +97,12 @@ function New-CIPPIntuneTemplate { $TemplateJson = (ConvertTo-Json -InputObject $inputvar -Depth 100 -Compress) } + 'windowsFeatureUpdateProfiles' { + $Type = 'windowsFeatureUpdateProfiles' + $Template = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$($urlname)/$($ID)" -tenantid $tenantfilter | Select-Object * -ExcludeProperty id, lastModifiedDateTime, '@odata.context', 'ScopeTagIds', 'supportsScopeTags', 'createdDateTime' + $DisplayName = $Template.displayName + $TemplateJson = ConvertTo-Json -InputObject $Template -Depth 100 -Compress + } } return [PSCustomObject]@{ TemplateJson = $TemplateJson diff --git a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 index 90df35f9d05c..3f500f41a30d 100644 --- a/Modules/CIPPCore/Public/New-CIPPTAP.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPTAP.ps1 @@ -7,21 +7,19 @@ function New-CIPPTAP { $Headers ) - try { $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/authentication/temporaryAccessPassMethods" -tenantid $TenantFilter -type POST -body '{}' -verbose Write-LogMessage -headers $Headers -API $APIName -message "Created Temporary Access Password (TAP) for $userid" -Sev 'Info' -tenant $TenantFilter - 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' - } + $Results = [System.Collections.Generic.List[string]]::new() + $Results.Add("The TAP for this user is $($GraphRequest.temporaryAccessPass) - This TAP is usable for the next $($GraphRequest.LifetimeInMinutes) minutes") + $Results.Add("$($GraphRequest.temporaryAccessPass)") + return $Results } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -message "Failed to created TAP for $($userid): $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - Return [pscustomobject]@{ resultText = "Failed to create TAP: $($ErrorMessage.NormalizedError)" - state = 'error' - } + $Result = "Failed to create Temporary Access Password (TAP) for $($userid): $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + throw @{ Results = $Result } } diff --git a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 index d23a10deb209..f0738334ee7d 100644 --- a/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPUserTask.ps1 @@ -49,6 +49,11 @@ function New-CIPPUserTask { $results.add($ManagerResult) } + if ($userobj.setSponsor) { + $SponsorResult = Set-CIPPManager -user $CreationResults.username -Manager $userObj.setSponsor.value -TenantFilter $UserObj.tenantFilter -APIName 'Set Sponsor' -Headers $Headers + $results.add($SponsorResult) + } + return @{ Results = $results username = $CreationResults.username @@ -56,4 +61,3 @@ function New-CIPPUserTask { CopyFrom = $CopyFrom } } - diff --git a/Modules/CIPPCore/Public/New-CippUser.ps1 b/Modules/CIPPCore/Public/New-CippUser.ps1 index 234c9392ba03..b741a161bded 100644 --- a/Modules/CIPPCore/Public/New-CippUser.ps1 +++ b/Modules/CIPPCore/Public/New-CippUser.ps1 @@ -13,7 +13,7 @@ function New-CIPPUser { Write-Host $UserObj.PrimDomain.value $Aliases = ($UserObj.AddedAliases) -split '\s' $password = if ($UserObj.password) { $UserObj.password } else { New-passwordString } - $UserprincipalName = "$($UserObj.Username ? $userobj.username :$userobj.mailNickname )@$($UserObj.Domain ? $UserObj.Domain : $UserObj.PrimDomain.value)" + $UserprincipalName = "$($userobj.username)@$($UserObj.Domain ? $UserObj.Domain : $UserObj.PrimDomain.value)" Write-Host "Creating user $UserprincipalName" Write-Host "tenant filter is $($UserObj.tenantFilter)" $BodyToship = [pscustomobject] @{ @@ -22,7 +22,7 @@ function New-CIPPUser { 'accountEnabled' = $true 'displayName' = $UserObj.displayName 'department' = $UserObj.Department - 'mailNickname' = $UserObj.Username ? $userobj.username :$userobj.mailNickname + 'mailNickname' = $UserObj.Username ? $userobj.username : $userobj.mailNickname 'userPrincipalName' = $UserprincipalName 'usageLocation' = $UserObj.usageLocation.value ? $UserObj.usageLocation.value : $UserObj.usageLocation 'city' = $UserObj.City diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroup.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroup.ps1 index b356dd990b3a..3f1bdafec13a 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGroup.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPGroup.ps1 @@ -11,20 +11,21 @@ function Remove-CIPPGroup { try { if ($GroupType -eq 'Distribution List' -or $GroupType -eq 'Mail-Enabled Security') { - New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-DistributionGroup' -cmdParams @{Identity = $id; BypassSecurityGroupManagerCheck = $true } -useSystemMailbox $true - Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantfilter) -message "$($DisplayName) Deleted" -Sev 'Info' + New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-DistributionGroup' -cmdParams @{Identity = $ID; BypassSecurityGroupManagerCheck = $true } -useSystemMailbox $true + Write-LogMessage -headers $Headers -API $APINAME -tenant $($TenantFilter) -message "$($DisplayName) Deleted" -Sev 'Info' return "Successfully Deleted $($GroupType) group $($DisplayName)" } elseif ($GroupType -eq 'Microsoft 365' -or $GroupType -eq 'Security') { $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/groups/$($ID)" -tenantid $TenantFilter -type Delete -verbose - Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantfilter) -message "$($DisplayName) Deleted" -Sev 'Info' + Write-LogMessage -headers $Headers -API $APINAME -tenant $($TenantFilter) -message "$($DisplayName) Deleted" -Sev 'Info' return "Successfully Deleted $($GroupType) group $($DisplayName)" } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -message "Could not delete $DisplayName. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - return "Could not delete $DisplayName. Error: $($ErrorMessage.NormalizedError)" + $Message = "Could not delete $DisplayName. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + throw $Message } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 index 47b494ac4b7c..fbc5cd2d436e 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 @@ -22,7 +22,7 @@ function Remove-CIPPMailboxRule { return "No rules for $($username) to delete" } else { ForEach ($rule in $rules) { - New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-InboxRule' -Anchor $username -cmdParams @{Identity = $rule.Identity } + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Remove-InboxRule' -Anchor $username -cmdParams @{Identity = $rule.Identity } } Write-LogMessage -headers $Headers -API $APIName -message "Deleted Rules for $($username)" -Sev 'Info' -tenant $TenantFilter return "Deleted Rules for $($username)" diff --git a/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 b/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 index b789f5943fc5..d892e9421227 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPUser.ps1 @@ -10,13 +10,14 @@ function Remove-CIPPUser { try { $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)" -type DELETE -tenant $TenantFilter - Write-LogMessage -headers $Headers, -API $APIName -message "Deleted account $username" -Sev 'Info' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message "Deleted account $username" -Sev 'Info' -tenant $TenantFilter return "Deleted the user account $username" } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers, -API $APIName -message "Could not delete $username. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - return "Could not delete $username. Error: $($ErrorMessage.NormalizedError)" + $Message = "Could not delete $username. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + return $Message } } diff --git a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 index 82ee5126cd4c..a7f37e6e7854 100644 --- a/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 +++ b/Modules/CIPPCore/Public/Revoke-CIPPSessions.ps1 @@ -2,14 +2,14 @@ function Revoke-CIPPSessions { [CmdletBinding()] param ( $Headers, - $userid, - $username, + $UserID, + $Username, $APIName = 'Revoke Sessions', $TenantFilter ) try { - $GraphRequest = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/invalidateAllRefreshTokens" -tenantid $TenantFilter -type POST -body '{}' -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($userid)/invalidateAllRefreshTokens" -tenantid $TenantFilter -type POST -body '{}' -verbose Write-LogMessage -headers $Headers -API $APIName -message "Revoked sessions for $($username)" -Sev 'Info' -tenant $TenantFilter return "Success. All sessions by $username have been revoked" diff --git a/Modules/CIPPCore/Public/SAMManifest.json b/Modules/CIPPCore/Public/SAMManifest.json index 65b801589a7f..a76e42384a22 100644 --- a/Modules/CIPPCore/Public/SAMManifest.json +++ b/Modules/CIPPCore/Public/SAMManifest.json @@ -554,6 +554,10 @@ { "id": "b7887744-6746-4312-813d-72daeaee7e2d", "type": "Scope" + }, + { + "id": "a8ead177-1889-4546-9387-f25e658e2a79", + "type": "Scope" } ] }, diff --git a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 index 671daa0667fa..a719998ee3fe 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 @@ -2,43 +2,47 @@ function Set-CIPPAssignedPolicy { [CmdletBinding(SupportsShouldProcess = $true)] param( $GroupName, + $ExcludeGroup, $PolicyId, $Type, $TenantFilter, - $PlatformType, + $PlatformType = 'deviceManagement', $APIName = 'Assign Policy', $Headers ) - if (!$PlatformType) { $PlatformType = 'deviceManagement' } + + Write-Host "Assigning policy $PolicyId ($PlatformType/$Type) to $GroupName" + try { - $assignmentsObject = switch ($GroupName) { + $assignmentsList = New-Object System.Collections.Generic.List[System.Object] + switch ($GroupName) { 'allLicensedUsers' { - @( + $assignmentsList.Add( @{ target = @{ '@odata.type' = '#microsoft.graph.allLicensedUsersAssignmentTarget' } } ) - break } 'AllDevices' { - @( + $assignmentsList.Add( @{ target = @{ '@odata.type' = '#microsoft.graph.allDevicesAssignmentTarget' } } ) - break } 'AllDevicesAndUsers' { - @( + $assignmentsList.Add( @{ target = @{ '@odata.type' = '#microsoft.graph.allDevicesAssignmentTarget' } - }, + } + ) + $assignmentsList.Add( @{ target = @{ '@odata.type' = '#microsoft.graph.allLicensedUsersAssignmentTarget' @@ -48,36 +52,67 @@ function Set-CIPPAssignedPolicy { } default { Write-Host "We're supposed to assign a custom group. The group is $GroupName" - $GroupNames = $GroupName.Split(',') - $GroupIds = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$select=id,displayName&$top=999' -tenantid $TenantFilter | ForEach-Object { - $Group = $_ - foreach ($SingleName in $GroupNames) { + $GroupNames = $GroupName.Split(',').Trim() + $GroupIds = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$select=id,displayName&$top=999' -tenantid $TenantFilter | + ForEach-Object { + foreach ($SingleName in $GroupNames) { + if ($_.displayName -like $SingleName) { + $_.id + } + } + } + foreach ($gid in $GroupIds) { + $assignmentsList.Add( + @{ + target = @{ + '@odata.type' = '#microsoft.graph.groupAssignmentTarget' + groupId = $gid + } + } + ) + } + } + } + if ($ExcludeGroup) { + Write-Host "We're supposed to exclude a custom group. The group is $ExcludeGroup" + $ExcludeGroupNames = $ExcludeGroup.Split(',').Trim() + $ExcludeGroupIds = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/groups?$select=id,displayName&$top=999' -tenantid $TenantFilter | + ForEach-Object { + foreach ($SingleName in $ExcludeGroupNames) { if ($_.displayName -like $SingleName) { - $group.id + $_.id } } } - foreach ($Group in $GroupIds) { + + foreach ($egid in $ExcludeGroupIds) { + $assignmentsList.Add( @{ target = @{ - '@odata.type' = '#microsoft.graph.groupAssignmentTarget' - groupId = $Group + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = $egid } } - } + ) } } + $assignmentsObject = [PSCustomObject]@{ - assignments = @($assignmentsObject) + assignments = $assignmentsList } - $AssignJSON = ($assignmentsObject | ConvertTo-Json -Depth 10 -Compress) + $AssignJSON = $assignmentsObject | ConvertTo-Json -Depth 10 -Compress Write-Host "AssignJSON: $AssignJSON" if ($PSCmdlet.ShouldProcess($GroupName, "Assigning policy $PolicyId")) { - Write-Host "https://graph.microsoft.com/beta/$($PlatformType)/$Type('$($PolicyId)')/assign" - $null = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$($PlatformType)/$Type('$($PolicyId)')/assign" -tenantid $tenantFilter -type POST -body $AssignJSON - Write-LogMessage -headers $Headers -API $APIName -message "Assigned $GroupName to Policy $PolicyId" -Sev 'Info' -tenant $TenantFilter + $uri = "https://graph.microsoft.com/beta/$($PlatformType)/$Type('$($PolicyId)')/assign" + $null = New-GraphPOSTRequest -uri $uri -tenantid $TenantFilter -type POST -body $AssignJSON + if ($ExcludeGroup) { + Write-LogMessage -headers $Headers -API $APIName -message "Assigned group '$GroupName' and excluded group '$ExcludeGroup' on Policy $PolicyId" -Sev 'Info' -tenant $TenantFilter + } else { + Write-LogMessage -headers $Headers -API $APIName -message "Assigned group '$GroupName' on Policy $PolicyId" -Sev 'Info' -tenant $TenantFilter + } } + } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -headers $Headers -API $APIName -message "Failed to assign $GroupName to Policy $PolicyId, using Platform $PlatformType and $Type. The error is:$ErrorMessage" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage diff --git a/Modules/CIPPCore/Public/Set-CIPPGroupAuthentication.ps1 b/Modules/CIPPCore/Public/Set-CIPPGroupAuthentication.ps1 index 6fca31b53dbf..561670eae554 100644 --- a/Modules/CIPPCore/Public/Set-CIPPGroupAuthentication.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPGroupAuthentication.ps1 @@ -19,11 +19,13 @@ function Set-CIPPGroupAuthentication( return "$GroupType's group cannot have this setting changed" } - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "$Id set to allow messages from people $messageSuffix" -Sev 'Info' - return "Set $GroupType group $Id to allow messages from people $messageSuffix" + $Message = "Successfully set $GroupType group $Id to allow messages from people $messageSuffix" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' + return $Message } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Delivery Management failed: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - return "Failed. $($ErrorMessage.NormalizedError)" + $Message = "Failed to set Delivery Management: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message $Message -Sev 'Error' -LogData $ErrorMessage + return $Message } } diff --git a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 index b34daface0e1..23d8bc8e8462 100644 --- a/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPHideFromGAL.ps1 @@ -10,11 +10,13 @@ function Set-CIPPHideFromGAL { $Text = if ($HideFromGAL) { 'hidden' } else { 'unhidden' } try { $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $UserId ; HiddenFromAddressListsEnabled = $HideFromGAL } - Write-LogMessage -headers $Headers -API $APINAME -tenant $($Tenantfilter) -message "$($UserId) $Text from GAL" -Sev Info - return "Successfully $Text $($UserId) from GAL." + $Result = "Successfully $Text $($UserId) from GAL." + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev Info + return $Result } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -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)" + $Result = "Failed to hide $($UserId) from GAL. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + return $Result } } diff --git a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 index 85323c33a79d..173a37b874a9 100644 --- a/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPIntunePolicy.ps1 @@ -6,125 +6,167 @@ function Set-CIPPIntunePolicy { $DisplayName, $RawJSON, $AssignTo, + $ExcludeGroup, $Headers, $APINAME, $tenantFilter ) + #connect to table, get replacement map. This is for future usage. The replacement map will allow users to create custom vars that get replaced by the actual values per tenant. Example: + # %WallPaperPath% gets replaced by RowKey WallPaperPath which is set to C:\Wallpapers for tenant 1, and D:\Wallpapers for tenant 2 + $ReplaceTable = Get-CIPPTable -tablename 'CippReplacemap' + $ReplaceMap = Get-CIPPAzDataTableEntity @ReplaceTable -Filter "PartitionKey eq '$tenantFilter'" + if ($ReplaceMap) { + foreach ($Replace in $ReplaceMap) { + $RawJSON = $RawJSON -replace $Replace.RowKey, $Replace.Value + } + } + #default replacements for all tenants: %tenantid% becomes $tenant.customerId, %tenantfilter% becomes $tenant.defaultDomainName, %tenantname% becomes $tenant.displayName + $Tenant = Get-Tenants -TenantFilter $tenantFilter + $RawJSON = $RawJSON -replace '%tenantid%', $Tenant.customerId + $RawJSON = $RawJSON -replace '%tenantfilter%', $Tenant.defaultDomainName + $RawJSON = $RawJSON -replace '%tenantname%', $Tenant.displayName + + try { switch ($TemplateType) { 'AppProtection' { + $PlatformType = 'deviceAppManagement' $TemplateType = ($RawJSON | ConvertFrom-Json).'@odata.type' -replace '#microsoft.graph.', '' $PolicyFile = $RawJSON | ConvertFrom-Json $Null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'description' -Value $description -Force $null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'displayName' -Value $displayname -Force $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 20 $TemplateTypeURL = if ($TemplateType -eq 'windowsInformationProtectionPolicy') { 'windowsInformationProtectionPolicies' } else { "$($TemplateType)s" } - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenantFilter + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($displayname -in $CheckExististing.displayName) { $PostType = 'edited' $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName } else { $PostType = 'added' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceAppManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON } } 'deviceCompliancePolicies' { + $PlatformType = 'deviceManagement' $TemplateTypeURL = 'deviceCompliancePolicies' - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter $JSON = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty id, createdDateTime, lastModifiedDateTime, version, 'scheduledActionsForRule@odata.context', '@odata.context' $JSON.scheduledActionsForRule = @($JSON.scheduledActionsForRule | Select-Object * -ExcludeProperty 'scheduledActionConfigurations@odata.context') if ($displayname -in $CheckExististing.displayName) { $RawJSON = ConvertTo-Json -InputObject ($JSON | Select-Object * -ExcludeProperty 'scheduledActionsForRule') -Depth 20 -Compress $PostType = 'edited' $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($DisplayName) to template defaults" -Sev 'info' $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName } else { $RawJSON = ConvertTo-Json -InputObject $JSON -Depth 20 -Compress $PostType = 'added' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } 'Admin' { + $PlatformType = 'deviceManagement' $TemplateTypeURL = 'groupPolicyConfigurations' $CreateBody = '{"description":"' + $description + '","displayName":"' + $displayname + '","roleScopeTagIds":["0"]}' - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($displayname -in $CheckExististing.displayName) { $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname - $ExistingData = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($ExistingID.id)')/definitionValues" -tenantid $tenantFilter + $ExistingData = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$($ExistingID.id)')/definitionValues" -tenantid $tenantFilter $DeleteJson = $RawJSON | ConvertFrom-Json -Depth 10 $DeleteJson.deletedIds = @($ExistingData.id) $DeleteJson.added = @() $DeleteJson = ConvertTo-Json -Depth 10 -InputObject $DeleteJson - $DeleteRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($ExistingID.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $DeleteJson - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($ExistingID.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $RawJSON + $DeleteRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$($ExistingID.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $DeleteJson + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$($ExistingID.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($Displayname) to template defaults" -Sev 'info' $PostType = 'edited' } else { $PostType = 'added' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $CreateBody - $UpdateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL('$($CreateRequest.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $CreateBody + $UpdateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL('$($CreateRequest.id)')/updateDefinitionValues" -tenantid $tenantFilter -type POST -body $RawJSON Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($Displayname) to template defaults" -Sev 'info' } } 'Device' { + $PlatformType = 'deviceManagement' $TemplateTypeURL = 'deviceConfigurations' $PolicyFile = $RawJSON | ConvertFrom-Json $Null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'description' -Value "$description" -Force $null = $PolicyFile | Add-Member -MemberType NoteProperty -Name 'displayName' -Value $displayname -Force - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName | Select-Object -Last 1 $PolicyFile = $policyFile | Select-Object * -ExcludeProperty 'featureUpdatesWillBeRolledBack', 'qualityUpdatesWillBeRolledBack', 'qualityUpdatesPauseStartDate', 'featureUpdatesPauseStartDate' $RawJSON = ConvertTo-Json -InputObject $PolicyFile -Depth 100 -Compress if ($ExistingID) { $PostType = 'edited' Write-Host "Raw JSON is $RawJSON" - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PATCH -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Updated policy $($DisplayName) to template defaults" -Sev 'info' } else { $PostType = 'added' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } 'Catalog' { + $PlatformType = 'deviceManagement' $TemplateTypeURL = 'configurationPolicies' $DisplayName = ($RawJSON | ConvertFrom-Json).Name - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($DisplayName -in $CheckExististing.name) { $ExistingID = $CheckExististing | Where-Object -Property Name -EQ $DisplayName - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property Name -EQ $DisplayName $PostType = 'edited' } else { $PostType = 'added' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } 'windowsDriverUpdateProfiles' { + $PlatformType = 'deviceManagement' $TemplateTypeURL = 'windowsDriverUpdateProfiles' $File = ($RawJSON | ConvertFrom-Json) $DisplayName = $File.displayName ?? $File.Name - $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter + if ($DisplayName -in $CheckExististing.displayName) { + $PostType = 'edited' + $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname + Write-Host 'We are editing' + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON + $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName + + } else { + $PostType = 'added' + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' + } + } + 'windowsFeatureUpdateProfiles' { + $PlatformType = 'deviceManagement' + $TemplateTypeURL = 'windowsFeatureUpdateProfiles' + $File = ($RawJSON | ConvertFrom-Json) + $DisplayName = $File.displayName ?? $File.Name + $CheckExististing = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter if ($DisplayName -in $CheckExististing.displayName) { $PostType = 'edited' $ExistingID = $CheckExististing | Where-Object -Property displayName -EQ $displayname Write-Host 'We are editing' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL/$($ExistingID.Id)" -tenantid $tenantFilter -type PUT -body $RawJSON $CreateRequest = $CheckExististing | Where-Object -Property displayName -EQ $DisplayName } else { $PostType = 'added' - $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/deviceManagement/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON + $CreateRequest = New-GraphPOSTRequest -uri "https://graph.microsoft.com/beta/$PlatformType/$TemplateTypeURL" -tenantid $tenantFilter -type POST -body $RawJSON Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantFilter) -message "Added policy $($DisplayName) via template" -Sev 'info' } } @@ -135,7 +177,7 @@ function Set-CIPPIntunePolicy { Write-Host "Assigning policy to $($AssignTo) with ID $($CreateRequest.id) and type $TemplateTypeURL for tenant $tenantFilter" Write-Host "ID is $($CreateRequest.id)" - Set-CIPPAssignedPolicy -GroupName $AssignTo -PolicyId $CreateRequest.id -Type $TemplateTypeURL -TenantFilter $tenantFilter + Set-CIPPAssignedPolicy -GroupName $AssignTo -PolicyId $CreateRequest.id -PlatformType $PlatformType -Type $TemplateTypeURL -TenantFilter $tenantFilter -ExcludeGroup $ExcludeGroup } return "Successfully $($PostType) policy for $($tenantFilter) with display name $($Displayname)" } catch { diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxArchive.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxArchive.ps1 index c21505e27310..e20ee118a99a 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxArchive.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxArchive.ps1 @@ -2,23 +2,31 @@ function Set-CIPPMailboxArchive { [CmdletBinding()] param ( $Headers, - $userid, - $username, + $UserID, + $Username, $APIName = 'Mailbox Archive', $TenantFilter, - [bool]$ArchiveEnabled + [bool]$ArchiveEnabled, + [switch]$AutoExpandingArchive ) - $User = $Request.Headers + try { + if ([string]::IsNullOrWhiteSpace($Username)) { $Username = $UserID } + $OperationType = if ($AutoExpandingArchive.IsPresent -eq $true) { 'auto-expanding archive' } else { 'archive' } + if ($AutoExpandingArchive.IsPresent -eq $true) { + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Enable-Mailbox' -cmdParams @{Identity = $UserID; AutoExpandingArchive = $true } + $Message = "Successfully enabled $OperationType for $Username" + } else { + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Enable-Mailbox' -cmdParams @{Identity = $UserID; Archive = $ArchiveEnabled } + $Message = "Successfully set $OperationType for $Username to $ArchiveEnabled" + } - Try { - if (!$username) { $username = $userid } - $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Enable-Mailbox' -cmdParams @{Identity = $userid; Archive = $ArchiveEnabled } - "Successfully set archive for $username to $ArchiveEnabled" - Write-LogMessage -Headers $User -API $APINAME -tenant $($tenantfilter) -message "Successfully set archive for $username to $ArchiveEnabled" -Sev 'Info' + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' + return $Message } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -Headers $User -API $APINAME -tenant $($tenantfilter) -message "Failed to set archive for $username. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - "Failed. $($ErrorMessage.NormalizedError)" + $Message = "Failed to set $OperationType for $Username. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message $Message -Sev 'Error' -LogData $ErrorMessage + throw $Message } } diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxLocale.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxLocale.ps1 index 42f922e7891a..5d3fde2bbdf1 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxLocale.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxLocale.ps1 @@ -14,11 +14,13 @@ function Set-CippMailboxLocale { Language = $locale LocalizeDefaultFolderName = $true } -Anchor $username - Write-LogMessage -headers $Headers -API $APIName -message "set locale for $($username) to a $locale" -Sev 'Info' -tenant $TenantFilter - return "set locale for $($username) to a $locale" + $Result = "Set locale for $($username) to a $locale" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Info' -tenant $TenantFilter + return $Result } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -message "Could not set locale for $($username). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - return "Could not set locale for $username. Error: $($ErrorMessage.NormalizedError)" + $Result = "Could not set locale for $($username). Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + throw $Result } } diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 index cd2ba3313635..60f9a6fb4fbf 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxType.ps1 @@ -2,22 +2,24 @@ function Set-CIPPMailboxType { [CmdletBinding()] param ( $Headers, - $userid, - $username, + $UserID, + $Username, $APIName = 'Mailbox Conversion', $TenantFilter, - [Parameter()] + [Parameter(Mandatory = $true)] [ValidateSet('Shared', 'Regular', 'Room', 'Equipment')]$MailboxType ) try { - if ([string]::IsNullOrWhiteSpace($username)) { $username = $userid } - $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; Type = $MailboxType } -Anchor $username - Write-LogMessage -headers $Headers -API $APIName -message "Converted $($username) to a $MailboxType mailbox" -Sev 'Info' -tenant $TenantFilter - return "Converted $username to a $MailboxType mailbox" + if ([string]::IsNullOrWhiteSpace($Username)) { $Username = $UserID } + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $UserID; Type = $MailboxType } -Anchor $Username + $Message = "Converted $Username to a $MailboxType mailbox" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev 'Info' -tenant $TenantFilter + return $Message } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -message "Could not convert $username to $MailboxType mailbox. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - return "Could not convert $username to a $MailboxType mailbox. Error: $($ErrorMessage.NormalizedError)" + $Message = "Could not convert $Username to a $MailboxType mailbox. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + return $Message } } diff --git a/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 b/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 index 8f3e6fe17c33..512d56a75257 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 @@ -2,18 +2,20 @@ function Set-CIPPMessageCopy { [CmdletBinding()] param ( $userid, - $MessageCopyForSentAsEnabled, + [bool]$MessageCopyForSentAsEnabled, $TenantFilter, $APIName = 'Manage OneDrive Access', $Headers ) Try { - New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; MessageCopyForSentAsEnabled = $MessageCopyForSentAsEnabled } - Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantfilter) -message "Successfully set MessageCopyForSentAsEnabled as $MessageCopyForSentAsEnabled on $($userid)." -Sev 'Info' - return "Successfully set MessageCopyForSentAsEnabled as $MessageCopyForSentAsEnabled on $($userid)." + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; MessageCopyForSentAsEnabled = $MessageCopyForSentAsEnabled } + $Result = "Successfully set MessageCopyForSentAsEnabled as $MessageCopyForSentAsEnabled on $($userid)." + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Info' + return $Result } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APINAME -tenant $($tenantfilter) -message "set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled failed: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage - return "set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled failed - $($ErrorMessage.NormalizedError)" + $Result = "Failed to set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled - $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Error' -LogData $ErrorMessage + throw $Result } } diff --git a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 index 74d248789127..ff87694f31f0 100644 --- a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 @@ -1,8 +1,9 @@ function Set-CIPPResetPassword { [CmdletBinding()] param( - $userid, - $tenantFilter, + $UserID, + $DisplayName, + $TenantFilter, $APIName = 'Reset Password', $Headers, [bool]$forceChangePasswordNextSignIn = $true @@ -17,32 +18,32 @@ function Set-CIPPResetPassword { } } | ConvertTo-Json -Compress - $UserDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)?`$select=onPremisesSyncEnabled" -noPagination $true -tenantid $TenantFilter -verbose - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($userid)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose + $UserDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)?`$select=onPremisesSyncEnabled" -noPagination $true -tenantid $TenantFilter -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose #PWPush $PasswordLink = New-PwPushLink -Payload $password if ($PasswordLink) { $password = $PasswordLink } - Write-LogMessage -headers $Headers -API $APIName -message "Reset the password for $($userid). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message "Reset the password for $DisplayName, $($UserID). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter 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." + return [pscustomobject]@{ resultText = "Reset the password for $DisplayName, $($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" + return [pscustomobject]@{ resultText = "Reset the password for $DisplayName, $($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 -headers $Headers -API $APIName -message "Could not reset password for $($userid). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + Write-LogMessage -headers $Headers -API $APIName -message "Could not reset password for $DisplayName, $($UserID). Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage return [pscustomobject]@{ - resultText = "Could not reset password for $($userid). Error: $($ErrorMessage.NormalizedError)" + resultText = "Could not reset password for $DisplayName, $($UserID). Error: $($ErrorMessage.NormalizedError)" state = 'Error' } } diff --git a/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 b/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 index 743b0a53c7d2..46eddbd432fd 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSAMAdminRoles.ps1 @@ -20,10 +20,15 @@ function Set-CIPPSAMAdminRoles { $SAMRolesTable = Get-CIPPTable -tablename 'SAMRoles' $Roles = Get-CIPPAzDataTableEntity @SAMRolesTable - $SAMRoles = $Roles.Roles | ConvertFrom-Json - $Tenants = $Roles.Tenants | ConvertFrom-Json - if ($Tenants.value) { - $Tenants = $Tenants.value + try { + $SAMRoles = $Roles.Roles | ConvertFrom-Json -ErrorAction Stop + $Tenants = $Roles.Tenants | ConvertFrom-Json -ErrorAction Stop + if ($Tenants.value) { + $Tenants = $Tenants.value + } + } catch { + $ActionLogs.Add('CIPP-SAM roles not configured') + return $ActionLogs } if (($SAMRoles | Measure-Object).count -gt 0 -and $Tenants -contains $TenantFilter -or $Tenants -contains 'AllTenants') { diff --git a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 index f3a51da6934b..bf2266cae08b 100644 --- a/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPSignInState.ps1 @@ -1,7 +1,7 @@ function Set-CIPPSignInState { [CmdletBinding()] param ( - $UserId, + $UserID, [bool]$AccountEnabled, $TenantFilter, $APIName = 'Disable User Sign-in', @@ -13,19 +13,19 @@ function Set-CIPPSignInState { accountEnabled = [bool]$AccountEnabled } $body = ConvertTo-Json -InputObject $body -Compress -Depth 5 - $UserDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)?`$select=onPremisesSyncEnabled" -noPagination $true -tenantid $TenantFilter -verbose - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)" -tenantid $TenantFilter -type PATCH -body $body -verbose - Write-LogMessage -headers $Headers -API $APIName -message "Set account enabled state to $AccountEnabled for $UserId" -Sev 'Info' -tenant $TenantFilter + $UserDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)?`$select=onPremisesSyncEnabled" -noPagination $true -tenantid $TenantFilter -verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)" -tenantid $TenantFilter -type PATCH -body $body -verbose + Write-LogMessage -headers $Headers -API $APIName -message "Set account enabled state to $AccountEnabled for $UserID" -Sev 'Info' -tenant $TenantFilter if ($UserDetails.onPremisesSyncEnabled -eq $true) { return 'WARNING: User is AD Sync enabled. Please enable/disable in AD.' } else { - return "Set account enabled state to $AccountEnabled for $UserId" + return "Set account enabled state to $AccountEnabled for $UserID" } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -message "Could not disable sign in for $UserId. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + Write-LogMessage -headers $Headers -API $APIName -message "Could not disable sign in for $UserID. Error: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage return "Could not disable $UserId. Error: $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 deleted file mode 100644 index c9f10dd78b14..000000000000 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPConfig.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -function Invoke-CIPPStandardAPConfig { - <# - .FUNCTIONALITY - Internal - #> - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'APConfig' - - If ($Settings.remediate -eq $true) { - - try { - Write-Host $($settings | ConvertTo-Json -Depth 100) - if ($settings.NotLocalAdmin -eq $true) { $usertype = 'Standard' } else { $usertype = 'Administrator' } - $DeploymentMode = if ($settings.DeploymentMode -eq 'true') { 'shared' } else { 'singleUser' } - - $Parameters = @{ - tenantFilter = $tenant - displayname = $settings.DisplayName - description = $settings.Description - usertype = $usertype - DeploymentMode = $DeploymentMode - assignto = $settings.Assignto - devicenameTemplate = $Settings.DeviceNameTemplate - allowWhiteGlove = $Settings.allowWhiteglove - CollectHash = $Settings.CollectHash - hideChangeAccount = $Settings.HideChangeAccount - hidePrivacy = $Settings.HidePrivacy - hideTerms = $Settings.HideTerms - Autokeyboard = $Settings.Autokeyboard - Language = $Settings.languages.value - } - Set-CIPPDefaultAPDeploymentProfile @Parameters - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - # Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Default Autopilot config: $ErrorMessage" -sev 'Error' - throw $ErrorMessage - } - - } -} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 deleted file mode 100644 index 303a30afd009..000000000000 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAPESP.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -function Invoke-CIPPStandardAPESP { - <# - .FUNCTIONALITY - Internal - #> - param($Tenant, $Settings) - If ($Settings.remediate -eq $true) { - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'APESP' - if ($Rerun -eq $true) { - exit 0 - } - try { - $Parameters = @{ - TenantFilter = $Tenant - ShowProgress = $Settings.ShowProgress - BlockDevice = $Settings.blockDevice - AllowReset = $Settings.AllowReset - EnableLog = $Settings.EnableLog - ErrorMessage = $Settings.ErrorMessage - TimeOutInMinutes = $Settings.TimeOutInMinutes - AllowFail = $Settings.AllowFail - OBEEOnly = $Settings.OBEEOnly - } - - Set-CIPPDefaultAPEnrollment @Parameters - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - throw $ErrorMessage - } - } - - -} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 index ad6778144a6a..22ac25cb001a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardActivityBasedTimeout.ps1 @@ -13,13 +13,14 @@ function Invoke-CIPPStandardActivityBasedTimeout { CAT Global Standards TAG - "mediumimpact" "CIS" "spo_idle_session_timeout" ADDEDCOMPONENT - {"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"}]} + {"type":"autoComplete","multiple":false,"creatable":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 + ADDEDDATE + 2022-04-13 POWERSHELLEQUIVALENT Portal or Graph API RECOMMENDEDBY @@ -33,28 +34,31 @@ function Invoke-CIPPStandardActivityBasedTimeout { param($Tenant, $Settings) #$Rerun -Type Standard -Tenant $Tenant -API 'ActivityBasedTimeout' -Settings $Settings + # Get timeout value using null-coalescing operator + $timeout = $Settings.timeout.value ?? $Settings.timeout + # Input validation - if ([string]::IsNullOrWhiteSpace($Settings.timeout) -or $Settings.timeout -eq 'Select a value' ) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'ActivityBasedTimeout: Invalid timeout parameter set' -sev Error + if ([string]::IsNullOrWhiteSpace($timeout) -or $timeout -eq 'Select a value' ) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'ActivityBasedTimeout: Invalid timeout parameter set' -sev Error Return } # Backwards compatibility for v5.7.0 and older - if ($null -eq $Settings.timeout ) { $Settings.timeout = '01:00:00' } + if ($null -eq $timeout ) { $timeout = '01:00:00' } - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' -tenantid $tenant - $StateIsCorrect = if ($CurrentState.definition -like "*$($Settings.timeout)*") { $true } else { $false } + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies' -tenantid $Tenant + $StateIsCorrect = if ($CurrentState.definition -like "*$timeout*") { $true } else { $false } If ($Settings.remediate -eq $true) { try { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Activity Based Timeout is already enabled and set to $($Settings.timeout)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Activity Based Timeout is already enabled and set to $timeout" -sev Info } else { $PolicyTemplate = @{ displayName = 'DefaultTimeoutPolicy' isOrganizationDefault = $true definition = @( - "{`"ActivityBasedTimeoutPolicy`":{`"Version`":1,`"ApplicationPolicies`":[{`"ApplicationId`":`"default`",`"WebSessionIdleTimeout`":`"$($Settings.timeout)`"}]}}" + "{`"ActivityBasedTimeoutPolicy`":{`"Version`":1,`"ApplicationPolicies`":[{`"ApplicationId`":`"default`",`"WebSessionIdleTimeout`":`"$timeout`"}]}}" ) } $body = ConvertTo-Json -InputObject $PolicyTemplate -Depth 10 -Compress @@ -67,26 +71,26 @@ function Invoke-CIPPStandardActivityBasedTimeout { $RequestType = 'PATCH' $URI = "https://graph.microsoft.com/beta/policies/activityBasedTimeoutPolicies/$($CurrentState.id)" } - New-GraphPostRequest -tenantid $tenant -Uri $URI -Type $RequestType -Body $body -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Enabled Activity Based Timeout with a value of $($Settings.timeout)" -sev Info + New-GraphPostRequest -tenantid $Tenant -Uri $URI -Type $RequestType -Body $body -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Enabled Activity Based Timeout with a value of $timeout" -sev Info } } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to enable Activity Based Timeout a value of $($Settings.timeout)." -sev Error -LogData $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to enable Activity Based Timeout a value of $timeout." -sev Error -LogData $_ } } if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Activity Based Timeout is enabled and set to $($Settings.timeout)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Activity Based Timeout is enabled and set to $timeout" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Activity Based Timeout is not set to $($Settings.timeout)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Activity Based Timeout is not set to $timeout" -sev Alert } } if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'ActivityBasedTimeout' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'ActivityBasedTimeout' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index df9c1b8c58e5..9625f199fec9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardAddDKIM { CAT Exchange Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2023-03-14 POWERSHELLEQUIVALENT New-DkimSigningConfig and Set-DkimSigningConfig RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 index 1eeaae1b89fb..c44bafe196c3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAnonReportDisable.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardAnonReportDisable { CAT Global Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Update-MgBetaAdminReportSetting -BodyParameter @{displayConcealedNames = \$true} RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index 888a7fca3608..9f577250c442 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -1,222 +1,223 @@ -function Invoke-CIPPStandardAntiPhishPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) AntiPhishPolicy - .SYNOPSIS - (Label) Default Anti-Phishing Policy - .DESCRIPTION - (Helptext) This creates a Anti-Phishing policy that automatically enables Mailbox Intelligence and spoofing, optional switches for Mailtips. - (DocsDescription) This creates a Anti-Phishing policy that automatically enables Mailbox Intelligence and spoofing, optional switches for Mailtips. - .NOTES - CAT - Defender Standards - TAG - "lowimpact" - "CIS" - "mdo_safeattachments" - "mdo_highconfidencespamaction" - "mdo_highconfidencephishaction" - "mdo_phisspamacation" - "mdo_spam_notifications_only_for_admins" - "mdo_antiphishingpolicies" - "mdo_phishthresholdlevel" - ADDEDCOMPONENT - {"type":"number","label":"Phishing email threshold. (Default 1)","name":"standards.AntiPhishPolicy.PhishThresholdLevel","default":1} - {"type":"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 - Set-AntiphishPolicy or New-AntiphishPolicy - RECOMMENDEDBY - "CIS" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - 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) { - $PolicyName = $PolicyList[0] - } else { - $PolicyName = $ExistingPolicy.Name - } - $RuleList = @( 'CIPP Default Anti-Phishing Rule','CIPP Default Anti-Phishing Policy') - $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishRule' | Where-Object -Property Name -In $RuleList - if ($null -eq $ExistingRule.Name) { - $RuleName = $RuleList[0] - } else { - $RuleName = $ExistingRule.Name - } - - $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 - - 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' - - $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishRule' | - Where-Object -Property Name -EQ $RuleName | - Select-Object Name, AntiPhishPolicy, Priority, RecipientDomainIs - - $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and - ($RuleState.AntiPhishPolicy -eq $PolicyName) -and - ($RuleState.Priority -eq 0) -and - (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy already correctly configured' -sev Info - } else { - 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) { - try { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Anti-phishing policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Anti-phishing policy $PolicyName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Anti-phishing policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing policy $PolicyName." -sev Error -LogData $_ - } - } - } - - if ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name - } - - if ($RuleState.AntiPhishPolicy -ne $PolicyName) { - $cmdparams.Add('AntiPhishPolicy', $PolicyName) - } - - if ($RuleState.Name -eq $RuleName) { - try { - $cmdparams.Add('Identity', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Anti-phishing rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Anti-phishing rule $RuleName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Anti-phishing rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing rule $RuleName." -sev Error -LogData $_ - } - } - } - } - - if ($Settings.alert -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy is not enabled' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } - -} +function Invoke-CIPPStandardAntiPhishPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) AntiPhishPolicy + .SYNOPSIS + (Label) Default Anti-Phishing Policy + .DESCRIPTION + (Helptext) This creates a Anti-Phishing policy that automatically enables Mailbox Intelligence and spoofing, optional switches for Mailtips. + (DocsDescription) This creates a Anti-Phishing policy that automatically enables Mailbox Intelligence and spoofing, optional switches for Mailtips. + .NOTES + CAT + Defender Standards + TAG + "CIS" + "mdo_safeattachments" + "mdo_highconfidencespamaction" + "mdo_highconfidencephishaction" + "mdo_phisspamacation" + "mdo_spam_notifications_only_for_admins" + "mdo_antiphishingpolicies" + "mdo_phishthresholdlevel" + ADDEDCOMPONENT + {"type":"number","label":"Phishing email threshold. (Default 1)","name":"standards.AntiPhishPolicy.PhishThresholdLevel","defaultValue":1} + {"type":"switch","label":"Show first contact safety tip","name":"standards.AntiPhishPolicy.EnableFirstContactSafetyTips","defaultValue":true} + {"type":"switch","label":"Show user impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarUsersSafetyTips","defaultValue":true} + {"type":"switch","label":"Show domain impersonation safety tip","name":"standards.AntiPhishPolicy.EnableSimilarDomainsSafetyTips","defaultValue":true} + {"type":"switch","label":"Show user impersonation unusual characters safety tip","name":"standards.AntiPhishPolicy.EnableUnusualCharactersSafetyTips","defaultValue":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 + ADDEDDATE + 2024-03-25 + POWERSHELLEQUIVALENT + Set-AntiphishPolicy or New-AntiphishPolicy + RECOMMENDEDBY + "CIS" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + 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) { + $PolicyName = $PolicyList[0] + } else { + $PolicyName = $ExistingPolicy.Name + } + $RuleList = @( 'CIPP Default Anti-Phishing Rule','CIPP Default Anti-Phishing Policy') + $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishRule' | Where-Object -Property Name -In $RuleList + if ($null -eq $ExistingRule.Name) { + $RuleName = $RuleList[0] + } else { + $RuleName = $ExistingRule.Name + } + + $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 + + 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' + + $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AntiPhishRule' | + Where-Object -Property Name -EQ $RuleName | + Select-Object Name, AntiPhishPolicy, Priority, RecipientDomainIs + + $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and + ($RuleState.AntiPhishPolicy -eq $PolicyName) -and + ($RuleState.Priority -eq 0) -and + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy already correctly configured' -sev Info + } else { + 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) { + try { + $cmdparams.Add('Identity', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Anti-phishing policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Anti-phishing policy $PolicyName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Anti-phishing policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing policy $PolicyName." -sev Error -LogData $_ + } + } + } + + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + if ($RuleState.AntiPhishPolicy -ne $PolicyName) { + $cmdparams.Add('AntiPhishPolicy', $PolicyName) + } + + if ($RuleState.Name -eq $RuleName) { + try { + $cmdparams.Add('Identity', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AntiPhishRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Anti-phishing rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Anti-phishing rule $RuleName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-AntiPhishRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Anti-phishing rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Anti-phishing rule $RuleName." -sev Error -LogData $_ + } + } + } + } + + if ($Settings.alert -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Anti-phishing policy is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'AntiPhishPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 new file mode 100644 index 000000000000..3ea9d244aedc --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 @@ -0,0 +1,80 @@ +function Invoke-CIPPStandardAntiSpamSafeList { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) AntiSpamSafeList + .SYNOPSIS + (Label) Set Anti-Spam Connection Filter Safe List + .DESCRIPTION + (Helptext) Sets the anti-spam connection filter policy option 'safe list' in Defender. + (DocsDescription) Sets [Microsoft's built-in 'safe list'](https://learn.microsoft.com/en-us/powershell/module/exchange/set-hostedconnectionfilterpolicy?view=exchange-ps#-enablesafelist) in the anti-spam connection filter policy, rather than setting a custom safe/block list of IPs. + .NOTES + CAT + Defender Standards + TAG + ADDEDCOMPONENT + {"type":"switch","name":"standards.AntiSpamSafeList.EnableSafeList","label":"Enable Safe List"} + IMPACT + Medium Impact + ADDEDDATE + 2025-02-15 + POWERSHELLEQUIVALENT + Set-HostedConnectionFilterPolicy "Default" -EnableSafeList \$true + 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/defender-standards#medium-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'AntiSpamSafeList' + + try { + $State = [System.Convert]::ToBoolean($Settings.EnableSafeList) + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'AntiSpamSafeList: Failed to convert the EnableSafeList parameter to a boolean' -sev Error + Return + } + + try { + $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedConnectionFilterPolicy' -cmdParams @{Identity = 'Default' }).EnableSafeList + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to get the Anti-Spam Connection Filter Safe List. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + Return + } + $WantedState = $State -eq $true ? $true : $false + $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'AntiSpamSafeList' -FieldValue $CurrentState -StoreAs bool -Tenant $Tenant + } + + if ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' + if ($StateIsCorrect -eq $false) { + try { + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-HostedConnectionFilterPolicy' -cmdParams @{ + Identity = 'Default' + EnableSafeList = $WantedState + } + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully set the Anti-Spam Connection Filter Safe List to $WantedState" -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set the Anti-Spam Connection Filter Safe List to $WantedState. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The Anti-Spam Connection Filter Safe List is already set correctly to $WantedState" -sev Info + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The Anti-Spam Connection Filter Safe List is set correctly to $WantedState" -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The Anti-Spam Connection Filter Safe List is not set correctly to $WantedState" -sev Alert + } + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 index bd9b80c3c0c3..183feb83dfee 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardAppDeploy { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT {"type":"textField","name":"standards.AppDeploy.appids","label":"Application IDs, comma separated"} IMPACT Low Impact + ADDEDDATE + 2024-07-07 POWERSHELLEQUIVALENT Portal or Graph API RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 index 510c9fdf9e08..45cd930a4cda 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 @@ -1,75 +1,76 @@ -function Invoke-CIPPStandardAtpPolicyForO365 { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) AtpPolicyForO365 - .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. - .NOTES - CAT - Defender Standards - TAG - "lowimpact" - "CIS" - ADDEDCOMPONENT - {"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 - Set-AtpPolicyForO365 - RECOMMENDEDBY - "CIS" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'AtpPolicyForO365' - - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AtpPolicyForO365' | - Select-Object EnableATPForSPOTeamsODB, EnableSafeDocs, AllowSafeDocsOpen - - $StateIsCorrect = ($CurrentState.EnableATPForSPOTeamsODB -eq $true) -and - ($CurrentState.EnableSafeDocs -eq $true) -and - ($CurrentState.AllowSafeDocsOpen -eq $Settings.AllowSafeDocsOpen) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Atp Policy For O365 already set.' -sev Info - } else { - $cmdparams = @{ - EnableATPForSPOTeamsODB = $true - EnableSafeDocs = $true - AllowSafeDocsOpen = $Settings.AllowSafeDocsOpen - } - - try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AtpPolicyForO365' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Atp Policy For O365' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Atp Policy For O365. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Atp Policy For O365 is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Atp Policy For O365 is not enabled' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'AtpPolicyForO365' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } - -} +function Invoke-CIPPStandardAtpPolicyForO365 { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) AtpPolicyForO365 + .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. + .NOTES + CAT + Defender Standards + TAG + "CIS" + ADDEDCOMPONENT + {"type":"switch","label":"Allow people to click through Protected View even if Safe Documents identified the file as malicious","name":"standards.AtpPolicyForO365.AllowSafeDocsOpen","defaultValue":false,"required":false} + IMPACT + Low Impact + ADDEDDATE + 2024-03-25 + POWERSHELLEQUIVALENT + Set-AtpPolicyForO365 + RECOMMENDEDBY + "CIS" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'AtpPolicyForO365' + + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AtpPolicyForO365' | + Select-Object EnableATPForSPOTeamsODB, EnableSafeDocs, AllowSafeDocsOpen + + $StateIsCorrect = ($CurrentState.EnableATPForSPOTeamsODB -eq $true) -and + ($CurrentState.EnableSafeDocs -eq $true) -and + ($CurrentState.AllowSafeDocsOpen -eq $Settings.AllowSafeDocsOpen) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Atp Policy For O365 already set.' -sev Info + } else { + $cmdparams = @{ + EnableATPForSPOTeamsODB = $true + EnableSafeDocs = $true + AllowSafeDocsOpen = $Settings.AllowSafeDocsOpen + } + + try { + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-AtpPolicyForO365' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Atp Policy For O365' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Atp Policy For O365. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Atp Policy For O365 is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Atp Policy For O365 is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'AtpPolicyForO365' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 index 3c5243f8e732..33f1ef104ac3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardAuditLog { CAT Global Standards TAG - "lowimpact" "CIS" "mip_search_auditlog" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Enable-OrganizationCustomization RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuthMethodsSettings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuthMethodsSettings.ps1 index b379d603c4b4..d09843d89e70 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuthMethodsSettings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAuthMethodsSettings.ps1 @@ -7,22 +7,26 @@ function Invoke-CIPPStandardAuthMethodsSettings { .SYNOPSIS (Label) Configure Authentication Methods Policy Settings .DESCRIPTION - (Helptext) Configures the report suspicious activity settings and system credential preferences in the authentication methods policy - (DocsDescription) This standard allows you to configure the reportSuspiciousActivitySettings and systemCredentialPreferences properties within the authentication methods policy. + (Helptext) Configures the report suspicious activity settings and system credential preferences in the authentication methods policy. + (DocsDescription) Controls the authentication methods policy settings for reporting suspicious activity and system credential preferences. These settings help enhance the security of authentication in your organization. .NOTES CAT - Entra Standards + Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"autoComplete","multiple":false,"name":"standards.AuthMethodsSettings.ReportSuspiciousActivity","label":"Report Suspicious Activity Settings","options":[{"label":"Default","value":"default"},{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} - {"type":"autoComplete","multiple":false,"name":"standards.AuthMethodsSettings.SystemCredential","label":"System Credential Preferences","options":[{"label":"Default","value":"default"},{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"required":false,"name":"standards.AuthMethodsSettings.ReportSuspiciousActivity","label":"Report Suspicious Activity Settings","options":[{"label":"Microsoft managed","value":"default"},{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"required":false,"name":"standards.AuthMethodsSettings.SystemCredential","label":"System Credential Preferences","options":[{"label":"Microsoft managed","value":"default"},{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact + ADDEDDATE + 2025-02-10 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicy + 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/global-standards#low-impact + 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-CIPPStandardAutoAddProxy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 index e74ff3a89996..964706df5ae3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 @@ -1,4 +1,34 @@ function Invoke-CIPPStandardAutoAddProxy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) AutoAddProxy + .SYNOPSIS + (Label) Automatically deploy proxy addresses + .DESCRIPTION + (Helptext) Automatically adds all available domains as a proxy address. + (DocsDescription) Automatically finds all available domain names in the tenant, and tries to add proxy addresses based on the user's UPN to each of these. + .NOTES + CAT + Exchange Standards + TAG + "CIS" + ADDEDCOMPONENT + IMPACT + Medium Impact + ADDEDDATE + 2025-02-07 + POWERSHELLEQUIVALENT + Set-Mailbox -EmailAddresses @{add=\$EmailAddress} + RECOMMENDEDBY + DISABLEDFEATURES + + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + 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-CIPPStandardAutoExpandArchive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 index a7bf50586167..bad412af24fd 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardAutoExpandArchive { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Set-OrganizationConfig -AutoExpandingArchive RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 new file mode 100644 index 000000000000..080b78ba5eab --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 @@ -0,0 +1,76 @@ +function Invoke-CIPPStandardAutopilotProfile { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) AutopilotProfile + .SYNOPSIS + (Label) Enable Autopilot Profile + .DESCRIPTION + (Helptext) Assign the appropriate Autopilot profile to streamline device deployment. + (DocsDescription) This standard allows the deployment of Autopilot profiles to devices, including settings such as unique name templates, language options, and local admin privileges. + .NOTES + CAT + Device Management Standards + TAG + DISABLEDFEATURES + + ADDEDCOMPONENT + {"type":"textField","name":"standards.AutopilotProfile.DisplayName","label":"Profile Display Name"} + {"type":"textField","name":"standards.AutopilotProfile.Description","label":"Profile Description"} + {"type":"textField","name":"standards.AutopilotProfile.DeviceNameTemplate","label":"Unique Device Name Template"} + {"type":"autoComplete","multiple":false,"creatable":false,"name":"standards.AutopilotProfile.Languages","label":"Languages","api":{"url":"/languageList.json","labelField":"language","valueField":"tag"}} + {"type":"switch","name":"standards.AutopilotProfile.CollectHash","label":"Convert all targeted devices to Autopilot","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.AssignToAllDevices","label":"Assign to all devices","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.SelfDeployingMode","label":"Enable Self-deploying Mode","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.HideTerms","label":"Hide Terms and Conditions","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.HidePrivacy","label":"Hide Privacy Settings","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.HideChangeAccount","label":"Hide Change Account Options","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.NotLocalAdmin","label":"Setup user as a standard user (not local admin)","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.AllowWhiteGlove","label":"Allow White Glove OOBE","defaultValue":true} + {"type":"switch","name":"standards.AutopilotProfile.AutoKeyboard","label":"Automatically configure keyboard","defaultValue":true} + IMPACT + Low Impact + ADDEDDATE + 2023-12-30 + 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/ + #> + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'APConfig' + + If ($Settings.remediate -eq $true) { + + try { + Write-Host $($settings | ConvertTo-Json -Depth 100) + if ($settings.NotLocalAdmin -eq $true) { $usertype = 'Standard' } else { $usertype = 'Administrator' } + $DeploymentMode = if ($settings.DeploymentMode -eq 'true') { 'shared' } else { 'singleUser' } + + $Parameters = @{ + tenantFilter = $tenant + displayname = $settings.DisplayName + description = $settings.Description + usertype = $usertype + DeploymentMode = $DeploymentMode + assignto = $settings.Assignto + devicenameTemplate = $Settings.DeviceNameTemplate + allowWhiteGlove = $Settings.allowWhiteglove + CollectHash = $Settings.CollectHash + hideChangeAccount = $Settings.HideChangeAccount + hidePrivacy = $Settings.HidePrivacy + hideTerms = $Settings.HideTerms + Autokeyboard = $Settings.Autokeyboard + Language = $Settings.languages.value + } + Set-CIPPDefaultAPDeploymentProfile @Parameters + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + # Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create Default Autopilot config: $ErrorMessage" -sev 'Error' + throw $ErrorMessage + } + + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 new file mode 100644 index 000000000000..63d2bc635414 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 @@ -0,0 +1,65 @@ +function Invoke-CIPPStandardAutopilotStatusPage { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) AutopilotStatusPage + .SYNOPSIS + (Label) Enable Autopilot Status Page + .DESCRIPTION + (Helptext) Deploy the Autopilot Status Page, which shows progress during device setup through Autopilot. + (DocsDescription) This standard allows configuration of the Autopilot Status Page, providing users with a visual representation of the progress during device setup. It includes options like timeout, logging, and retry settings. + .NOTES + CAT + Device Management Standards + TAG + DISABLEDFEATURES + + ADDEDCOMPONENT + {"type":"number","name":"standards.AutopilotStatusPage.TimeOutInMinutes","label":"Timeout in minutes","defaultValue":60} + {"type":"textField","name":"standards.AutopilotStatusPage.ErrorMessage","label":"Custom Error Message","required":false} + {"type":"switch","name":"standards.AutopilotStatusPage.ShowProgress","label":"Show progress to users","defaultValue":true} + {"type":"switch","name":"standards.AutopilotStatusPage.EnableLog","label":"Turn on log collection","defaultValue":true} + {"type":"switch","name":"standards.AutopilotStatusPage.OBEEOnly","label":"Show status page only with OOBE setup","defaultValue":true} + {"type":"switch","name":"standards.AutopilotStatusPage.BlockDevice","label":"Block device usage during setup","defaultValue":true} + {"type":"switch","name":"standards.AutopilotStatusPage.AllowRetry","label":"Allow retry","defaultValue":true} + {"type":"switch","name":"standards.AutopilotStatusPage.AllowReset","label":"Allow reset","defaultValue":true} + {"type":"switch","name":"standards.AutopilotStatusPage.AllowFail","label":"Allow users to use device if setup fails","defaultValue":true} + IMPACT + Low Impact + ADDEDDATE + 2023-12-30 + 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/ + #> + param($Tenant, $Settings) + If ($Settings.remediate -eq $true) { + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'APESP' + if ($Rerun -eq $true) { + exit 0 + } + try { + $Parameters = @{ + TenantFilter = $Tenant + ShowProgress = $Settings.ShowProgress + BlockDevice = $Settings.blockDevice + AllowReset = $Settings.AllowReset + EnableLog = $Settings.EnableLog + ErrorMessage = $Settings.ErrorMessage + TimeOutInMinutes = $Settings.TimeOutInMinutes + AllowFail = $Settings.AllowFail + OBEEOnly = $Settings.OBEEOnly + } + + Set-CIPPDefaultAPEnrollment @Parameters + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + throw $ErrorMessage + } + } + + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 index 738ef7844b91..4a6e949c4523 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardBookings { CAT Exchange Standards TAG - "mediumimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.Bookings.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"label":"Select value","name":"standards.Bookings.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Medium Impact + ADDEDDATE + 2024-05-31 POWERSHELLEQUIVALENT Set-OrganizationConfig -BookingsEnabled RECOMMENDEDBY @@ -30,42 +31,45 @@ function Invoke-CIPPStandardBookings { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'Bookings' + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').BookingsEnabled - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + $WantedState = if ($state -eq 'true') { $true } else { $false } $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } if ($Settings.report -eq $true) { # Default is not set, not set means it's enabled if ($null -eq $CurrentState ) { $CurrentState = $true } - Add-CIPPBPAField -FieldName 'BookingsState' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'BookingsState' -FieldValue $CurrentState -StoreAs bool -Tenant $Tenant } # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'BookingsEnabled: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'BookingsEnabled: Invalid state parameter set' -sev Error Return } if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $false) { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ BookingsEnabled = $WantedState } -useSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set the tenant Bookings state to $($Settings.state)" -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ BookingsEnabled = $WantedState } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully set the tenant Bookings state to $state" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set the tenant Bookings state to $($Settings.state). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set the tenant Bookings state to $state. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Bookings state is already set correctly to $($Settings.state)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant Bookings state is already set correctly to $state" -sev Info } } if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Bookings is set correctly to $($Settings.state)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant Bookings is set correctly to $state" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Bookings is not set correctly to $($Settings.state)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant Bookings is not set correctly to $state" -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 index 6c28b2d8baf5..76365a928281 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardBranding.ps1 @@ -13,16 +13,17 @@ function Invoke-CIPPStandardBranding { CAT Global Standards TAG - "lowimpact" ADDEDCOMPONENT {"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":"autoComplete","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 + ADDEDDATE + 2024-05-13 POWERSHELLEQUIVALENT Portal only RECOMMENDEDBY @@ -44,10 +45,13 @@ function Invoke-CIPPStandardBranding { Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the branding for $Tenant. This tenant might not have premium licenses available: $ErrorMessage" -Sev Error } + # Get layoutTemplateType value using null-coalescing operator + $layoutTemplateType = $Settings.layoutTemplateType.value ?? $Settings.layoutTemplateType + $StateIsCorrect = ($CurrentState.signInPageText -eq $Settings.signInPageText) -and ($CurrentState.usernameHintText -eq $Settings.usernameHintText) -and ($CurrentState.loginPageTextVisibilitySettings.hideAccountResetCredentials -eq $Settings.hideAccountResetCredentials) -and - ($CurrentState.loginPageLayoutConfiguration.layoutTemplateType -eq $Settings.layoutTemplateType) -and + ($CurrentState.loginPageLayoutConfiguration.layoutTemplateType -eq $layoutTemplateType) -and ($CurrentState.loginPageLayoutConfiguration.isHeaderShown -eq $Settings.isHeaderShown) -and ($CurrentState.loginPageLayoutConfiguration.isFooterShown -eq $Settings.isFooterShown) @@ -69,17 +73,17 @@ function Invoke-CIPPStandardBranding { hideAccountResetCredentials = $Settings.hideAccountResetCredentials } loginPageLayoutConfiguration = [pscustomobject]@{ - layoutTemplateType = $Settings.layoutTemplateType + layoutTemplateType = $layoutTemplateType isHeaderShown = $Settings.isHeaderShown isFooterShown = $Settings.isFooterShown } } | ConvertTo-Json -Compress } - New-GraphPostRequest @GraphRequest + $null = New-GraphPostRequest @GraphRequest Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully updated branding.' -Sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update branding. Error: $($ErrorMessage)" -Sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update branding. Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 index 384c50ee66e2..3345291f41d3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardCloudMessageRecall { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.CloudMessageRecall.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"label":"Select value","name":"standards.CloudMessageRecall.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Low Impact + ADDEDDATE + 2024-05-31 POWERSHELLEQUIVALENT Set-OrganizationConfig -MessageRecallEnabled RECOMMENDEDBY @@ -30,19 +31,22 @@ function Invoke-CIPPStandardCloudMessageRecall { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'CloudMessageRecall' + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').MessageRecallEnabled - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + $WantedState = if ($state -eq 'true') { $true } else { $false } $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } if ($Settings.report -eq $true) { # Default is not set, not set means it's enabled if ($null -eq $CurrentState ) { $CurrentState = $true } - Add-CIPPBPAField -FieldName 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'MessageRecall' -FieldValue $CurrentState -StoreAs bool -Tenant $Tenant } # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'MessageRecallEnabled: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'MessageRecallEnabled: Invalid state parameter set' -sev Error Return } @@ -50,26 +54,23 @@ function Invoke-CIPPStandardCloudMessageRecall { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $false) { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ MessageRecallEnabled = $WantedState } -useSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set the tenant Message Recall state to $($Settings.state)" -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ MessageRecallEnabled = $WantedState } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully set the tenant Message Recall state to $state" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set the tenant Message Recall state to $($Settings.state). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set the tenant Message Recall state to $state. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Message Recall state is already set correctly to $($Settings.state)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant Message Recall state is already set correctly to $state" -sev Info } } if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Message Recall is set correctly to $($Settings.state)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant Message Recall is set correctly to $state" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant Message Recall is not set correctly to $($Settings.state)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant Message Recall is not set correctly to $state" -sev Alert } } - - - } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 index 9c2e705610b7..03105df1c8b5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 @@ -15,9 +15,11 @@ function Invoke-CIPPStandardConditionalAccessTemplate { MULTIPLE True DISABLEDFEATURES - + IMPACT - High + High Impact + ADDEDDATE + 2023-12-30 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"}]} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 index 0bb37f43d770..b6035cb0cd9a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 @@ -13,10 +13,12 @@ function Invoke-CIPPStandardDelegateSentItems { CAT Exchange Standards TAG - "mediumimpact" ADDEDCOMPONENT + {"type":"switch","label":"Include user mailboxes","name":"standards.DelegateSentItems.IncludeUserMailboxes"} IMPACT Medium Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Set-Mailbox RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 index 0d90e2a0e4ff..75929ccdc116 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 @@ -13,13 +13,14 @@ function Invoke-CIPPStandardDeletedUserRentention { CAT SharePoint Standards TAG - "lowimpact" ADDEDCOMPONENT - {"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"}]} + {"type":"autoComplete","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 + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgBetaAdminSharepointSetting + Update-MgBetaAdminSharePointSetting RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block @@ -33,20 +34,23 @@ function Invoke-CIPPStandardDeletedUserRentention { $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'DeletedUserRentention' -FieldValue $CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays -StoreAs string -Tenant $tenant + Add-CIPPBPAField -FieldName 'DeletedUserRentention' -FieldValue $CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays -StoreAs string -Tenant $Tenant } + # Get days value using null-coalescing operator + $Days = $Settings.Days.value ?? $Settings.Days + # Input validation - if (($Settings.Days -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'DeletedUserRententio: Invalid Days parameter set' -sev Error + if (($Days -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'DeletedUserRentention: Invalid Days parameter set' -sev Error Return } # Backwards compatibility for v5.9.4 and back - if ($null -eq $Settings.Days) { + if ([string]::IsNullOrWhiteSpace($Days)) { $WantedState = 365 } else { - $WantedState = [int]$Settings.Days + $WantedState = [int]$Days } $StateSetCorrectly = if ($CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays -eq $WantedState) { $true } else { $false } @@ -57,26 +61,26 @@ function Invoke-CIPPStandardDeletedUserRentention { if ($StateSetCorrectly -eq $false) { try { $body = [PSCustomObject]@{ - deletedUserPersonalSiteRetentionPeriodInDays = $Settings.Days + deletedUserPersonalSiteRetentionPeriodInDays = $Days } $body = ConvertTo-Json -InputObject $body -Depth 5 -Compress - New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type PATCH -Body $body -ContentType 'application/json' + $null = New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type PATCH -Body $body -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set deleted user rentention of OneDrive to $WantedState days(s)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set deleted user retention of OneDrive to $WantedState day(s)" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set deleted user rentention of OneDrive to $WantedState days(s). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set deleted user retention of OneDrive to $WantedState day(s). Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is already set to $WantedState days(s)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Deleted user retention of OneDrive is already set to $WantedState day(s)" -sev Info } } if ($Settings.alert -eq $true) { if ($StateSetCorrectly -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is set to $WantedState days(s)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Deleted user retention of OneDrive is set to $WantedState day(s)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Deleted user rentention of OneDrive is not set to $WantedState days(s). Value is: $($CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays) day(s)." -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Deleted user retention of OneDrive is not set to $WantedState day(s). Current value is: $($CurrentInfo.deletedUserPersonalSiteRetentionPeriodInDays) day(s)." -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 index a09a7fa3daf7..bf7928089d8f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive { CAT SharePoint Standards TAG - "mediumimpact" ADDEDCOMPONENT - {"type":"autoComplete","multiple":false,"label":"Add Shortcuts To OneDrive button state","name":"standards.DisableAddShortcutsToOneDrive.state","options":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"label":"Add Shortcuts To OneDrive button state","name":"standards.DisableAddShortcutsToOneDrive.state","options":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} IMPACT Medium Impact + ADDEDDATE + 2023-07-25 POWERSHELLEQUIVALENT Set-SPOTenant -DisableAddShortcutsToOneDrive \$true or \$false RECOMMENDEDBY @@ -37,12 +38,13 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive { } # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + $StateValue = $Settings.state.value ?? $Settings.state + if (([string]::IsNullOrWhiteSpace($StateValue) -or $StateValue -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'DisableAddShortcutsToOneDrive: Invalid state parameter set' -sev Error Return } - $WantedState = [System.Convert]::ToBoolean($Settings.state) + $WantedState = [System.Convert]::ToBoolean($StateValue) $StateIsCorrect = if ($CurrentState.DisableAddToOneDrive -eq $WantedState) { $true } else { $false } $HumanReadableState = if ($WantedState -eq $true) { 'disabled' } else { 'enabled' } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 index d0061c46b32d..e295651f6165 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardDisableAdditionalStorageProviders { CAT Exchange Standards TAG - "lowimpact" "CIS" "exo_storageproviderrestricted" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-01-17 POWERSHELLEQUIVALENT Get-OwaMailboxPolicy \| Set-OwaMailboxPolicy -AdditionalStorageProvidersEnabled \$False RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 index ac75add64456..d22a1f88b8fa 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableAppCreation.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardDisableAppCreation { CAT Entra (AAD) Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-03-20 POWERSHELLEQUIVALENT Update-MgPolicyAuthorizationPolicy RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 index 73c9716025cf..feab61d0ee06 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 @@ -13,13 +13,16 @@ function Invoke-CIPPStandardDisableBasicAuthSMTP { CAT Global Standards TAG - "mediumimpact" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Set-TransportConfig -SmtpClientAuthenticationDisabled \$true RECOMMENDEDBY + "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 index 42ae78c7a734..b85b0777b6f1 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableEmail.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardDisableEmail { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2023-12-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 index f920de3c18d7..780a8177da55 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardDisableExternalCalendarSharing { CAT Exchange Standards TAG - "lowimpact" "CIS" "exo_individualsharing" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-01-08 POWERSHELLEQUIVALENT Get-SharingPolicy \| Set-SharingPolicy -Enabled \$False RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 index 55c188bda32e..d0661ab6a34b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuestDirectory.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardDisableGuestDirectory { CAT Global Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2022-05-04 POWERSHELLEQUIVALENT Set-AzureADMSAuthorizationPolicy -GuestUserRoleId '2af84b1e-32c8-42b7-82bc-daa82404023b' RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 index 32e3d2a345a4..3271feda4b05 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 @@ -13,13 +13,16 @@ function Invoke-CIPPStandardDisableGuests { CAT Entra (AAD) Standards TAG - "mediumimpact" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2022-10-20 POWERSHELLEQUIVALENT Graph API RECOMMENDEDBY + "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 index ceb53907e1e0..12614ae0090e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardDisableM365GroupUsers { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2022-07-17 POWERSHELLEQUIVALENT Update-MgBetaDirectorySetting RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 index b6507d5710e5..36dc84459f06 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardDisableOutlookAddins { CAT Exchange Standards TAG - "mediumimpact" "CIS" "exo_outlookaddins" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2024-02-05 POWERSHELLEQUIVALENT Get-ManagementRoleAssignment \| Remove-ManagementRoleAssignment RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableQRCodePin.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableQRCodePin.ps1 index 98c05fc3c90e..98ce2c9b1158 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableQRCodePin.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableQRCodePin.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardDisableQRCodePin { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2024-02-10 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 index 2c9a435131d7..8cdba0d63a8b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardDisableReshare { CAT SharePoint Standards TAG - "highimpact" "CIS" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgBetaAdminSharepointSetting + Update-MgBetaAdminSharePointSetting RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 index a9a6e9deeff3..b8e21c804f95 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSMS.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardDisableSMS { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2023-12-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 index 55fa4af4371d..0912dbce54bd 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardDisableSecurityGroupUsers { CAT Entra (AAD) Standards TAG - "mediumimpact" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2022-07-17 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthorizationPolicy RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 index 4567b9d99a72..6829d04564ab 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { CAT Entra (AAD) Standards TAG - "mediumimpact" ADDEDCOMPONENT {"type":"textField","name":"standards.DisableSelfServiceLicenses.Exclusions","label":"License Ids to exclude from this standard","required":false} IMPACT Medium Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Set-MsolCompanySettings -AllowAdHocSubscriptions \$false RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 index 37b894544638..f38bc79e6637 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardDisableSharePointLegacyAuth { CAT SharePoint Standards TAG - "mediumimpact" "CIS" "spo_legacy_auth" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2024-02-05 POWERSHELLEQUIVALENT Set-SPOTenant -LegacyAuthProtocolsEnabled \$false RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 index 7a42cc0ec788..071a8d12d38e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharedMailbox.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardDisableSharedMailbox { CAT Exchange Standards TAG - "mediumimpact" "CIS" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Get-Mailbox & Update-MgUser RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 index 4ad21eb72c6c..450882ec1bbe 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardDisableTNEF { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-04-26 POWERSHELLEQUIVALENT Set-RemoteDomain -Identity 'Default' -TNEFEnabled \$false RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 index 1a2ebea5f2f0..34192ba11dd3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableTenantCreation.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardDisableTenantCreation { CAT Entra (AAD) Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2022-11-29 POWERSHELLEQUIVALENT Update-MgPolicyAuthorizationPolicy RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 index 9f2d1a96dfde..d437a3780e50 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardDisableUserSiteCreate { CAT SharePoint Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgAdminSharepointSetting + Update-MgAdminSharePointSetting RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 index c44565c5b519..b09e560e43c9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardDisableViva { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2022-05-25 POWERSHELLEQUIVALENT Set-UserBriefingConfig RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 index d52dd3afedd0..b892cf34202e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableVoice.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardDisableVoice { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2023-12-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 index 9c3ab1093e0f..b07f36a401af 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisablex509Certificate.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardDisablex509Certificate { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2023-12-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 index 8705dcd630cb..224b1e81963f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 @@ -13,17 +13,19 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { CAT Exchange Standards TAG - "highimpact" "CIS" "mdo_autoforwardingmode" "mdo_blockmailforward" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2024-07-26 POWERSHELLEQUIVALENT Set-HostedOutboundSpamFilterPolicy -AutoForwardingMode 'Off' RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 index dd64008cff74..e82f0032a277 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableAppConsentRequests.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardEnableAppConsentRequests { CAT Entra (AAD) Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT {"type":"AdminRolesMultiSelect","label":"App Consent Reviewer Roles","name":"standards.EnableAppConsentRequests.ReviewerRoles"} IMPACT Low Impact + ADDEDDATE + 2023-11-27 POWERSHELLEQUIVALENT Update-MgPolicyAdminConsentRequestPolicy RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 index 7434e8035e07..b64f8062db19 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableCustomerLockbox.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardEnableCustomerLockbox { CAT Global Standards TAG - "lowimpact" "CIS" "CustomerLockBoxEnabled" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-01-08 POWERSHELLEQUIVALENT Set-OrganizationConfig -CustomerLockBoxEnabled \$true RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 index d76014e535dc..88e68f9581c9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableFIDO2.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardEnableFIDO2 { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2022-12-08 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 index 4394cf0740cd..f7a90138c7f3 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableHardwareOAuth.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardEnableHardwareOAuth { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2023-12-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 index cdea9bd134b1..f872be29d6ef 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 @@ -1,78 +1,79 @@ -function Invoke-CIPPStandardEnableLitigationHold { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) EnableLitigationHold - .SYNOPSIS - (Label) Enable Litigation Hold for all users - .DESCRIPTION - (Helptext) Enables litigation hold for all UserMailboxes with a valid license. - (DocsDescription) Enables litigation hold for all UserMailboxes with a valid license. - .NOTES - CAT - Exchange Standards - TAG - "lowimpact" - ADDEDCOMPONENT - IMPACT - Low Impact - POWERSHELLEQUIVALENT - Set-Mailbox -LitigationHoldEnabled \$true - 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/exchange-standards#low-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'EnableLitigationHold' - - $MailboxesNoLitHold = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdparams @{ Filter = 'LitigationHoldEnabled -eq "False"' } | Where-Object { $_.PersistedCapabilities -contains 'BPOS_S_DlpAddOn' -or $_.PersistedCapabilities -contains 'BPOS_S_Enterprise' } - - If ($Settings.remediate -eq $true) { - - if ($null -eq $MailboxesNoLitHold) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Litigation Hold already enabled for all accounts' -sev Info - } else { - try { - $Request = $MailboxesNoLitHold | ForEach-Object { - @{ - CmdletInput = @{ - CmdletName = 'Set-Mailbox' - Parameters = @{ Identity = $_.UserPrincipalName; LitigationHoldEnabled = $true } - } - } - } - - $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) - $BatchResults | ForEach-Object { - if ($_.error) { - $ErrorMessage = Get-NormalizedError -Message $_.error - Write-Host "Failed to Enable Litigation Hold for $($_.Target). Error: $ErrorMessage" - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to Enable Litigation Hold for $($_.Target). Error: $ErrorMessage" -sev Error - } - } - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to Enable Litigation Hold for all accounts. Error: $ErrorMessage" -sev Error - } - } - - } - - if ($Settings.alert -eq $true) { - - if ($MailboxesNoLitHold) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Mailboxes without Litigation Hold: $($MailboxesNoLitHold.Count)" -sev Alert - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'All mailboxes have Litigation Hold enabled' -sev Info - } - } - - if ($Settings.report -eq $true) { - $filtered = $MailboxesNoLitHold | Select-Object -Property UserPrincipalName - Add-CIPPBPAField -FieldName 'EnableLitHold' -FieldValue $filtered -StoreAs json -Tenant $Tenant - } -} +function Invoke-CIPPStandardEnableLitigationHold { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) EnableLitigationHold + .SYNOPSIS + (Label) Enable Litigation Hold for all users + .DESCRIPTION + (Helptext) Enables litigation hold for all UserMailboxes with a valid license. + (DocsDescription) Enables litigation hold for all UserMailboxes with a valid license. + .NOTES + CAT + Exchange Standards + TAG + ADDEDCOMPONENT + IMPACT + Low Impact + ADDEDDATE + 2024-06-25 + POWERSHELLEQUIVALENT + Set-Mailbox -LitigationHoldEnabled \$true + 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/exchange-standards#low-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'EnableLitigationHold' + + $MailboxesNoLitHold = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-Mailbox' -cmdparams @{ Filter = 'LitigationHoldEnabled -eq "False"' } | Where-Object { $_.PersistedCapabilities -contains 'BPOS_S_DlpAddOn' -or $_.PersistedCapabilities -contains 'BPOS_S_Enterprise' } + + If ($Settings.remediate -eq $true) { + + if ($null -eq $MailboxesNoLitHold) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Litigation Hold already enabled for all accounts' -sev Info + } else { + try { + $Request = $MailboxesNoLitHold | ForEach-Object { + @{ + CmdletInput = @{ + CmdletName = 'Set-Mailbox' + Parameters = @{ Identity = $_.UserPrincipalName; LitigationHoldEnabled = $true } + } + } + } + + $BatchResults = New-ExoBulkRequest -tenantid $tenant -cmdletArray @($Request) + $BatchResults | ForEach-Object { + if ($_.error) { + $ErrorMessage = Get-NormalizedError -Message $_.error + Write-Host "Failed to Enable Litigation Hold for $($_.Target). Error: $ErrorMessage" + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to Enable Litigation Hold for $($_.Target). Error: $ErrorMessage" -sev Error + } + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to Enable Litigation Hold for all accounts. Error: $ErrorMessage" -sev Error + } + } + + } + + if ($Settings.alert -eq $true) { + + if ($MailboxesNoLitHold) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Mailboxes without Litigation Hold: $($MailboxesNoLitHold.Count)" -sev Alert + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'All mailboxes have Litigation Hold enabled' -sev Info + } + } + + if ($Settings.report -eq $true) { + $filtered = $MailboxesNoLitHold | Select-Object -Property UserPrincipalName + Add-CIPPBPAField -FieldName 'EnableLitHold' -FieldValue $filtered -StoreAs json -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 index e5211d2eda92..f7fa667ef7e5 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 @@ -13,17 +13,19 @@ function Invoke-CIPPStandardEnableMailTips { CAT Exchange Standards TAG - "lowimpact" "CIS" "exo_mailtipsenabled" ADDEDCOMPONENT - {"type":"number","name":"standards.EnableMailTips.MailTipsLargeAudienceThreshold","label":"Number of recipients to trigger the large audience MailTip (Default is 25)","placeholder":"Enter a profile name","default":25} + {"type":"number","name":"standards.EnableMailTips.MailTipsLargeAudienceThreshold","label":"Number of recipients to trigger the large audience MailTip (Default is 25)","placeholder":"Enter a profile name","defaultValue":25} IMPACT Low Impact + ADDEDDATE + 2024-01-14 POWERSHELLEQUIVALENT Set-OrganizationConfig RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 index dac3185d381a..e65bd27e986b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardEnableMailboxAuditing { CAT Exchange Standards TAG - "lowimpact" "CIS" "exo_mailboxaudit" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-01-08 POWERSHELLEQUIVALENT Set-OrganizationConfig -AuditDisabled \$false RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 index 9a28cea18c9c..32d76c87d284 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardEnableOnlineArchiving { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-01-20 POWERSHELLEQUIVALENT Enable-Mailbox -Archive \$true RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 index fda0d9fa90b0..1023eecb109e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEnablePronouns.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardEnablePronouns { CAT Global Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-06-05 POWERSHELLEQUIVALENT Update-MgBetaAdminPeoplePronoun -IsEnabledInOrganization:\$true RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 index f28b6984c1c9..93fcf7958b3e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 @@ -13,13 +13,14 @@ function Invoke-CIPPStandardExcludedfileExt { CAT SharePoint Standards TAG - "highimpact" ADDEDCOMPONENT {"type":"textField","name":"standards.ExcludedfileExt.ext","label":"Extensions, Comma separated"} IMPACT High Impact + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgAdminSharepointSetting + Update-MgAdminSharePointSetting RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 index 95f28b7c2cd9..6aa494364001 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardExternalMFATrusted { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.ExternalMFATrusted.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"label":"Select value","name":"standards.ExternalMFATrusted.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Low Impact + ADDEDDATE + 2024-03-26 POWERSHELLEQUIVALENT Update-MgBetaPolicyCrossTenantAccessPolicyDefault RECOMMENDEDBY @@ -31,17 +32,20 @@ function Invoke-CIPPStandardExternalMFATrusted { ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'ExternalMFATrusted' $ExternalMFATrusted = (New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default?$select=inboundTrust' -tenantid $Tenant) - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + $WantedState = if ($state -eq 'true') { $true } else { $false } $StateMessage = if ($WantedState) { 'enabled' } else { 'disabled' } if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'ExternalMFATrusted' -FieldValue $ExternalMFATrusted.inboundTrust.isMfaAccepted -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'ExternalMFATrusted' -FieldValue $ExternalMFATrusted.inboundTrust.isMfaAccepted -StoreAs bool -Tenant $Tenant } # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error Return } @@ -49,17 +53,17 @@ function Invoke-CIPPStandardExternalMFATrusted { Write-Host 'Remediate External MFA Trusted' if ($ExternalMFATrusted.inboundTrust.isMfaAccepted -eq $WantedState ) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "External MFA Trusted is already $StateMessage." -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "External MFA Trusted is already $StateMessage." -sev Info } else { try { $NewBody = $ExternalMFATrusted $NewBody.inboundTrust.isMfaAccepted = $WantedState $NewBody = ConvertTo-Json -Depth 10 -InputObject $NewBody -Compress - $null = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default' -Type patch -Body $NewBody -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set External MFA Trusted to $StateMessage." -sev Info + $null = New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default' -Type patch -Body $NewBody -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set External MFA Trusted to $StateMessage." -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set External MFA Trusted to $StateMessage. Error: $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set External MFA Trusted to $StateMessage. Error: $ErrorMessage" -sev Error } } } @@ -67,9 +71,9 @@ function Invoke-CIPPStandardExternalMFATrusted { if ($Settings.alert -eq $true) { if ($ExternalMFATrusted.inboundTrust.isMfaAccepted -eq $WantedState) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "External MFA Trusted is $StateMessage." -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "External MFA Trusted is $StateMessage." -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "External MFA Trusted is not $StateMessage." -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "External MFA Trusted is not $StateMessage." -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index adface2383c8..34aa1a51fe1d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardFocusedInbox { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.FocusedInbox.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"autoComplete","multiple":false,"label":"Select value","name":"standards.FocusedInbox.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact + ADDEDDATE + 2024-04-26 POWERSHELLEQUIVALENT Set-OrganizationConfig -FocusedInboxOn \$true or \$false RECOMMENDEDBY @@ -30,29 +31,32 @@ function Invoke-CIPPStandardFocusedInbox { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'FocusedInbox' + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + # Input validation - if ([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') { + if ([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'ExternalMFATrusted: Invalid state parameter set' -sev Error Return } $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').FocusedInboxOn - $WantedState = if ($Settings.state -eq 'enabled') { $true } else { $false } + $WantedState = if ($state -eq 'enabled') { $true } else { $false } $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Focused Inbox is already set to $($Settings.state)." -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Focused Inbox is already set to $state." -sev Info } else { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdparams @{ FocusedInboxOn = $WantedState } - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Focused Inbox state to $($Settings.state)." -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ FocusedInboxOn = $WantedState } + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Focused Inbox state to $state." -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Focused Inbox state to $($Settings.state). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Focused Inbox state to $state. Error: $($ErrorMessage.NormalizedError)" -sev Error } } } @@ -60,13 +64,13 @@ function Invoke-CIPPStandardFocusedInbox { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Focused Inbox is set to $($Settings.state)." -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Focused Inbox is set to $state." -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Focused Inbox is not set to $($Settings.state)." -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Focused Inbox is not set to $state." -sev Alert } } if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'FocusedInboxCorrectState' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'FocusedInboxCorrectState' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 index 8b1fd25e48b3..1e973ef9daeb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT - {"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"}]} + {"type":"autoComplete","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 + ADDEDDATE + 2024-05-03 POWERSHELLEQUIVALENT Set-QuarantinePolicy -EndUserSpamNotificationFrequency RECOMMENDEDBY @@ -44,29 +45,32 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'GlobalQuarantineNotificationsSet' -FieldValue [string]$CurrentState.EndUserSpamNotificationFrequency -StoreAs string -Tenant $tenant + Add-CIPPBPAField -FieldName 'GlobalQuarantineNotificationsSet' -FieldValue [string]$CurrentState.EndUserSpamNotificationFrequency -StoreAs string -Tenant $Tenant } + # Get notification interval using null-coalescing operator + $NotificationInterval = $Settings.NotificationInterval.value ?? $Settings.NotificationInterval + # Input validation try { - $WantedState = [timespan]$Settings.NotificationInterval + $WantedState = [timespan]$NotificationInterval } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Invalid state selected for Global Quarantine Notifications. Error: $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message "GlobalQuarantineNotifications: Invalid NotificationInterval parameter set. Error: $ErrorMessage" -sev Error Return } if ($Settings.remediate -eq $true) { - Write-Host 'Time to remediate' + if ($CurrentState.EndUserSpamNotificationFrequency -eq $WantedState) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Global Quarantine Notifications are already set to the desired value of $WantedState" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Global Quarantine Notifications are already set to the desired value of $WantedState" -sev Info } else { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-QuarantinePolicy' -cmdParams @{Identity = $CurrentState.Identity; EndUserSpamNotificationFrequency = [string]$WantedState } -useSystemmailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set Global Quarantine Notifications to $WantedState" -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-QuarantinePolicy' -cmdParams @{Identity = $CurrentState.Identity; EndUserSpamNotificationFrequency = [string]$WantedState } -useSystemmailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Global Quarantine Notifications to $WantedState" -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set Global Quarantine Notifications to $WantedState. Error: $ErrorMessage" -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Global Quarantine Notifications to $WantedState. Error: $ErrorMessage" -sev Error } } } @@ -74,9 +78,9 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { if ($Settings.alert -eq $true) { if ($CurrentState.EndUserSpamNotificationFrequency -eq $WantedState) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Global Quarantine Notifications are set to the desired value of $WantedState" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Global Quarantine Notifications are set to the desired value of $WantedState" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Global Quarantine Notifications are not set to the desired value of $WantedState" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Global Quarantine Notifications are not set to the desired value of $WantedState" -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 index cee0f39dc6e3..c36603c329b4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 @@ -15,9 +15,11 @@ function Invoke-CIPPStandardGroupTemplate { CAT Templates DISABLEDFEATURES - + IMPACT - Medium + Medium Impact + ADDEDDATE + 2023-12-30 ADDEDCOMPONENT {"type":"autoComplete","name":"groupTemplate","label":"Select Group Template","api":{"url":"/api/ListGroupTemplates","labelField":"Displayname","valueField":"GUID","queryKey":"ListGroupTemplates"}} UPDATECOMMENTBLOCK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 index 5193b69708fb..4119652649a9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardGuestInvite.ps1 @@ -1,70 +1,78 @@ -function Invoke-CIPPStandardGuestInvite { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) GuestInvite - .SYNOPSIS - (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 - Entra (AAD) Standards - TAG - "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 - 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/list-standards/entra-aad-standards#medium-impact - #> - - param($Tenant, $Settings) - - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -tenantid $Tenant - - $StateIsCorrect = ($CurrentState.allowInvitesFrom -eq $Settings.allowInvitesFrom.value) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Guest Invite settings is already applied correctly.' -Sev Info - } else { - try { - $GraphRequest = @{ - tenantID = $Tenant - uri = "https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy" - AsApp = $false - Type = 'PATCH' - ContentType = 'application/json; charset=utf-8' - Body = [pscustomobject]@{ - allowInvitesFrom = $Settings.allowInvitesFrom.value - } | ConvertTo-Json -Compress - } - New-GraphPostRequest @GraphRequest - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Successfully updated Guest Invite setting to $($Settings.allowInvitesFrom.value)" -Sev Info - } catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update Guest Invite setting to $($Settings.allowInvitesFrom.value)" -Sev Error -LogData $_ - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Guest Invite settings is enabled.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Guest Invite settings is not enabled.' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'GuestInvite' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } -} +function Invoke-CIPPStandardGuestInvite { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) GuestInvite + .SYNOPSIS + (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 + Entra (AAD) Standards + TAG + ADDEDCOMPONENT + {"type":"autoComplete","required":true,"multiple":false,"creatable":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 + Medium Impact + ADDEDDATE + 2024-11-12 + POWERSHELLEQUIVALENT + + 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#medium-impact + #> + + param($Tenant, $Settings) + + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -tenantid $Tenant + + # Input validation and value handling + $AllowInvitesFromValue = $Settings.allowInvitesFrom.value ?? $Settings.allowInvitesFrom + if (([string]::IsNullOrWhiteSpace($AllowInvitesFromValue) -or $AllowInvitesFromValue -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'GuestInvite: Invalid allowInvitesFrom parameter set' -sev Error + Return + } + + $StateIsCorrect = ($CurrentState.allowInvitesFrom -eq $AllowInvitesFromValue) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Guest Invite settings is already applied correctly.' -Sev Info + } else { + try { + $GraphRequest = @{ + tenantID = $Tenant + uri = 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' + AsApp = $false + Type = 'PATCH' + ContentType = 'application/json; charset=utf-8' + Body = [pscustomobject]@{ + allowInvitesFrom = $AllowInvitesFromValue + } | ConvertTo-Json -Compress + } + New-GraphPostRequest @GraphRequest + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Successfully updated Guest Invite setting to $AllowInvitesFromValue" -Sev Info + } catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update Guest Invite setting to $AllowInvitesFromValue" -Sev Error -LogData $_ + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Guest Invite settings is enabled.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Guest Invite settings is not enabled.' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'GuestInvite' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 index d8ca6d499c9f..9342c223041d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 @@ -1,76 +1,79 @@ -function Invoke-CIPPStandardIntuneComplianceSettings { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) IntuneComplianceSettings - .SYNOPSIS - (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 - 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/list-standards/intune-standards#low-impact - #> - - param($Tenant, $Settings) - - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/settings' -tenantid $Tenant - - if ($null -eq $Settings.deviceComplianceCheckinThresholdDays) { $Settings.deviceComplianceCheckinThresholdDays = $CurrentState.deviceComplianceCheckinThresholdDays } - $StateIsCorrect = ($CurrentState.secureByDefault -eq $Settings.secureByDefault.value) -and - ($CurrentState.deviceComplianceCheckinThresholdDays -eq $Settings.deviceComplianceCheckinThresholdDays) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'InTune Compliance settings is already applied correctly.' -Sev Info - } else { - try { - $GraphRequest = @{ - tenantID = $Tenant - uri = "https://graph.microsoft.com/beta/deviceManagement" - AsApp = $true - Type = 'PATCH' - ContentType = 'application/json; charset=utf-8' - Body = [pscustomobject]@{ - settings = [pscustomobject]@{ - secureByDefault = $Settings.secureByDefault.value - deviceComplianceCheckinThresholdDays = $Settings.deviceComplianceCheckinThresholdDays - } - } | ConvertTo-Json -Compress - } - New-GraphPostRequest @GraphRequest - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully updated InTune Compliance settings.' -Sev Info - } catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to update InTune Compliance settings." -Sev Error -LogData $_ - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'InTune Compliance settings is enabled.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'InTune Compliance settings is not enabled.' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'IntuneComplianceSettings' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } -} +function Invoke-CIPPStandardIntuneComplianceSettings { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) IntuneComplianceSettings + .SYNOPSIS + (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 + TAG + ADDEDCOMPONENT + {"type":"autoComplete","required":true,"multiple":false,"creatable":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 + ADDEDDATE + 2024-11-12 + POWERSHELLEQUIVALENT + + 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/intune-standards#low-impact + #> + + param($Tenant, $Settings) + + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/settings' -tenantid $Tenant + + if ($null -eq $Settings.deviceComplianceCheckinThresholdDays) { $Settings.deviceComplianceCheckinThresholdDays = $CurrentState.deviceComplianceCheckinThresholdDays } + $SecureByDefault = $Settings.secureByDefault.value ?? $Settings.secureByDefault + $StateIsCorrect = ($CurrentState.secureByDefault -eq $SecureByDefault) -and + ($CurrentState.deviceComplianceCheckinThresholdDays -eq $Settings.deviceComplianceCheckinThresholdDays) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'InTune Compliance settings is already applied correctly.' -Sev Info + } else { + try { + $GraphRequest = @{ + tenantID = $Tenant + uri = 'https://graph.microsoft.com/beta/deviceManagement' + AsApp = $true + Type = 'PATCH' + ContentType = 'application/json; charset=utf-8' + Body = [pscustomobject]@{ + settings = [pscustomobject]@{ + secureByDefault = $SecureByDefault + deviceComplianceCheckinThresholdDays = $Settings.deviceComplianceCheckinThresholdDays + } + } | ConvertTo-Json -Compress + } + New-GraphPostRequest @GraphRequest + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully updated InTune Compliance settings.' -Sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Failed to update InTune Compliance settings.' -Sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'InTune Compliance settings is enabled.' -Sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'InTune Compliance settings is not enabled.' -Sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'IntuneComplianceSettings' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 index 68a437bd4bc4..a5fe3e775c3e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardIntuneTemplate.ps1 @@ -17,11 +17,14 @@ function Invoke-CIPPStandardIntuneTemplate { DISABLEDFEATURES IMPACT - High + High Impact + ADDEDDATE + 2023-12-30 ADDEDCOMPONENT - {"type":"autoComplete","multiple":false,"name":"TemplateList","label":"Select Intune Template","api":{"url":"/api/ListIntuneTemplates","labelField":"Displayname","valueField":"GUID","queryKey":"languages"}} + {"type":"autoComplete","multiple":false,"creatable":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."} + {"name":"ExcludeGroup","label":"Exclude Groups","type":"textField","required":false,"helpText":"Enter the group name to exclude from the assignment. Wildcards are allowed."} UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK @@ -34,7 +37,6 @@ function Invoke-CIPPStandardIntuneTemplate { Write-Host 'starting template deploy' Write-Host "The full settings are $($Settings | ConvertTo-Json)" - $APINAME = 'Standards' foreach ($Template in $Settings) { Write-Host "working on template deploy: $($Template | ConvertTo-Json)" try { @@ -46,11 +48,11 @@ function Invoke-CIPPStandardIntuneTemplate { $description = $request.body.Description $RawJSON = $Request.body.RawJSON $Template.customGroup ? ($Template.AssignTo = $Template.customGroup) : $null - Set-CIPPIntunePolicy -TemplateType $Request.body.Type -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $Template.AssignTo -tenantFilter $Tenant + Set-CIPPIntunePolicy -TemplateType $Request.body.Type -Description $description -DisplayName $displayname -RawJSON $RawJSON -AssignTo $Template.AssignTo -ExcludeGroup $Template.excludeGroup -tenantFilter $Tenant } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template $PolicyName, Error: $ErrorMessage" -sev 'Error' + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to create or update Intune Template $displayname, Error: $ErrorMessage" -sev 'Error' } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 index 018cc262c0ef..94409b104bbb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardLegacyMFACleanup.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardLegacyMFACleanup { CAT Entra (AAD) Standards TAG - "mediumimpact" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Set-MsolUser -StrongAuthenticationRequirements \$null RECOMMENDEDBY @@ -28,5 +29,6 @@ function Invoke-CIPPStandardLegacyMFACleanup { param($Tenant, $Settings) Write-LogMessage -API 'Standards' -tenant $tenant -message 'Per User MFA APIs have been disabled.' -sev Info + # TODO - Re-implement this standard } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 new file mode 100644 index 000000000000..c778a17d4d7b --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 @@ -0,0 +1,126 @@ +function Invoke-CIPPStandardMDMScope { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) MDMScope + .SYNOPSIS + (Label) Configure MDM user scope + .DESCRIPTION + (Helptext) Configures the MDM user scope. This also sets the terms of use, discovery and compliance URL to default URLs. + (DocsDescription) Configures the MDM user scope. This also sets the terms of use URL, discovery URL and compliance URL to default values. + .NOTES + CAT + Intune Standards + TAG + ADDEDCOMPONENT + {"name":"appliesTo","label":"MDM User Scope?","type":"radio","options":[{"label":"All","value":"all"},{"label":"None","value":"none"},{"label":"Custom Group","value":"selected"}]} + {"type":"textField","name":"standards.MDMScope.customGroup","label":"Custom Group Name","required":false} + IMPACT + Low Impact + ADDEDDATE + 2025-02-18 + POWERSHELLEQUIVALENT + 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/intune-standards#low-impact + #> + + param($Tenant, $Settings) + + $CurrentInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/mobileDeviceManagementPolicies/0000000a-0000-0000-c000-000000000000?$expand=includedGroups' -tenantid $Tenant + + $StateIsCorrect = ($CurrentInfo.termsOfUseUrl -eq 'https://portal.manage.microsoft.com/TermsofUse.aspx') -and + ($CurrentInfo.discoveryUrl -eq 'https://enrollment.manage.microsoft.com/enrollmentserver/discovery.svc') -and + ($CurrentInfo.complianceUrl -eq 'https://portal.manage.microsoft.com/?portalAction=Compliance') -and + ($CurrentInfo.appliesTo -eq $Settings.appliesTo) -and + ($Settings.appliesTo -ne 'selected' -or ($CurrentInfo.includedGroups.displayName -contains $Settings.customGroup)) + + If ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'MDM Scope already correctly configured' -sev Info + } else { + $GraphParam = @{ + tenantid = $tenant + Uri = 'https://graph.microsoft.com/beta/policies/mobileDeviceManagementPolicies/0000000a-0000-0000-c000-000000000000' + ContentType = 'application/json; charset=utf-8' + asApp = $false + type = 'PATCH' + AddedHeaders = @{'Accept-Language' = 0 } + Body = @{ + 'termsOfUseUrl' = 'https://portal.manage.microsoft.com/TermsofUse.aspx' + 'discoveryUrl' = 'https://enrollment.manage.microsoft.com/enrollmentserver/discovery.svc' + 'complianceUrl' = 'https://portal.manage.microsoft.com/?portalAction=Compliance' + } | ConvertTo-Json + } + + try { + New-GraphPostRequest @GraphParam + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully configured MDM Scope' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to configure MDM Scope." -sev Error -LogData $ErrorMessage + } + + # Workaround for MDM Scope Assignment error: "Could not set MDM Scope for [TENANT]: Simultaneous patch requests on both the appliesTo and URL properties are currently not supported." + if ($Settings.appliesTo -ne 'selected') { + $GraphParam = @{ + tenantid = $tenant + Uri = 'https://graph.microsoft.com/beta/policies/mobileDeviceManagementPolicies/0000000a-0000-0000-c000-000000000000' + ContentType = 'application/json; charset=utf-8' + asApp = $false + type = 'PATCH' + AddedHeaders = @{'Accept-Language' = 0 } + Body = @{ + 'appliesTo' = $Settings.appliesTo + } | ConvertTo-Json + } + + try { + New-GraphPostRequest @GraphParam + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully assigned $($Settings.appliesTo) to MDM Scope" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to assign $($Settings.appliesTo) to MDM Scope." -sev Error -LogData $ErrorMessage + } + } else { + $GroupID = (New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/groups?`$top=999&`$select=id,displayName&`$filter=displayName eq '$($Settings.customGroup)'" -tenantid $tenant -asApp $true).id + $GraphParam = @{ + tenantid = $tenant + Uri = 'https://graph.microsoft.com/beta/policies/mobileDeviceManagementPolicies/0000000a-0000-0000-c000-000000000000/includedGroups/$ref' + ContentType = 'application/json; charset=utf-8' + asApp = $false + type = 'POST' + AddedHeaders = @{'Accept-Language' = 0 } + Body = @{ + '@odata.id' = "https://graph.microsoft.com/odata/groups('$GroupID')" + } | ConvertTo-Json + } + + try { + New-GraphPostRequest @GraphParam + Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully assigned $($Settings.customGroup) to MDM Scope" -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to assign $($Settings.customGroup) to MDM Scope" -sev Error -LogData $ErrorMessage + } + } + } + } + + if ($Settings.alert -eq $true -eq $true) { + if ($StateIsCorrect) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'MDM Scope is correctly configured' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'MDM Scope is not correctly configured' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'MDMScope' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 index 28ad1f65a291..bdff96e5f284 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 @@ -13,7 +13,6 @@ function Invoke-CIPPStandardMailContacts { CAT Global Standards TAG - "lowimpact" ADDEDCOMPONENT {"type":"textField","name":"standards.MailContacts.GeneralContact","label":"General Contact","required":false} {"type":"textField","name":"standards.MailContacts.SecurityContact","label":"Security Contact","required":false} @@ -21,6 +20,8 @@ function Invoke-CIPPStandardMailContacts { {"type":"textField","name":"standards.MailContacts.TechContact","label":"Technical Contact","required":false} IMPACT Low Impact + ADDEDDATE + 2022-03-13 POWERSHELLEQUIVALENT Set-MsolCompanyContactInformation RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index e34a7124f8e5..0ef4dda2994a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -1,172 +1,173 @@ -function Invoke-CIPPStandardMalwareFilterPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) MalwareFilterPolicy - .SYNOPSIS - (Label) Default Malware Filter Policy - .DESCRIPTION - (Helptext) This creates a Malware filter policy that enables the default File filter and Zero-hour auto purge for malware. - (DocsDescription) This creates a Malware filter policy that enables the default File filter and Zero-hour auto purge for malware. - .NOTES - CAT - Defender Standards - TAG - "lowimpact" - "CIS" - "mdo_zapspam" - "mdo_zapphish" - "mdo_zapmalware" - ADDEDCOMPONENT - {"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 - Set-MalwareFilterPolicy or New-MalwareFilterPolicy - RECOMMENDEDBY - "CIS" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'MalwareFilterPolicy' - - $PolicyList = @('CIPP Default Malware Policy','Default Malware Policy') - $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterPolicy' | Where-Object -Property Name -In $PolicyList - if ($null -eq $ExistingPolicy.Name) { - $PolicyName = $PolicyList[0] - } else { - $PolicyName = $ExistingPolicy.Name - } - $RuleList = @( 'CIPP Default Malware Rule','CIPP Default Malware Policy') - $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterRule' | Where-Object -Property Name -In $RuleList - if ($null -eq $ExistingRule.Name) { - $RuleName = $RuleList[0] - } else { - $RuleName = $ExistingRule.Name - } - - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterPolicy' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object Name, EnableFileFilter, FileTypeAction, FileTypes, ZapEnabled, QuarantineTag, EnableInternalSenderAdminNotifications, InternalSenderAdminAddress, EnableExternalSenderAdminNotifications, ExternalSenderAdminAddress - - $DefaultFileTypes = @('ace', 'ani', 'apk', 'app', 'appx', 'arj', 'bat', 'cab', 'cmd', 'com', 'deb', 'dex', 'dll', 'docm', 'elf', 'exe', 'hta', 'img', 'iso', 'jar', 'jnlp', 'kext', 'lha', 'lib', 'library', 'lnk', 'lzh', 'macho', 'msc', 'msi', 'msix', 'msp', 'mst', 'pif', 'ppa', 'ppam', 'reg', 'rev', 'scf', 'scr', 'sct', 'sys', 'uif', 'vb', 'vbe', 'vbs', 'vxd', 'wsc', 'wsf', 'wsh', 'xll', 'xz', 'z') - - if ($null -eq $Settings.OptionalFileTypes) { - $ExpectedFileTypes = $DefaultFileTypes - } else { - $ExpectedFileTypes = $DefaultFileTypes + @($Settings.OptionalFileTypes.Split(',').Trim()) - } - - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.EnableFileFilter -eq $true) -and - ($CurrentState.FileTypeAction -eq $Settings.FileTypeAction) -and - (!(Compare-Object -ReferenceObject $CurrentState.FileTypes -DifferenceObject $ExpectedFileTypes)) -and - ($CurrentState.ZapEnabled -eq $true) -and - ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and - ($CurrentState.EnableInternalSenderAdminNotifications -eq $Settings.EnableInternalSenderAdminNotifications) -and - (($null -eq $Settings.InternalSenderAdminAddress) -or ($CurrentState.InternalSenderAdminAddress -eq $Settings.InternalSenderAdminAddress)) -and - ($CurrentState.EnableExternalSenderAdminNotifications -eq $Settings.EnableExternalSenderAdminNotifications) -and - (($null -eq $Settings.ExternalSenderAdminAddress) -or ($CurrentState.ExternalSenderAdminAddress -eq $Settings.ExternalSenderAdminAddress)) - - $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' - - $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterRule' | - Where-Object -Property Name -EQ $RuleName | - Select-Object Name, MalwareFilterPolicy, Priority, RecipientDomainIs - - $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and - ($RuleState.MalwareFilterPolicy -eq $PolicyName) -and - ($RuleState.Priority -eq 0) -and - (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) - - if ($Settings.remediate -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Malware Filter Policy already correctly configured' -sev Info - } else { - $cmdparams = @{ - EnableFileFilter = $true - FileTypes = $ExpectedFileTypes - FileTypeAction = $Settings.FileTypeAction - ZapEnabled = $true - QuarantineTag = $Settings.QuarantineTag - EnableInternalSenderAdminNotifications = $Settings.EnableInternalSenderAdminNotifications - InternalSenderAdminAddress = $Settings.InternalSenderAdminAddress - EnableExternalSenderAdminNotifications = $Settings.EnableExternalSenderAdminNotifications - ExternalSenderAdminAddress = $Settings.ExternalSenderAdminAddress - } - - if ($CurrentState.Name -eq $PolicyName) { - try { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MalwareFilterPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Malware Filter policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Malware Filter policy $PolicyName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-MalwareFilterPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Malware Filter policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Malware Filter policy $PolicyName." -sev Error -LogData $_ - } - } - } - - if ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name - } - - if ($RuleState.MalwareFilterPolicy -ne $PolicyName) { - $cmdparams.Add('MalwareFilterPolicy', $PolicyName) - } - - if ($RuleState.Name -eq $RuleName) { - try { - $cmdparams.Add('Identity', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MalwareFilterRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Malware Filter rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Malware Filter Rule $RuleName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', $RuleName) - New-ExoRequest -tenantid $Tenant -cmdlet 'New-MalwareFilterRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Malware Filter rule $RuleName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Malware Filter rule $RuleName." -sev Error -LogData $_ - } - } - } - } - - if ($Settings.alert -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Malware Filter Policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Malware Filter Policy is not enabled' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'MalwareFilterPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } - -} +function Invoke-CIPPStandardMalwareFilterPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) MalwareFilterPolicy + .SYNOPSIS + (Label) Default Malware Filter Policy + .DESCRIPTION + (Helptext) This creates a Malware filter policy that enables the default File filter and Zero-hour auto purge for malware. + (DocsDescription) This creates a Malware filter policy that enables the default File filter and Zero-hour auto purge for malware. + .NOTES + CAT + Defender Standards + TAG + "CIS" + "mdo_zapspam" + "mdo_zapphish" + "mdo_zapmalware" + ADDEDCOMPONENT + {"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 + ADDEDDATE + 2024-03-25 + POWERSHELLEQUIVALENT + Set-MalwareFilterPolicy or New-MalwareFilterPolicy + RECOMMENDEDBY + "CIS" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/defender-standards#low-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'MalwareFilterPolicy' + + $PolicyList = @('CIPP Default Malware Policy','Default Malware Policy') + $ExistingPolicy = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterPolicy' | Where-Object -Property Name -In $PolicyList + if ($null -eq $ExistingPolicy.Name) { + $PolicyName = $PolicyList[0] + } else { + $PolicyName = $ExistingPolicy.Name + } + $RuleList = @( 'CIPP Default Malware Rule','CIPP Default Malware Policy') + $ExistingRule = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterRule' | Where-Object -Property Name -In $RuleList + if ($null -eq $ExistingRule.Name) { + $RuleName = $RuleList[0] + } else { + $RuleName = $ExistingRule.Name + } + + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterPolicy' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object Name, EnableFileFilter, FileTypeAction, FileTypes, ZapEnabled, QuarantineTag, EnableInternalSenderAdminNotifications, InternalSenderAdminAddress, EnableExternalSenderAdminNotifications, ExternalSenderAdminAddress + + $DefaultFileTypes = @('ace', 'ani', 'apk', 'app', 'appx', 'arj', 'bat', 'cab', 'cmd', 'com', 'deb', 'dex', 'dll', 'docm', 'elf', 'exe', 'hta', 'img', 'iso', 'jar', 'jnlp', 'kext', 'lha', 'lib', 'library', 'lnk', 'lzh', 'macho', 'msc', 'msi', 'msix', 'msp', 'mst', 'pif', 'ppa', 'ppam', 'reg', 'rev', 'scf', 'scr', 'sct', 'sys', 'uif', 'vb', 'vbe', 'vbs', 'vxd', 'wsc', 'wsf', 'wsh', 'xll', 'xz', 'z') + + if ($null -eq $Settings.OptionalFileTypes) { + $ExpectedFileTypes = $DefaultFileTypes + } else { + $ExpectedFileTypes = $DefaultFileTypes + @($Settings.OptionalFileTypes.Split(',').Trim()) + } + + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.EnableFileFilter -eq $true) -and + ($CurrentState.FileTypeAction -eq $Settings.FileTypeAction) -and + (!(Compare-Object -ReferenceObject $CurrentState.FileTypes -DifferenceObject $ExpectedFileTypes)) -and + ($CurrentState.ZapEnabled -eq $true) -and + ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and + ($CurrentState.EnableInternalSenderAdminNotifications -eq $Settings.EnableInternalSenderAdminNotifications) -and + (($null -eq $Settings.InternalSenderAdminAddress) -or ($CurrentState.InternalSenderAdminAddress -eq $Settings.InternalSenderAdminAddress)) -and + ($CurrentState.EnableExternalSenderAdminNotifications -eq $Settings.EnableExternalSenderAdminNotifications) -and + (($null -eq $Settings.ExternalSenderAdminAddress) -or ($CurrentState.ExternalSenderAdminAddress -eq $Settings.ExternalSenderAdminAddress)) + + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MalwareFilterRule' | + Where-Object -Property Name -EQ $RuleName | + Select-Object Name, MalwareFilterPolicy, Priority, RecipientDomainIs + + $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and + ($RuleState.MalwareFilterPolicy -eq $PolicyName) -and + ($RuleState.Priority -eq 0) -and + (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) + + if ($Settings.remediate -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Malware Filter Policy already correctly configured' -sev Info + } else { + $cmdparams = @{ + EnableFileFilter = $true + FileTypes = $ExpectedFileTypes + FileTypeAction = $Settings.FileTypeAction + ZapEnabled = $true + QuarantineTag = $Settings.QuarantineTag + EnableInternalSenderAdminNotifications = $Settings.EnableInternalSenderAdminNotifications + InternalSenderAdminAddress = $Settings.InternalSenderAdminAddress + EnableExternalSenderAdminNotifications = $Settings.EnableExternalSenderAdminNotifications + ExternalSenderAdminAddress = $Settings.ExternalSenderAdminAddress + } + + if ($CurrentState.Name -eq $PolicyName) { + try { + $cmdparams.Add('Identity', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MalwareFilterPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Malware Filter policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Malware Filter policy $PolicyName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $PolicyName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-MalwareFilterPolicy' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Malware Filter policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Malware Filter policy $PolicyName." -sev Error -LogData $_ + } + } + } + + if ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + if ($RuleState.MalwareFilterPolicy -ne $PolicyName) { + $cmdparams.Add('MalwareFilterPolicy', $PolicyName) + } + + if ($RuleState.Name -eq $RuleName) { + try { + $cmdparams.Add('Identity', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MalwareFilterRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Malware Filter rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Malware Filter Rule $RuleName." -sev Error -LogData $_ + } + } else { + try { + $cmdparams.Add('Name', $RuleName) + New-ExoRequest -tenantid $Tenant -cmdlet 'New-MalwareFilterRule' -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Malware Filter rule $RuleName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Malware Filter rule $RuleName." -sev Error -LogData $_ + } + } + } + } + + if ($Settings.alert -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Malware Filter Policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Malware Filter Policy is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'MalwareFilterPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 index 4126811842e8..22da3819e8f9 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardMessageExpiration { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-02-23 POWERSHELLEQUIVALENT Set-TransportConfig -MessageExpirationTimeout 12.00:00:00 RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 index b00f525d0fef..b97689a2f960 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardNudgeMFA.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardNudgeMFA { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT - {"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} + {"type":"autoComplete","multiple":false,"creatable":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)","defaultValue":1} IMPACT Low Impact + ADDEDDATE + 2022-12-08 POWERSHELLEQUIVALENT Update-MgPolicyAuthenticationMethodPolicy RECOMMENDEDBY @@ -31,63 +32,72 @@ function Invoke-CIPPStandardNudgeMFA { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'NudgeMFA' - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $Tenant - $StateIsCorrect = ($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq $Settings.state) -and + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + + try { + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $Tenant + $StateIsCorrect = ($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.state -eq $state) -and ($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays -eq $Settings.snoozeDurationInDays) -and ($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.enforceRegistrationAfterAllowedSnoozes -eq $true) + } catch { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Failed to get Authenticator App Nudge state, check your permissions and try again' -sev Error -LogData (Get-CippException -Exception $_) + Return + } if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'NudgeMFA' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'NudgeMFA' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant } - # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'NudgeMFA: Invalid state parameter set' -sev Error Return } # Input validation if (([Int32]$Settings.snoozeDurationInDays -lt 0 -or [Int32]$Settings.snoozeDurationInDays -gt 15) -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'NudgeMFA: Invalid snoozeDurationInDays parameter set' -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'NudgeMFA: Invalid snoozeDurationInDays parameter set' -sev Error Return } - - If ($Settings.remediate -eq $true) { + if ($Settings.remediate -eq $true) { $StateName = $Settings.state.Substring(0, 1).ToUpper() + $Settings.state.Substring(1) - if ($StatsIsCorrect -eq $false) { + if ($StateIsCorrect -eq $false) { try { $GraphRequest = @{ - tenantid = $tenant - uri = 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' - AsApp = $false - Type = 'PATCH' + tenantid = $Tenant + uri = 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' + AsApp = $false + Type = 'PATCH' ContentType = 'application/json' - Body = @{ + Body = @{ registrationEnforcement = @{ authenticationMethodsRegistrationCampaign = @{ - state = $Settings.state - snoozeDurationInDays = $Settings.snoozeDurationInDays + state = $state + snoozeDurationInDays = $Settings.snoozeDurationInDays enforceRegistrationAfterAllowedSnoozes = $true + includeTargets = $CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.includeTargets + excludeTargets = $CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.excludeTargets } } } | ConvertTo-Json -Depth 10 -Compress } New-GraphPostRequest @GraphRequest - Write-LogMessage -API 'Standards' -tenant $tenant -message "$StateName Authenticator App Nudge with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "$StateName Authenticator App Nudge with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info } catch { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set Authenticator App Nudge to $($Settings.state)" -sev Error -LogData $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Authenticator App Nudge to $state" -sev Error -LogData $_ } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Authenticator App Nudge is already set to $($Settings.state) with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Authenticator App Nudge is already set to $state with a snooze duration of $($Settings.snoozeDurationInDays)" -sev Info } } if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Authenticator App Nudge is enabled with a snooze duration of $($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Authenticator App Nudge is enabled with a snooze duration of $($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Authenticator App Nudge is not enabled with a snooze duration of $($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Authenticator App Nudge is not enabled with a snooze duration of $($CurrentState.registrationEnforcement.authenticationMethodsRegistrationCampaign.snoozeDurationInDays)" -sev Alert } } + } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 index 5df66cd46ca5..c1bdb39fa96b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsent.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardOauthConsent { CAT Entra (AAD) Standards TAG - "mediumimpact" "CIS" ADDEDCOMPONENT {"type":"textField","name":"standards.OauthConsent.AllowedApps","label":"Allowed application IDs, comma separated","required":false} IMPACT Medium Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Update-MgPolicyAuthorizationPolicy RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 index e43a57367058..da3d0063cdbb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOauthConsentLowSec.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardOauthConsentLowSec { CAT Entra (AAD) Standards TAG - "mediumimpact" "IntegratedApps" IMPACT Medium Impact + ADDEDDATE + 2022-08-16 POWERSHELLEQUIVALENT Update-MgPolicyAuthorizationPolicy RECOMMENDEDBY @@ -30,26 +31,66 @@ function Invoke-CIPPStandardOauthConsentLowSec { ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'OauthConsentLowSec' $State = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -tenantid $tenant) + $PermissionState = (New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/servicePrincipals(appId='00000003-0000-0000-c000-000000000000')/delegatedPermissionClassifications" -tenantid $tenant) | Select-Object -Property permissionName + + $requiredPermissions = @('offline_access', 'openid', 'User.Read', 'profile', 'email') + $missingPermissions = $requiredPermissions | Where-Object { $PermissionState.permissionName -notcontains $_ } + If ($Settings.remediate -eq $true) { - try { - if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('managePermissionGrantsForSelf.microsoft-user-default-low')) { - Write-Host 'Going to set' - New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' -Type PATCH -Body '{"permissionGrantPolicyIdsAssignedToDefaultUserRole":["managePermissionGrantsForSelf.microsoft-user-default-low"]}' -ContentType 'application/json' + if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -in @('managePermissionGrantsForSelf.microsoft-user-default-low')) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode(microsoft-user-default-low) is already enabled.' -sev Info + } else { + try { + $GraphParam = @{ + tenantid = $tenant + Uri = 'https://graph.microsoft.com/beta/policies/authorizationPolicy/authorizationPolicy' + Type = 'PATCH' + Body = @{ + permissionGrantPolicyIdsAssignedToDefaultUserRole = @('managePermissionGrantsForSelf.microsoft-user-default-low') + } | ConvertTo-Json + ContentType = 'application/json' + } + $null = New-GraphPostRequest @GraphParam + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode(microsoft-user-default-low) has been enabled.' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Application Consent Mode (microsoft-user-default-low) Error: $ErrorMessage" -sev Error + } + } + + if ($missingPermissions.Count -eq 0) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'All permissions for Application Consent already assigned.' -sev Info + } else { + try { + $missingPermissions | ForEach-Object { + $GraphParam = @{ + tenantid = $tenant + Uri = "https://graph.microsoft.com/beta/servicePrincipals(appId='00000003-0000-0000-c000-000000000000')/delegatedPermissionClassifications" + Type = 'POST' + Body = @{ + permissionName = $_ + classification = 'low' + } | ConvertTo-Json + ContentType = 'application/json' + } + $null = New-GraphPostRequest @GraphParam + Write-LogMessage -API 'Standards' -tenant $tenant -message "Permission $_ has been added to low Application Consent" -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply low consent permissions Error: $ErrorMessage" -sev Error } - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode(microsoft-user-default-low) has been enabled.' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to apply Application Consent Mode (microsoft-user-default-low) Error: $ErrorMessage" -sev Error } } - if ($Settings.alert -eq $true) { + if ($Settings.alert -eq $true) { if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('managePermissionGrantsForSelf.microsoft-user-default-low')) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode(microsoft-user-default-low) is not enabled.' -sev Alert } else { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Application Consent Mode(microsoft-user-default-low) is enabled.' -sev Info } } + if ($Settings.report -eq $true) { if ($State.permissionGrantPolicyIdsAssignedToDefaultUserRole -notin @('managePermissionGrantsForSelf.microsoft-user-default-low')) { $State.permissionGrantPolicyIdsAssignedToDefaultUserRole = $false diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 index 4c6230c0b28c..098a85d27f3e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardOutBoundSpamAlert { CAT Exchange Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT {"type":"textField","name":"standards.OutBoundSpamAlert.OutboundSpamContact","label":"Outbound spam contact"} IMPACT Low Impact + ADDEDDATE + 2023-05-03 POWERSHELLEQUIVALENT Set-HostedOutboundSpamFilterPolicy RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 index 4116d53897c6..f7efdc7d203c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWcompanionAppAllowedState.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.PWcompanionAppAllowedState.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"label":"Select value","name":"standards.PWcompanionAppAllowedState.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact + ADDEDDATE + 2023-05-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY @@ -30,30 +31,33 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'PWcompanionAppAllowedState' - $authenticatorFeaturesState = (New-GraphGetRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type GET) - $authstate = if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq 'enabled') { $true } else { $false } + $authenticatorFeaturesState = (New-GraphGetRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type GET) + $authState = if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq 'enabled') { $true } else { $false } if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'companionAppAllowedState' -FieldValue $authstate -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'companionAppAllowedState' -FieldValue $authState -StoreAs bool -Tenant $Tenant } + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'PWcompanionAppAllowedState: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'PWcompanionAppAllowedState: Invalid state parameter set' -sev Error Return } If ($Settings.remediate -eq $true) { - if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq $Settings.state) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "companionAppAllowedState is already set to the desired state of $($Settings.state)." -sev Info + if ($authenticatorFeaturesState.featureSettings.companionAppAllowedState.state -eq $state) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "companionAppAllowedState is already set to the desired state of $state." -sev Info } else { try { # Remove number matching from featureSettings because this is now Microsoft enforced and shipping it returns an error $authenticatorFeaturesState.featureSettings.PSObject.Properties.Remove('numberMatchingRequiredState') # Define feature body $featureBody = @{ - state = $Settings.state + state = $state includeTarget = [PSCustomObject]@{ targetType = 'group' id = 'all_users' @@ -65,21 +69,21 @@ function Invoke-CIPPStandardPWcompanionAppAllowedState { } $authenticatorFeaturesState.featureSettings.companionAppAllowedState = $featureBody $body = ConvertTo-Json -Depth 3 -Compress -InputObject $authenticatorFeaturesState - (New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type patch -Body $body -ContentType 'application/json') - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set companionAppAllowedState to $($Settings.state)." -sev Info + $null = (New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -Type patch -Body $body -ContentType 'application/json') + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set companionAppAllowedState to $state." -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set companionAppAllowedState to $($Settings.state). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippExceptionMessage -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set companionAppAllowedState to $state. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } } if ($Settings.alert -eq $true) { - if ($authstate) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'companionAppAllowedState is enabled.' -sev Info + if ($authState) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'companionAppAllowedState is enabled.' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'companionAppAllowedState is not enabled.' -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'companionAppAllowedState is not enabled.' -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 index 8ddea0115551..142732c5b0cf 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardPWdisplayAppInformationRequiredState { CAT Entra (AAD) Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY @@ -32,7 +33,9 @@ function Invoke-CIPPStandardPWdisplayAppInformationRequiredState { ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'PWdisplayAppInformationRequiredState' $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -tenantid $Tenant - $StateIsCorrect = ($CurrentState.state -eq 'enabled') + $StateIsCorrect = ($CurrentState.state -eq 'enabled') -and + ($CurrentState.featureSettings.numberMatchingRequiredState.state -eq 'enabled') -and + ($CurrentState.featureSettings.displayAppInformationRequiredState.state -eq 'enabled') If ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 index fd6d68613ace..f21def0d2784 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPasswordExpireDisabled.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardPasswordExpireDisabled { CAT Entra (AAD) Standards TAG - "lowimpact" "CIS" "PWAgePolicyNew" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT Update-MgDomain RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 index 21a802bc079c..8e028d5a4eaa 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPerUserMFA.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardPerUserMFA { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2024-06-14 POWERSHELLEQUIVALENT Graph API RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 index 4cd025548e72..d250edcd3b66 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardPhishProtection { CAT Global Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2024-01-22 DISABLEDFEATURES POWERSHELLEQUIVALENT diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 index 1c0472b3749b..9b8db4155929 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 @@ -1,4 +1,4 @@ -function Invoke-CIPPStandardProfilePhotos { +function Invoke-CIPPStandardProfilePhotos { <# .FUNCTIONALITY Internal @@ -7,33 +7,40 @@ .SYNOPSIS (Label) Allow users to set profile photos .DESCRIPTION - (Helptext) Controls whether users can set their own profile photos in Microsoft 365 + (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"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"label":"Select value","name":"standards.ProfilePhotos.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact + ADDEDDATE + 2025-01-19 POWERSHELLEQUIVALENT Set-OrganizationConfig -ProfilePhotoOptions EnablePhotos and Update-MgBetaAdminPeople + 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/global-standards#low-impact #> param($Tenant, $Settings) + # Get state value using null-coalescing operator + $StateValue = $Settings.state.value ?? $Settings.state + # Input validation - if ([string]::IsNullOrWhiteSpace($Settings.state)) { + if ([string]::IsNullOrWhiteSpace($StateValue)) { 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' + $DesiredState = $StateValue -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. @@ -61,12 +68,12 @@ if ($CurrentStatesCorrect -eq $false) { Write-Host 'Settings are not correct' try { - if ($Settings.state -eq 'enabled') { + if ($StateValue -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 + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Profile photo settings to $StateValue" -sev Info } else { Write-Host 'Disabling' @@ -82,23 +89,23 @@ # } # $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 + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set Profile photo settings to $StateValue" -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 + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set profile photo settings to $StateValue. 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 + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings are already set to the desired state: $StateValue" -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 + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings do not match desired state: $StateValue" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings match desired state: $($Settings.state)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Profile photo settings match desired state: $StateValue" -sev Alert } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 index 3040ef1f155e..84a5376bb816 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 @@ -1,91 +1,89 @@ -function Invoke-CIPPStandardQuarantineRequestAlert { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) QuarantineRequestAlert - .SYNOPSIS - (Label) Quarantine Release Request Alert - .DESCRIPTION - (Helptext) Sets a e-mail address to alert when a User requests to release a quarantined message. - (DocsDescription) Sets a e-mail address to alert when a User requests to release a quarantined message. This is useful for monitoring and ensuring that the correct messages are released. - .NOTES - CAT - Defender Standards - TAG - "lowimpact" - ADDEDCOMPONENT - {"type":"textField","name":"standards.QuarantineRequestAlert.NotifyUser","label":"E-mail to receive the alert"} - IMPACT - Low Impact - POWERSHELLEQUIVALENT - New-ProtectionAlert and Set-ProtectionAlert - 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/defender-standards#low-impact - #> - - param ($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'QuarantineRequestAlert' - - $PolicyName = 'CIPP User requested to release a quarantined message' - - $CurrentState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-ProtectionAlert' -Compliance | - Where-Object { $_.Name -eq $PolicyName } | - Select-Object -Property * - - $StateIsCorrect = ($CurrentState.NotifyUser -contains $Settings.NotifyUser) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Quarantine Request Alert is configured correctly' -sev Info - } else { - $cmdparams = @{ - 'NotifyUser' = $Settings.NotifyUser - 'Category' = 'ThreatManagement' - 'Operation' = 'QuarantineRequestReleaseMessage' - 'Severity' = 'Informational' - 'AggregationType' = 'None' - } - - if ($CurrentState.Name -eq $PolicyName) { - try { - $cmdparams += @{ - 'Identity' = $PolicyName - } - New-ExoRequest -TenantId $Tenant -cmdlet 'Set-ProtectionAlert' -Compliance -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully configured Quarantine Request Alert' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to configure Quarantine Request Alert. Error: $ErrorMessage" -sev Error - } - } else { - try { - $cmdparams += @{ - 'Name' = $PolicyName - 'ThreatType' = 'Activity' - } - New-ExoRequest -TenantId $Tenant -cmdlet 'New-ProtectionAlert' -Compliance -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully created Quarantine Request Alert' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to create Quarantine Request Alert. Error: $ErrorMessage" -sev Error - } - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Quarantine Request Alert is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Quarantine Request Alert is disabled' -sev Info - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'QuarantineRequestAlert' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +function Invoke-CIPPStandardQuarantineRequestAlert { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) QuarantineRequestAlert + .SYNOPSIS + (Label) Quarantine Release Request Alert + .DESCRIPTION + (Helptext) Sets a e-mail address to alert when a User requests to release a quarantined message. + (DocsDescription) Sets a e-mail address to alert when a User requests to release a quarantined message. This is useful for monitoring and ensuring that the correct messages are released. + .NOTES + CAT + Defender Standards + TAG + ADDEDCOMPONENT + {"type":"textField","name":"standards.QuarantineRequestAlert.NotifyUser","label":"E-mail to receive the alert"} + IMPACT + Low Impact + ADDEDDATE + 2024-07-15 + POWERSHELLEQUIVALENT + New-ProtectionAlert and Set-ProtectionAlert + 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/defender-standards#low-impact + #> + + param ($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'QuarantineRequestAlert' + + $PolicyName = 'CIPP User requested to release a quarantined message' + + $CurrentState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-ProtectionAlert' -Compliance | + Where-Object { $_.Name -eq $PolicyName } | + Select-Object -Property * + + $StateIsCorrect = ($CurrentState.NotifyUser -contains $Settings.NotifyUser) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Quarantine Request Alert is configured correctly' -sev Info + } else { + $cmdparams = @{ + 'NotifyUser' = $Settings.NotifyUser + 'Category' = 'ThreatManagement' + 'Operation' = 'QuarantineRequestReleaseMessage' + 'Severity' = 'Informational' + 'AggregationType' = 'None' + } + + if ($CurrentState.Name -eq $PolicyName) { + try { + $cmdparams['Identity'] = $PolicyName + New-ExoRequest -TenantId $Tenant -cmdlet 'Set-ProtectionAlert' -Compliance -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully configured Quarantine Request Alert' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to configure Quarantine Request Alert. Error: $ErrorMessage" -sev Error + } + } else { + try { + $cmdparams['name'] = $PolicyName + $cmdparams['ThreatType'] = 'Activity' + + New-ExoRequest -TenantId $Tenant -cmdlet 'New-ProtectionAlert' -Compliance -cmdparams $cmdparams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully created Quarantine Request Alert' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to create Quarantine Request Alert. Error: $ErrorMessage" -sev Error + } + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Quarantine Request Alert is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Quarantine Request Alert is disabled' -sev Info + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'QuarantineRequestAlert' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRetentionPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 similarity index 58% rename from Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRetentionPolicy.ps1 rename to Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 index 291e21412a92..346b100e04c6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRetentionPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 @@ -1,86 +1,113 @@ -function Invoke-CIPPStandardRetentionPolicyTag { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) RetentionPolicyTag - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'RetentionPolicyTag' - - $PolicyName = 'CIPP Deleted Items' - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-RetentionPolicyTag' | - Where-Object -Property Identity -EQ $PolicyName - - $PolicyState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-RetentionPolicy' | - Where-Object -Property Identity -EQ 'Default MRM Policy' - - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.RetentionEnabled -eq $true) -and - ($CurrentState.RetentionAction -eq 'PermanentlyDelete') -and - ($CurrentState.AgeLimitForRetention -eq ([timespan]::FromDays($Settings.AgeLimitForRetention))) -and - ($CurrentState.Type -eq 'DeletedItems') -and - ($PolicyState.RetentionPolicyTagLinks -contains $PolicyName) - - if ($Settings.remediate -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Retention policy tag already correctly configured' -sev Info - } else { - $cmdparams = @{ - RetentionEnabled = $true - AgeLimitForRetention = $Settings.AgeLimitForRetention - RetentionAction = 'PermanentlyDelete' - } - - if ($CurrentState.Name -eq $PolicyName) { - try { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-RetentionPolicyTag' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Retention policy tag $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Retention policy tag $PolicyName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', $PolicyName) - $cmdparams.Add('Type', 'DeletedItems') - New-ExoRequest -tenantid $Tenant -cmdlet 'New-RetentionPolicyTag' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Retention policy tag $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Retention policy tag $PolicyName." -sev Error -LogData $_ - } - } - - if ($PolicyState.RetentionPolicyTagLinks -notcontains $PolicyName) { - try { - $cmdparams = @{ - Identity = 'Default MRM Policy' - RetentionPolicyTagLinks = @($PolicyState.RetentionPolicyTagLinks + $PolicyName) - } - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-RetentionPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Added $PolicyName Retention tag to $($PolicyState.Identity)." -sev Info - } catch { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to add $PolicyName Retention tag to $($PolicyState.Identity)." -sev Error -LogData $_.Exception.Message - } - } - - } - - } - - if ($Settings.alert -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Retention Policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Retention Policy is not enabled' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'RetentionPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } - -} +function Invoke-CIPPStandardRetentionPolicyTag { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) RetentionPolicyTag + .SYNOPSIS + (Label) Retention Policy, permanently delete items in Deleted Items after X days + .DESCRIPTION + (Helptext) Creates a CIPP - Deleted Items retention policy tag that permanently deletes items in the Deleted Items folder after X days. + (DocsDescription) Creates a CIPP - Deleted Items retention policy tag that permanently deletes items in the Deleted Items folder after X days. + .NOTES + CAT + Exchange Standards + TAG + ADDEDCOMPONENT + {"type":"number","name":"standards.RetentionPolicyTag.AgeLimitForRetention","label":"Retention Days","required":true} + IMPACT + High Impact + ADDEDDATE + 2025-02-02 + POWERSHELLEQUIVALENT + Set-RetentionPolicyTag + 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/exchange-standards#high-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'RetentionPolicyTag' + + $PolicyName = 'CIPP Deleted Items' + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-RetentionPolicyTag' | + Where-Object -Property Identity -EQ $PolicyName + + $PolicyState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-RetentionPolicy' | + Where-Object -Property Identity -EQ 'Default MRM Policy' + + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.RetentionEnabled -eq $true) -and + ($CurrentState.RetentionAction -eq 'PermanentlyDelete') -and + ($CurrentState.AgeLimitForRetention -eq ([timespan]::FromDays($Settings.AgeLimitForRetention))) -and + ($CurrentState.Type -eq 'DeletedItems') -and + ($PolicyState.RetentionPolicyTagLinks -contains $PolicyName) + + if ($Settings.remediate -eq $true) { + Write-Host 'Time to remediate' + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Retention policy tag already correctly configured' -sev Info + } else { + $cmdParams = @{ + RetentionEnabled = $true + AgeLimitForRetention = $Settings.AgeLimitForRetention + RetentionAction = 'PermanentlyDelete' + } + + if ($CurrentState.Name -eq $PolicyName) { + try { + $cmdParams.Add('Identity', $PolicyName) + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-RetentionPolicyTag' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Retention policy tag $PolicyName." -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to update Retention policy tag $PolicyName." -sev Error -LogData $ErrorMessage + } + } else { + try { + $cmdParams.Add('Name', $PolicyName) + $cmdParams.Add('Type', 'DeletedItems') + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'New-RetentionPolicyTag' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Created Retention policy tag $PolicyName." -sev Info + } catch { + + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create Retention policy tag $PolicyName." -sev Error -LogData $ErrorMessage + } + } + + if ($PolicyState.RetentionPolicyTagLinks -notcontains $PolicyName) { + try { + $cmdParams = @{ + Identity = 'Default MRM Policy' + RetentionPolicyTagLinks = @($PolicyState.RetentionPolicyTagLinks + $PolicyName) + } + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-RetentionPolicy' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Added $PolicyName Retention tag to $($PolicyState.Identity)." -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to add $PolicyName Retention tag to $($PolicyState.Identity)." -sev Error -LogData $ErrorMessage + } + } + + } + + } + + if ($Settings.alert -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Retention Policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Retention Policy is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'RetentionPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 index 47776ea2f17f..1421b89997b0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardRotateDKIM { CAT Exchange Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2023-03-14 POWERSHELLEQUIVALENT Rotate-DkimSigningConfig RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 index bd016f0f9ba8..e447a74ab4af 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 @@ -1,68 +1,69 @@ -function Invoke-CIPPStandardSPAzureB2B { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SPAzureB2B - .SYNOPSIS - (Label) Enable SharePoint and OneDrive integration with Azure AD B2B - .DESCRIPTION - (Helptext) Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled - (DocsDescription) Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled - .NOTES - CAT - SharePoint Standards - TAG - "lowimpact" - "CIS" - ADDEDCOMPONENT - IMPACT - Low Impact - POWERSHELLEQUIVALENT - Set-SPOTenant -EnableAzureADB2BIntegration \$true - RECOMMENDEDBY - "CIS 3.0" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPAzureB2B' - - $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | - Select-Object -Property EnableAzureADB2BIntegration - - $StateIsCorrect = ($CurrentState.EnableAzureADB2BIntegration -eq $true) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Azure B2B is already enabled' -Sev Info - } else { - $Properties = @{ - EnableAzureADB2BIntegration = $true - } - - try { - Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set the SharePoint Azure B2B to enabled' -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set the SharePoint Azure B2B to enabled. Error: $ErrorMessage" -Sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Azure B2B is enabled' -Sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Azure B2B is not enabled' -Sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'AzureB2B' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } -} +function Invoke-CIPPStandardSPAzureB2B { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SPAzureB2B + .SYNOPSIS + (Label) Enable SharePoint and OneDrive integration with Azure AD B2B + .DESCRIPTION + (Helptext) Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled + (DocsDescription) Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled + .NOTES + CAT + SharePoint Standards + TAG + "CIS" + ADDEDCOMPONENT + IMPACT + Low Impact + ADDEDDATE + 2024-07-09 + POWERSHELLEQUIVALENT + Set-SPOTenant -EnableAzureADB2BIntegration \$true + RECOMMENDEDBY + "CIS 3.0" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPAzureB2B' + + $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | + Select-Object -Property EnableAzureADB2BIntegration + + $StateIsCorrect = ($CurrentState.EnableAzureADB2BIntegration -eq $true) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Azure B2B is already enabled' -Sev Info + } else { + $Properties = @{ + EnableAzureADB2BIntegration = $true + } + + try { + Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set the SharePoint Azure B2B to enabled' -Sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set the SharePoint Azure B2B to enabled. Error: $ErrorMessage" -Sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Azure B2B is enabled' -Sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Azure B2B is not enabled' -Sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'AzureB2B' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 index c9f44c0c8a21..9852c5536afb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 @@ -1,68 +1,70 @@ -function Invoke-CIPPStandardSPDirectSharing { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SPDirectSharing - .SYNOPSIS - (Label) Default sharing to Direct users - .DESCRIPTION - (Helptext) Ensure default link sharing is set to Direct in SharePoint and OneDrive - (DocsDescription) Ensure default link sharing is set to Direct in SharePoint and OneDrive - .NOTES - CAT - SharePoint Standards - TAG - "mediumimpact" - "CIS" - ADDEDCOMPONENT - IMPACT - Medium Impact - POWERSHELLEQUIVALENT - Set-SPOTenant -DefaultSharingLinkType Direct - RECOMMENDEDBY - "CIS 3.0" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDirectSharing' - - $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | - Select-Object -Property DefaultSharingLinkType - - $StateIsCorrect = ($CurrentState.DefaultSharingLinkType -eq 'Direct' -or $CurrentState.DefaultSharingLinkType -eq 1) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Sharing Restriction is already enabled' -Sev Info - } else { - $Properties = @{ - DefaultSharingLinkType = 1 - } - - try { - Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set the SharePoint Sharing Restriction to Direct' -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set the SharePoint Sharing Restriction to Direct. Error: $ErrorMessage" -Sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Sharing Restriction is enabled' -Sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Sharing Restriction is not enabled' -Sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'DirectSharing' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } -} +function Invoke-CIPPStandardSPDirectSharing { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SPDirectSharing + .SYNOPSIS + (Label) Default sharing to Direct users + .DESCRIPTION + (Helptext) Ensure default link sharing is set to Direct in SharePoint and OneDrive + (DocsDescription) Ensure default link sharing is set to Direct in SharePoint and OneDrive + .NOTES + CAT + SharePoint Standards + TAG + "CIS" + ADDEDCOMPONENT + IMPACT + Medium Impact + ADDEDDATE + 2024-07-09 + POWERSHELLEQUIVALENT + Set-SPOTenant -DefaultSharingLinkType Direct + RECOMMENDEDBY + "CIS" + "CIPP" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDirectSharing' + + $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | + Select-Object -Property DefaultSharingLinkType + + $StateIsCorrect = ($CurrentState.DefaultSharingLinkType -eq 'Direct' -or $CurrentState.DefaultSharingLinkType -eq 1) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Sharing Restriction is already enabled' -Sev Info + } else { + $Properties = @{ + DefaultSharingLinkType = 1 + } + + try { + Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set the SharePoint Sharing Restriction to Direct' -Sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set the SharePoint Sharing Restriction to Direct. Error: $ErrorMessage" -Sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Sharing Restriction is enabled' -Sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint Sharing Restriction is not enabled' -Sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'DirectSharing' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 index 7ee1f747340b..a4034f2c66aa 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 @@ -1,69 +1,70 @@ -function Invoke-CIPPStandardSPDisableLegacyWorkflows { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SPDisableLegacyWorkflows - .SYNOPSIS - (Label) Disable Legacy Workflows - .DESCRIPTION - (Helptext) Disables the creation of new SharePoint 2010 and 2013 classic workflows and removes the 'Return to classic SharePoint' link on modern SharePoint list and library pages. - (DocsDescription) Disables the creation of new SharePoint 2010 and 2013 classic workflows and removes the 'Return to classic SharePoint' link on modern SharePoint list and library pages. - .NOTES - CAT - SharePoint Standards - TAG - "lowimpact" - ADDEDCOMPONENT - IMPACT - Low Impact - POWERSHELLEQUIVALENT - Set-SPOTenant -DisableWorkflow2010 \$true -DisableWorkflow2013 \$true -DisableBackToClassic \$true - 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/sharepoint-standards#low-impact - #> - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDisableLegacyWorkflows' - - $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | - Select-Object -Property * - - $StateIsCorrect = ($CurrentState.StopNew2010Workflows -eq $true) -and - ($CurrentState.StopNew2013Workflows -eq $true) -and - ($CurrentState.DisableBackToClassic -eq $true) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Legacy Workflows are already disabled.' -Sev Info - } else { - $Properties = @{ - StopNew2010Workflows = $true - StopNew2013Workflows = $true - DisableBackToClassic = $true - } - - try { - Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully disabled Legacy Workflows' -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to disable Legacy Workflows. Error: $ErrorMessage" -Sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Legacy Workflows are disabled' -Sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Legacy Workflows are enabled' -Sev Info - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SPDisableLegacyWorkflows' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +function Invoke-CIPPStandardSPDisableLegacyWorkflows { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SPDisableLegacyWorkflows + .SYNOPSIS + (Label) Disable Legacy Workflows + .DESCRIPTION + (Helptext) Disables the creation of new SharePoint 2010 and 2013 classic workflows and removes the 'Return to classic SharePoint' link on modern SharePoint list and library pages. + (DocsDescription) Disables the creation of new SharePoint 2010 and 2013 classic workflows and removes the 'Return to classic SharePoint' link on modern SharePoint list and library pages. + .NOTES + CAT + SharePoint Standards + TAG + ADDEDCOMPONENT + IMPACT + Low Impact + ADDEDDATE + 2024-07-15 + POWERSHELLEQUIVALENT + Set-SPOTenant -DisableWorkflow2010 \$true -DisableWorkflow2013 \$true -DisableBackToClassic \$true + 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/sharepoint-standards#low-impact + #> + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDisableLegacyWorkflows' + + $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | + Select-Object -Property * + + $StateIsCorrect = ($CurrentState.StopNew2010Workflows -eq $true) -and + ($CurrentState.StopNew2013Workflows -eq $true) -and + ($CurrentState.DisableBackToClassic -eq $true) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Legacy Workflows are already disabled.' -Sev Info + } else { + $Properties = @{ + StopNew2010Workflows = $true + StopNew2013Workflows = $true + DisableBackToClassic = $true + } + + try { + Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully disabled Legacy Workflows' -Sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to disable Legacy Workflows. Error: $ErrorMessage" -Sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Legacy Workflows are disabled' -Sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Legacy Workflows are enabled' -Sev Info + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SPDisableLegacyWorkflows' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 index 76e9a1682200..03c34ec3b768 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 @@ -1,68 +1,70 @@ -function Invoke-CIPPStandardSPDisallowInfectedFiles { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SPDisallowInfectedFiles - .SYNOPSIS - (Label) Disallow downloading infected files from SharePoint - .DESCRIPTION - (Helptext) Ensure Office 365 SharePoint infected files are disallowed for download - (DocsDescription) Ensure Office 365 SharePoint infected files are disallowed for download - .NOTES - CAT - SharePoint Standards - TAG - "lowimpact" - "CIS" - ADDEDCOMPONENT - IMPACT - Low Impact - POWERSHELLEQUIVALENT - Set-SPOTenant -DisallowInfectedFileDownload \$true - RECOMMENDEDBY - "CIS 3.0" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDisallowInfectedFiles' - - $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | - Select-Object -Property DisallowInfectedFileDownload - - $StateIsCorrect = ($CurrentState.DisallowInfectedFileDownload -eq $true) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Downloading Sharepoint infected files are already disallowed.' -Sev Info - } else { - $Properties = @{ - DisallowInfectedFileDownload = $true - } - - try { - Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties - Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Successfully disallowed downloading SharePoint infected files.' -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -Message "Failed to disallow downloading Sharepoint infected files. Error: $ErrorMessage" -Sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Downloading Sharepoint infected files are disallowed.' -Sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Downloading Sharepoint infected files are allowed.' -Sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SPDisallowInfectedFiles' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +function Invoke-CIPPStandardSPDisallowInfectedFiles { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SPDisallowInfectedFiles + .SYNOPSIS + (Label) Disallow downloading infected files from SharePoint + .DESCRIPTION + (Helptext) Ensure Office 365 SharePoint infected files are disallowed for download + (DocsDescription) Ensure Office 365 SharePoint infected files are disallowed for download + .NOTES + CAT + SharePoint Standards + TAG + "CIS" + ADDEDCOMPONENT + IMPACT + Low Impact + ADDEDDATE + 2024-07-09 + POWERSHELLEQUIVALENT + Set-SPOTenant -DisallowInfectedFileDownload \$true + RECOMMENDEDBY + "CIS" + "CIPP" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#low-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPDisallowInfectedFiles' + + $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | + Select-Object -Property DisallowInfectedFileDownload + + $StateIsCorrect = ($CurrentState.DisallowInfectedFileDownload -eq $true) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Downloading Sharepoint infected files are already disallowed.' -Sev Info + } else { + $Properties = @{ + DisallowInfectedFileDownload = $true + } + + try { + Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties + Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Successfully disallowed downloading SharePoint infected files.' -Sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -Message "Failed to disallow downloading Sharepoint infected files. Error: $ErrorMessage" -Sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Downloading Sharepoint infected files are disallowed.' -Sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -Message 'Downloading Sharepoint infected files are allowed.' -Sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SPDisallowInfectedFiles' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 index 05b078a5e62e..a3b808415c65 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 @@ -1,71 +1,73 @@ -function Invoke-CIPPStandardSPEmailAttestation { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SPEmailAttestation - .SYNOPSIS - (Label) Require reauthentication with verification code - .DESCRIPTION - (Helptext) Ensure reauthentication with verification code is restricted - (DocsDescription) Ensure reauthentication with verification code is restricted - .NOTES - CAT - SharePoint Standards - TAG - "mediumimpact" - "CIS" - ADDEDCOMPONENT - {"type":"number","name":"standards.SPEmailAttestation.Days","label":"Require reauth every X Days (Default 15)"} - IMPACT - Medium Impact - POWERSHELLEQUIVALENT - Set-SPOTenant -EmailAttestationRequired \$true -EmailAttestationReAuthDays 15 - RECOMMENDEDBY - "CIS 3.0" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPEmailAttestation' - - $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | - Select-Object -Property EmailAttestationReAuthDays, EmailAttestationRequired - - $StateIsCorrect = ($CurrentState.EmailAttestationReAuthDays -eq $Settings.Days) -and - ($CurrentState.EmailAttestationRequired -eq $true) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Sharepoint reauthentication with verification code is already restricted.' -Sev Info - } else { - $Properties = @{ - EmailAttestationReAuthDays = $Settings.Days - EmailAttestationRequired = $true - } - - try { - Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set reauthentication with verification code restriction.' -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set reauthentication with verification code restriction. Error: $ErrorMessage" -Sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is restricted.' -Sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is not restricted.' -Sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SPEmailAttestation' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +function Invoke-CIPPStandardSPEmailAttestation { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SPEmailAttestation + .SYNOPSIS + (Label) Require re-authentication with verification code + .DESCRIPTION + (Helptext) Ensure re-authentication with verification code is restricted + (DocsDescription) Ensure re-authentication with verification code is restricted + .NOTES + CAT + SharePoint Standards + TAG + "CIS" + ADDEDCOMPONENT + {"type":"number","name":"standards.SPEmailAttestation.Days","label":"Require re-authentication every X Days (Default 15)"} + IMPACT + Medium Impact + ADDEDDATE + 2024-07-09 + POWERSHELLEQUIVALENT + Set-SPOTenant -EmailAttestationRequired \$true -EmailAttestationReAuthDays 15 + RECOMMENDEDBY + "CIS" + "CIPP" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPEmailAttestation' + + $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | + Select-Object -Property EmailAttestationReAuthDays, EmailAttestationRequired + + $StateIsCorrect = ($CurrentState.EmailAttestationReAuthDays -eq $Settings.Days) -and + ($CurrentState.EmailAttestationRequired -eq $true) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Sharepoint reauthentication with verification code is already restricted.' -Sev Info + } else { + $Properties = @{ + EmailAttestationReAuthDays = $Settings.Days + EmailAttestationRequired = $true + } + + try { + Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set reauthentication with verification code restriction.' -Sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set reauthentication with verification code restriction. Error: $ErrorMessage" -Sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is restricted.' -Sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Reauthentication with verification code is not restricted.' -Sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SPEmailAttestation' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 index 02589cf0c61e..b2f7db4c3f68 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 @@ -1,71 +1,72 @@ -function Invoke-CIPPStandardSPExternalUserExpiration { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SPExternalUserExpiration - .SYNOPSIS - (Label) Set guest access to expire automatically - .DESCRIPTION - (Helptext) Ensure guest access to a site or OneDrive will expire automatically - (DocsDescription) Ensure guest access to a site or OneDrive will expire automatically - .NOTES - CAT - SharePoint Standards - TAG - "mediumimpact" - "CIS" - ADDEDCOMPONENT - {"type":"number","name":"standards.SPExternalUserExpiration.Days","label":"Days until expiration (Default 60)"} - IMPACT - Medium Impact - POWERSHELLEQUIVALENT - Set-SPOTenant -ExternalUserExpireInDays 30 -ExternalUserExpirationRequired \$True - RECOMMENDEDBY - "CIS 3.0" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPExternalUserExpiration' - - $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | - Select-Object -Property ExternalUserExpireInDays, ExternalUserExpirationRequired - - $StateIsCorrect = ($CurrentState.ExternalUserExpireInDays -eq $Settings.Days) -and - ($CurrentState.ExternalUserExpirationRequired -eq $true) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Sharepoint External User Expiration is already enabled.' -Sev Info - } else { - $Properties = @{ - ExternalUserExpireInDays = $Settings.Days - ExternalUserExpirationRequired = $true - } - - try { - Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set External User Expiration' -Sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set External User Expiration. Error: $ErrorMessage" -Sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'External User Expiration is enabled' -Sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'External User Expiration is not enabled' -Sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'ExternalUserExpiration' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +function Invoke-CIPPStandardSPExternalUserExpiration { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SPExternalUserExpiration + .SYNOPSIS + (Label) Set guest access to expire automatically + .DESCRIPTION + (Helptext) Ensure guest access to a site or OneDrive will expire automatically + (DocsDescription) Ensure guest access to a site or OneDrive will expire automatically + .NOTES + CAT + SharePoint Standards + TAG + "CIS" + ADDEDCOMPONENT + {"type":"number","name":"standards.SPExternalUserExpiration.Days","label":"Days until expiration (Default 60)"} + IMPACT + Medium Impact + ADDEDDATE + 2024-07-09 + POWERSHELLEQUIVALENT + Set-SPOTenant -ExternalUserExpireInDays 30 -ExternalUserExpirationRequired \$True + RECOMMENDEDBY + "CIS 3.0" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards/sharepoint-standards#medium-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPExternalUserExpiration' + + $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | + Select-Object -Property ExternalUserExpireInDays, ExternalUserExpirationRequired + + $StateIsCorrect = ($CurrentState.ExternalUserExpireInDays -eq $Settings.Days) -and + ($CurrentState.ExternalUserExpirationRequired -eq $true) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'SharePoint External User Expiration is already enabled.' -Sev Info + } else { + $Properties = @{ + ExternalUserExpireInDays = $Settings.Days + ExternalUserExpirationRequired = $true + } + + try { + Get-CIPPSPOTenant -TenantFilter $Tenant | Set-CIPPSPOTenant -Properties $Properties + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'Successfully set External User Expiration' -Sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Failed to set External User Expiration. Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'External User Expiration is enabled' -Sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message 'External User Expiration is not enabled' -Sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'ExternalUserExpiration' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 index 4b54a8b44ad3..bd4b5a81e7b2 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardSPSyncButtonState { CAT SharePoint Standards TAG - "mediumimpact" ADDEDCOMPONENT - {"type":"autoComplete","multiple":false,"label":"SharePoint Sync Button state","name":"standards.SPSyncButtonState.state","options":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"label":"SharePoint Sync Button state","name":"standards.SPSyncButtonState.state","options":[{"label":"Disabled","value":"true"},{"label":"Enabled","value":"false"}]} IMPACT Medium Impact + ADDEDDATE + 2024-07-26 POWERSHELLEQUIVALENT Set-SPOTenant -HideSyncButtonOnTeamSite \$true or \$false RECOMMENDEDBY @@ -31,20 +32,22 @@ function Invoke-CIPPStandardSPSyncButtonState { ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SPSyncButtonState' $CurrentState = Get-CIPPSPOTenant -TenantFilter $Tenant | Select-Object _ObjectIdentity_, TenantFilter, HideSyncButtonOnDocLib - $WantedState = [System.Convert]::ToBoolean($Settings.state) - $StateIsCorrect = if ($CurrentState.HideSyncButtonOnDocLib -eq $WantedState) { $true } else { $false } - $HumanReadableState = if ($WantedState -eq $true) { 'disabled' } else { 'enabled' } if ($Settings.report -eq $true) { Add-CIPPBPAField -FieldName 'SPSyncButtonDisabled' -FieldValue $CurrentState.HideSyncButtonOnDocLib -StoreAs bool -Tenant $Tenant } # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + $StateValue = $Settings.state.value ?? $Settings.state + if (([string]::IsNullOrWhiteSpace($StateValue) -or $StateValue -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'SPSyncButtonState: Invalid state parameter set' -sev Error Return } + $WantedState = [System.Convert]::ToBoolean($StateValue) + $StateIsCorrect = if ($CurrentState.HideSyncButtonOnDocLib -eq $WantedState) { $true } else { $false } + $HumanReadableState = if ($WantedState -eq $true) { 'disabled' } else { 'enabled' } + if ($Settings.remediate -eq $true) { Write-Host 'Time to remediate' diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index d45abf7e5973..3ad9eb6b025b 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -1,170 +1,171 @@ -function Invoke-CIPPStandardSafeAttachmentPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SafeAttachmentPolicy - .SYNOPSIS - (Label) Default Safe Attachment Policy - .DESCRIPTION - (Helptext) This creates a Safe Attachment policy - (DocsDescription) This creates a Safe Attachment policy - .NOTES - CAT - Defender Standards - TAG - "lowimpact" - "CIS" - "mdo_safedocuments" - "mdo_commonattachmentsfilter" - "mdo_safeattachmentpolicy" - ADDEDCOMPONENT - {"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 - Set-SafeAttachmentPolicy or New-SafeAttachmentPolicy - RECOMMENDEDBY - "CIS" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - 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' - - $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant - $ServicePlans = $ServicePlans.servicePlans.servicePlanName - $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" - - 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 - } - - $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentPolicy' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object Name, Enable, Action, QuarantineTag, Redirect, RedirectAddress - - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.Enable -eq $true) -and - ($CurrentState.Action -eq $Settings.SafeAttachmentAction) -and - ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and - ($CurrentState.Redirect -eq $Settings.Redirect) -and - (($null -eq $Settings.RedirectAddress) -or ($CurrentState.RedirectAddress -eq $Settings.RedirectAddress)) - - $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' - - $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | - Where-Object -Property Name -EQ $RuleName | - Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs - - $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 ($Settings.remediate -eq $true) { - - 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.SafeAttachmentAction - QuarantineTag = $Settings.QuarantineTag - Redirect = $Settings.Redirect - RedirectAddress = $Settings.RedirectAddress - } - - 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 ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name - } - - if ($RuleState.SafeAttachmentPolicy -ne $PolicyName) { - $cmdparams.Add('SafeAttachmentPolicy', $PolicyName) - } - - 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 ($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 - } - } 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 - } - } -} +function Invoke-CIPPStandardSafeAttachmentPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SafeAttachmentPolicy + .SYNOPSIS + (Label) Default Safe Attachment Policy + .DESCRIPTION + (Helptext) This creates a Safe Attachment policy + (DocsDescription) This creates a Safe Attachment policy + .NOTES + CAT + Defender Standards + TAG + "CIS" + "mdo_safedocuments" + "mdo_commonattachmentsfilter" + "mdo_safeattachmentpolicy" + ADDEDCOMPONENT + {"type":"select","multiple":false,"label":"Safe Attachment Action","name":"standards.SafeAttachmentPolicy.SafeAttachmentAction","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 + ADDEDDATE + 2024-03-25 + POWERSHELLEQUIVALENT + Set-SafeAttachmentPolicy or New-SafeAttachmentPolicy + RECOMMENDEDBY + "CIS" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + 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' + + $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant + $ServicePlans = $ServicePlans.servicePlans.servicePlanName + $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" + + 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 + } + + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentPolicy' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object Name, Enable, Action, QuarantineTag, Redirect, RedirectAddress + + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.Enable -eq $true) -and + ($CurrentState.Action -eq $Settings.SafeAttachmentAction) -and + ($CurrentState.QuarantineTag -eq $Settings.QuarantineTag) -and + ($CurrentState.Redirect -eq $Settings.Redirect) -and + (($null -eq $Settings.RedirectAddress) -or ($CurrentState.RedirectAddress -eq $Settings.RedirectAddress)) + + $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' + + $RuleState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-SafeAttachmentRule' | + Where-Object -Property Name -EQ $RuleName | + Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs + + $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 ($Settings.remediate -eq $true) { + + 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.SafeAttachmentAction + QuarantineTag = $Settings.QuarantineTag + Redirect = $Settings.Redirect + RedirectAddress = $Settings.RedirectAddress + } + + 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 ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + if ($RuleState.SafeAttachmentPolicy -ne $PolicyName) { + $cmdparams.Add('SafeAttachmentPolicy', $PolicyName) + } + + 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 ($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 + } + } 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 b9b9823cf47c..a9ad0f3cbd8d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -1,178 +1,179 @@ -function Invoke-CIPPStandardSafeLinksPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SafeLinksPolicy - .SYNOPSIS - (Label) Default SafeLinks Policy - .DESCRIPTION - (Helptext) This creates a safelink policy that automatically scans, tracks, and and enables safe links for Email, Office, and Teams for both external and internal senders - (DocsDescription) This creates a safelink policy that automatically scans, tracks, and and enables safe links for Email, Office, and Teams for both external and internal senders - .NOTES - CAT - Defender Standards - TAG - "lowimpact" - "CIS" - "mdo_safelinksforemail" - "mdo_safelinksforOfficeApps" - ADDEDCOMPONENT - {"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 - Set-SafeLinksPolicy or New-SafeLinksPolicy - RECOMMENDEDBY - "CIS" - UPDATECOMMENTBLOCK - Run the Tools\Update-StandardsComments.ps1 script to update this comment block - .LINK - 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' - - $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant - $ServicePlans = $ServicePlans.servicePlans.servicePlanName - $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" - - 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 { - $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 - } - - $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 { - $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 ($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 ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name - } - - if ($RuleState.SafeLinksPolicy -ne $PolicyName) { - $cmdparams.Add('SafeLinksPolicy', $PolicyName) - } - - 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 ($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 - } - } 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 - } - } -} +function Invoke-CIPPStandardSafeLinksPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SafeLinksPolicy + .SYNOPSIS + (Label) Default SafeLinks Policy + .DESCRIPTION + (Helptext) This creates a safelink policy that automatically scans, tracks, and and enables safe links for Email, Office, and Teams for both external and internal senders + (DocsDescription) This creates a safelink policy that automatically scans, tracks, and and enables safe links for Email, Office, and Teams for both external and internal senders + .NOTES + CAT + Defender Standards + TAG + "CIS" + "mdo_safelinksforemail" + "mdo_safelinksforOfficeApps" + ADDEDCOMPONENT + {"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 + ADDEDDATE + 2024-03-25 + POWERSHELLEQUIVALENT + Set-SafeLinksPolicy or New-SafeLinksPolicy + RECOMMENDEDBY + "CIS" + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + 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' + + $ServicePlans = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/subscribedSkus?$select=servicePlans' -tenantid $Tenant + $ServicePlans = $ServicePlans.servicePlans.servicePlanName + $MDOLicensed = $ServicePlans -contains "ATP_ENTERPRISE" + + 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 { + $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 + } + + $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 { + $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 ($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 ($RuleStateIsCorrect -eq $false) { + $cmdparams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + if ($RuleState.SafeLinksPolicy -ne $PolicyName) { + $cmdparams.Add('SafeLinksPolicy', $PolicyName) + } + + 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 ($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 + } + } 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 283bc4d5a267..c68ec98e4a0a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 @@ -13,15 +13,17 @@ function Invoke-CIPPStandardSafeSendersDisable { CAT Exchange Standards TAG - "mediumimpact" ADDEDCOMPONENT DISABLEDFEATURES IMPACT Medium Impact + ADDEDDATE + 2023-10-26 POWERSHELLEQUIVALENT Set-MailboxJunkEmailConfiguration RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 index 3a43c05d0222..90e2db0be9df 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSecurityDefaults.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardSecurityDefaults { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2021-11-19 POWERSHELLEQUIVALENT [Read more here](https://www.cyberdrain.com/automating-with-powershell-enabling-secure-defaults-and-sd-explained/) RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 index 4084650d240e..766b57bf21c0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardSendFromAlias { CAT Exchange Standards TAG - "mediumimpact" ADDEDCOMPONENT IMPACT Medium Impact + ADDEDDATE + 2022-05-25 POWERSHELLEQUIVALENT Set-Mailbox RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 index a2ce48171f59..90616d76e459 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardSendReceiveLimitTenant { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"number","name":"standards.SendReceiveLimitTenant.SendLimit","label":"Send limit in MB (Default is 35)","default":35} - {"type":"number","name":"standards.SendReceiveLimitTenant.ReceiveLimit","label":"Receive Limit in MB (Default is 36)","default":36} + {"type":"number","name":"standards.SendReceiveLimitTenant.SendLimit","label":"Send limit in MB (Default is 35)","defaultValue":35} + {"type":"number","name":"standards.SendReceiveLimitTenant.ReceiveLimit","label":"Receive Limit in MB (Default is 36)","defaultValue":36} IMPACT Low Impact + ADDEDDATE + 2023-11-16 POWERSHELLEQUIVALENT Set-MailboxPlan RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 index c1469596a27e..f1e267db8efd 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 @@ -13,13 +13,14 @@ function Invoke-CIPPStandardShortenMeetings { CAT Exchange Standards TAG - "mediumimpact" ADDEDCOMPONENT - {"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} + {"type":"autoComplete","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)","defaultValue":5} + {"type":"number","name":"standards.ShortenMeetings.DefaultMinutesToReduceLongEventsBy","label":"Minutes to reduce long calendar events by (Default is 10)","defaultValue":10} IMPACT Medium Impact + ADDEDDATE + 2024-05-27 POWERSHELLEQUIVALENT Set-OrganizationConfig -ShortenEventScopeDefault -DefaultMinutesToReduceShortEventsBy -DefaultMinutesToReduceLongEventsBy RECOMMENDEDBY @@ -34,17 +35,20 @@ function Invoke-CIPPStandardShortenMeetings { # Input validation if ([Int32]$Settings.DefaultMinutesToReduceShortEventsBy -lt 0 -or [Int32]$Settings.DefaultMinutesToReduceShortEventsBy -gt 29) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Invalid shorten meetings settings specified. DefaultMinutesToReduceShortEventsBy must be an integer between 0 and 29' -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'ShortenMeetings: Invalid setting specified. DefaultMinutesToReduceShortEventsBy must be an integer between 0 and 29' -sev Error Return } if ([Int32]$Settings.DefaultMinutesToReduceLongEventsBy -lt 0 -or [Int32]$Settings.DefaultMinutesToReduceLongEventsBy -gt 29) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Invalid shorten meetings settings specified. DefaultMinutesToReduceLongEventsBy must be an integer between 0 and 29' -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'ShortenMeetings: Invalid setting specified. DefaultMinutesToReduceLongEventsBy must be an integer between 0 and 29' -sev Error Return } + # Get state value using null-coalescing operator + $scopeDefault = $Settings.ShortenEventScopeDefault.value ?? $Settings.ShortenEventScopeDefault + $CurrentState = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig' | - Select-Object -Property ShortenEventScopeDefault, DefaultMinutesToReduceShortEventsBy, DefaultMinutesToReduceLongEventsBy - $CorrectState = if ($CurrentState.ShortenEventScopeDefault -eq $Settings.ShortenEventScopeDefault -and + Select-Object -Property ShortenEventScopeDefault, DefaultMinutesToReduceShortEventsBy, DefaultMinutesToReduceLongEventsBy + $CorrectState = if ($CurrentState.ShortenEventScopeDefault -eq $scopeDefault -and $CurrentState.DefaultMinutesToReduceShortEventsBy -eq $Settings.DefaultMinutesToReduceShortEventsBy -and $CurrentState.DefaultMinutesToReduceLongEventsBy -eq $Settings.DefaultMinutesToReduceLongEventsBy) { $true } else { $false } @@ -52,14 +56,14 @@ function Invoke-CIPPStandardShortenMeetings { Write-Host 'Time to remediate' if ($CorrectState -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Shorten meetings settings are already in the correct state. ' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Shorten meetings settings are already in the correct state. ' -sev Info } else { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ShortenEventScopeDefault = $Settings.ShortenEventScopeDefault; DefaultMinutesToReduceShortEventsBy = $Settings.DefaultMinutesToReduceShortEventsBy; DefaultMinutesToReduceLongEventsBy = $Settings.DefaultMinutesToReduceLongEventsBy } - Write-LogMessage -API 'Standards' -tenant $tenant -message "Shorten meetings settings have been set to the following state. State: $($Settings.ShortenEventScopeDefault), Short:$($Settings.DefaultMinutesToReduceShortEventsBy), Long: $($Settings.DefaultMinutesToReduceLongEventsBy)" -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ShortenEventScopeDefault = $Settings.ShortenEventScopeDefault; DefaultMinutesToReduceShortEventsBy = $Settings.DefaultMinutesToReduceShortEventsBy; DefaultMinutesToReduceLongEventsBy = $Settings.DefaultMinutesToReduceLongEventsBy } + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Shorten meetings settings have been set to the following state. State: $($Settings.ShortenEventScopeDefault), Short:$($Settings.DefaultMinutesToReduceShortEventsBy), Long: $($Settings.DefaultMinutesToReduceLongEventsBy)" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set shorten meetings settings. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set shorten meetings settings. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } } @@ -67,18 +71,18 @@ function Invoke-CIPPStandardShortenMeetings { if ($Settings.alert -eq $true) { if ($CorrectState -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Shorten meetings settings are already in the correct state. Current state: $($CurrentState.ShortenEventScopeDefault), Short:$($CurrentState.DefaultMinutesToReduceShortEventsBy), Long: $($CurrentState.DefaultMinutesToReduceLongEventsBy)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Shorten meetings settings are already in the correct state. Current state: $($CurrentState.ShortenEventScopeDefault), Short:$($CurrentState.DefaultMinutesToReduceShortEventsBy), Long: $($CurrentState.DefaultMinutesToReduceLongEventsBy)" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Shorten meetings settings are not in the correct state. Current state: $($CurrentState.ShortenEventScopeDefault), Short:$($CurrentState.DefaultMinutesToReduceShortEventsBy), Long: $($CurrentState.DefaultMinutesToReduceLongEventsBy)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Shorten meetings settings are not in the correct state. Current state: $($CurrentState.ShortenEventScopeDefault), Short:$($CurrentState.DefaultMinutesToReduceShortEventsBy), Long: $($CurrentState.DefaultMinutesToReduceLongEventsBy)" -sev Alert } } if ($Settings.report -eq $true) { if ($CorrectState -eq $true) { - Add-CIPPBPAField -FieldName 'ShortenMeetings' -FieldValue $CorrectState -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'ShortenMeetings' -FieldValue $CorrectState -StoreAs bool -Tenant $Tenant } else { - Add-CIPPBPAField -FieldName 'ShortenMeetings' -FieldValue $CurrentState -StoreAs json -Tenant $tenant + Add-CIPPBPAField -FieldName 'ShortenMeetings' -FieldValue $CurrentState -StoreAs json -Tenant $Tenant } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index 0a1a86939f08..c46b4f4ca0cf 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -1,178 +1,220 @@ -function Invoke-CIPPStandardSpamFilterPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) SpamFilterPolicy - .SYNOPSIS - (Label) Default Spam Filter Policy - .DESCRIPTION - (Helptext) This standard creates a Spam filter policy similar to the default strict policy. - (DocsDescription) This standard creates a Spam filter policy similar to the default strict policy. - .NOTES - CAT - Defender Standards - TAG - "mediumimpact" - ADDEDCOMPONENT - {"type":"number","label":"Bulk email threshold (Default 7)","name":"standards.SpamFilterPolicy.BulkThreshold","default":7} - {"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 - New-HostedContentFilterPolicy or Set-HostedContentFilterPolicy - 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/defender-standards#medium-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SpamFilterPolicy' - - $PolicyName = 'CIPP Default Spam Filter Policy' - - $CurrentState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-HostedContentFilterPolicy' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object -Property * - - $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and - ($CurrentState.SpamAction -eq $Settings.SpamAction.value) -and - ($CurrentState.SpamQuarantineTag -eq $Settings.SpamQuarantineTag.value) -and - ($CurrentState.HighConfidenceSpamAction -eq $Settings.HighConfidenceSpamAction.value) -and - ($CurrentState.HighConfidenceSpamQuarantineTag -eq $Settings.HighConfidenceSpamQuarantineTag.value) -and - ($CurrentState.BulkSpamAction -eq $Settings.BulkSpamAction.value) -and - ($CurrentState.BulkQuarantineTag -eq $Settings.BulkQuarantineTag.value) -and - ($CurrentState.PhishSpamAction -eq $Settings.PhishSpamAction.value) -and - ($CurrentState.PhishQuarantineTag -eq $Settings.PhishQuarantineTag.value) -and - ($CurrentState.HighConfidencePhishAction -eq 'Quarantine') -and - ($CurrentState.HighConfidencePhishQuarantineTag -eq $Settings.HighConfidencePhishQuarantineTag.value) -and - ($CurrentState.BulkThreshold -eq $Settings.BulkThreshold) -and - ($CurrentState.QuarantineRetentionPeriod -eq 30) -and - ($CurrentState.IncreaseScoreWithNumericIps -eq 'On') -and - ($CurrentState.IncreaseScoreWithRedirectToOtherPort -eq 'On') -and - ($CurrentState.MarkAsSpamEmptyMessages -eq 'On') -and - ($CurrentState.MarkAsSpamJavaScriptInHtml -eq 'On') -and - ($CurrentState.MarkAsSpamSpfRecordHardFail -eq 'On') -and - ($CurrentState.MarkAsSpamFromAddressAuthFail -eq 'On') -and - ($CurrentState.MarkAsSpamNdrBackscatter -eq 'On') -and - ($CurrentState.MarkAsSpamBulkMail -eq 'On') -and - ($CurrentState.InlineSafetyTipsEnabled -eq $true) -and - ($CurrentState.PhishZapEnabled -eq $true) -and - ($CurrentState.SpamZapEnabled -eq $true) - - $AcceptedDomains = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-AcceptedDomain' - - $RuleState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-HostedContentFilterRule' | - Where-Object -Property Name -EQ $PolicyName | - Select-Object -Property * - - $RuleStateIsCorrect = ($RuleState.Name -eq $PolicyName) -and - ($RuleState.HostedContentFilterPolicy -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 'Spam Filter Policy already correctly configured' -sev Info - } else { - $cmdparams = @{ - SpamAction = $Settings.SpamAction.value - SpamQuarantineTag = $Settings.SpamQuarantineTag.value - HighConfidenceSpamAction = $Settings.HighConfidenceSpamAction.value - HighConfidenceSpamQuarantineTag = $Settings.HighConfidenceSpamQuarantineTag.value - BulkSpamAction = $Settings.BulkSpamAction.value - BulkQuarantineTag = $Settings.BulkQuarantineTag.value - PhishSpamAction = $Settings.PhishSpamAction.value - PhishQuarantineTag = $Settings.PhishQuarantineTag.value - HighConfidencePhishAction = 'Quarantine' - HighConfidencePhishQuarantineTag = $Settings.HighConfidencePhishQuarantineTag.value - BulkThreshold = $Settings.BulkThreshold - QuarantineRetentionPeriod = 30 - IncreaseScoreWithNumericIps = 'On' - IncreaseScoreWithRedirectToOtherPort = 'On' - MarkAsSpamEmptyMessages = 'On' - MarkAsSpamJavaScriptInHtml = 'On' - MarkAsSpamSpfRecordHardFail = 'On' - MarkAsSpamFromAddressAuthFail = 'On' - MarkAsSpamNdrBackscatter = 'On' - MarkAsSpamBulkMail = 'On' - InlineSafetyTipsEnabled = $true - PhishZapEnabled = $true - SpamZapEnabled = $true - } - Write-Host "================== DEBUG ==================" - Write-Host $cmdparams - - if ($CurrentState.Name -eq $PolicyName) { - try { - $cmdparams.Add('Identity', $PolicyName) - New-ExoRequest -TenantId $Tenant -cmdlet 'Set-HostedContentFilterPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Updated Spam Filter policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to update Spam Filter policy $PolicyName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', $PolicyName) - New-ExoRequest -TenantId $Tenant -cmdlet 'New-HostedContentFilterPolicy' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Created Spam Filter policy $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to create Spam Filter policy $PolicyName." -sev Error -LogData $_ - } - } - } - - if ($RuleStateIsCorrect -eq $false) { - $cmdparams = @{ - Priority = 0 - RecipientDomainIs = $AcceptedDomains.Name - } - - if ($RuleState.HostedContentFilterPolicy -ne $PolicyName) { - $cmdparams.Add('HostedContentFilterPolicy', $PolicyName) - } - - if ($RuleState.Name -eq $PolicyName) { - try { - $cmdparams.Add('Identity', "$PolicyName") - New-ExoRequest -TenantId $Tenant -cmdlet 'Set-HostedContentFilterRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Updated Spam Filter rule $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to update Spam Filter rule $PolicyName." -sev Error -LogData $_ - } - } else { - try { - $cmdparams.Add('Name', "$PolicyName") - New-ExoRequest -TenantId $Tenant -cmdlet 'New-HostedContentFilterRule' -cmdparams $cmdparams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Created Spam Filter rule $PolicyName." -sev Info - } catch { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to create Spam Filter rule $PolicyName." -sev Error -LogData $_ - } - } - } - } - - if ($Settings.alert -eq $true) { - - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message 'Spam Filter Policy is enabled' -sev Info - } else { - Write-LogMessage -API 'Standards' -Tenant $Tenant -message 'Spam Filter Policy is not enabled' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SpamFilterPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant - } - -} +function Invoke-CIPPStandardSpamFilterPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) SpamFilterPolicy + .SYNOPSIS + (Label) Default Spam Filter Policy + .DESCRIPTION + (Helptext) This standard creates a Spam filter policy similar to the default strict policy. + (DocsDescription) This standard creates a Spam filter policy similar to the default strict policy. + .NOTES + CAT + Defender Standards + TAG + ADDEDCOMPONENT + {"type":"number","label":"Bulk email threshold (Default 7)","name":"standards.SpamFilterPolicy.BulkThreshold","defaultValue":7} + {"type":"autoComplete","required":true,"multiple":false,"creatable":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","required":true,"multiple":false,"creatable":false,"label":"Spam Quarantine Tag","name":"standards.SpamFilterPolicy.SpamQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":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","required":true,"multiple":false,"creatable":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","required":true,"multiple":false,"creatable":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","required":true,"multiple":false,"creatable":false,"label":"Bulk Quarantine Tag","name":"standards.SpamFilterPolicy.BulkQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":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","required":true,"multiple":false,"creatable":false,"label":"Phish Quarantine Tag","name":"standards.SpamFilterPolicy.PhishQuarantineTag","options":[{"label":"AdminOnlyAccessPolicy","value":"AdminOnlyAccessPolicy"},{"label":"DefaultFullAccessPolicy","value":"DefaultFullAccessPolicy"},{"label":"DefaultFullAccessWithNotificationPolicy","value":"DefaultFullAccessWithNotificationPolicy"}]} + {"type":"autoComplete","required":true,"multiple":false,"creatable":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 + ADDEDDATE + 2024-07-15 + POWERSHELLEQUIVALENT + New-HostedContentFilterPolicy or Set-HostedContentFilterPolicy + 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/defender-standards#medium-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'SpamFilterPolicy' + + $PolicyName = 'CIPP Default Spam Filter Policy' + + $CurrentState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-HostedContentFilterPolicy' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object -Property * + + $SpamAction = $Settings.SpamAction.value ?? $Settings.SpamAction + $SpamQuarantineTag = $Settings.SpamQuarantineTag.value ?? $Settings.SpamQuarantineTag + $HighConfidenceSpamAction = $Settings.HighConfidenceSpamAction.value ?? $Settings.HighConfidenceSpamAction + $HighConfidenceSpamQuarantineTag = $Settings.HighConfidenceSpamQuarantineTag.value ?? $Settings.HighConfidenceSpamQuarantineTag + $BulkSpamAction = $Settings.BulkSpamAction.value ?? $Settings.BulkSpamAction + $BulkQuarantineTag = $Settings.BulkQuarantineTag.value ?? $Settings.BulkQuarantineTag + $PhishSpamAction = $Settings.PhishSpamAction.value ?? $Settings.PhishSpamAction + $PhishQuarantineTag = $Settings.PhishQuarantineTag.value ?? $Settings.PhishQuarantineTag + $HighConfidencePhishQuarantineTag = $Settings.HighConfidencePhishQuarantineTag.value ?? $Settings.HighConfidencePhishQuarantineTag + + $IncreaseScoreWithImageLinks = if ($Settings.IncreaseScoreWithImageLinks) { 'On' } else { 'Off' } + $IncreaseScoreWithBizOrInfoUrls = if ($Settings.IncreaseScoreWithBizOrInfoUrls) { 'On' } else { 'Off' } + $MarkAsSpamFramesInHtml = if ($Settings.MarkAsSpamFramesInHtml) { 'On' } else { 'Off' } + $MarkAsSpamObjectTagsInHtml = if ($Settings.MarkAsSpamObjectTagsInHtml) { 'On' } else { 'Off' } + $MarkAsSpamEmbedTagsInHtml = if ($Settings.MarkAsSpamEmbedTagsInHtml) { 'On' } else { 'Off' } + $MarkAsSpamFormTagsInHtml = if ($Settings.MarkAsSpamFormTagsInHtml) { 'On' } else { 'Off' } + $MarkAsSpamWebBugsInHtml = if ($Settings.MarkAsSpamWebBugsInHtml) { 'On' } else { 'Off' } + $MarkAsSpamSensitiveWordList = if ($Settings.MarkAsSpamSensitiveWordList) { 'On' } else { 'Off' } + + $StateIsCorrect = ($CurrentState.Name -eq $PolicyName) -and + ($CurrentState.SpamAction -eq $SpamAction) -and + ($CurrentState.SpamQuarantineTag -eq $SpamQuarantineTag) -and + ($CurrentState.HighConfidenceSpamAction -eq $HighConfidenceSpamAction) -and + ($CurrentState.HighConfidenceSpamQuarantineTag -eq $HighConfidenceSpamQuarantineTag) -and + ($CurrentState.BulkSpamAction -eq $BulkSpamAction) -and + ($CurrentState.BulkQuarantineTag -eq $BulkQuarantineTag) -and + ($CurrentState.PhishSpamAction -eq $PhishSpamAction) -and + ($CurrentState.PhishQuarantineTag -eq $PhishQuarantineTag) -and + ($CurrentState.HighConfidencePhishAction -eq 'Quarantine') -and + ($CurrentState.HighConfidencePhishQuarantineTag -eq $HighConfidencePhishQuarantineTag) -and + ($CurrentState.BulkThreshold -eq $Settings.BulkThreshold) -and + ($CurrentState.QuarantineRetentionPeriod -eq 30) -and + ($CurrentState.IncreaseScoreWithImageLinks -eq $IncreaseScoreWithImageLinks) -and + ($CurrentState.IncreaseScoreWithNumericIps -eq 'On') -and + ($CurrentState.IncreaseScoreWithRedirectToOtherPort -eq 'On') -and + ($CurrentState.IncreaseScoreWithBizOrInfoUrls -eq $IncreaseScoreWithBizOrInfoUrls) -and + ($CurrentState.MarkAsSpamEmptyMessages -eq 'On') -and + ($CurrentState.MarkAsSpamJavaScriptInHtml -eq 'On') -and + ($CurrentState.MarkAsSpamFramesInHtml -eq $MarkAsSpamFramesInHtml) -and + ($CurrentState.MarkAsSpamObjectTagsInHtml -eq $MarkAsSpamObjectTagsInHtml) -and + ($CurrentState.MarkAsSpamEmbedTagsInHtml -eq $MarkAsSpamEmbedTagsInHtml) -and + ($CurrentState.MarkAsSpamFormTagsInHtml -eq $MarkAsSpamFormTagsInHtml) -and + ($CurrentState.MarkAsSpamWebBugsInHtml -eq $MarkAsSpamWebBugsInHtml) -and + ($CurrentState.MarkAsSpamSensitiveWordList -eq $MarkAsSpamSensitiveWordList) -and + ($CurrentState.MarkAsSpamSpfRecordHardFail -eq 'On') -and + ($CurrentState.MarkAsSpamFromAddressAuthFail -eq 'On') -and + ($CurrentState.MarkAsSpamNdrBackscatter -eq 'On') -and + ($CurrentState.MarkAsSpamBulkMail -eq 'On') -and + ($CurrentState.InlineSafetyTipsEnabled -eq $true) -and + ($CurrentState.PhishZapEnabled -eq $true) -and + ($CurrentState.SpamZapEnabled -eq $true) -and + ($CurrentState.EnableLanguageBlockList -eq $Settings.EnableLanguageBlockList) -and + ((-not $CurrentState.LanguageBlockList -and -not $Settings.LanguageBlockList.value) -or (!(Compare-Object -ReferenceObject $CurrentState.LanguageBlockList -DifferenceObject $Settings.LanguageBlockList.value))) -and + ($CurrentState.EnableRegionBlockList -eq $Settings.EnableRegionBlockList) -and + ((-not $CurrentState.RegionBlockList -and -not $Settings.RegionBlockList.value) -or (!(Compare-Object -ReferenceObject $CurrentState.RegionBlockList -DifferenceObject $Settings.RegionBlockList.value))) + + $AcceptedDomains = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-AcceptedDomain' + + $RuleState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-HostedContentFilterRule' | + Where-Object -Property Name -EQ $PolicyName | + Select-Object -Property * + + $RuleStateIsCorrect = ($RuleState.Name -eq $PolicyName) -and + ($RuleState.HostedContentFilterPolicy -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 'Spam Filter Policy already correctly configured' -sev Info + } else { + $cmdparams = @{ + SpamAction = $SpamAction + SpamQuarantineTag = $SpamQuarantineTag + HighConfidenceSpamAction = $HighConfidenceSpamAction + HighConfidenceSpamQuarantineTag = $HighConfidenceSpamQuarantineTag + BulkSpamAction = $BulkSpamAction + BulkQuarantineTag = $BulkQuarantineTag + PhishSpamAction = $PhishSpamAction + PhishQuarantineTag = $PhishQuarantineTag + HighConfidencePhishAction = 'Quarantine' + HighConfidencePhishQuarantineTag = $HighConfidencePhishQuarantineTag + BulkThreshold = $Settings.BulkThreshold + QuarantineRetentionPeriod = 30 + IncreaseScoreWithImageLinks = $IncreaseScoreWithImageLinks + IncreaseScoreWithNumericIps = 'On' + IncreaseScoreWithRedirectToOtherPort = 'On' + IncreaseScoreWithBizOrInfoUrls = $IncreaseScoreWithBizOrInfoUrls + MarkAsSpamEmptyMessages = 'On' + MarkAsSpamJavaScriptInHtml = 'On' + MarkAsSpamFramesInHtml = $MarkAsSpamFramesInHtml + MarkAsSpamObjectTagsInHtml = $MarkAsSpamObjectTagsInHtml + MarkAsSpamEmbedTagsInHtml = $MarkAsSpamEmbedTagsInHtml + MarkAsSpamFormTagsInHtml = $MarkAsSpamFormTagsInHtml + MarkAsSpamWebBugsInHtml = $MarkAsSpamWebBugsInHtml + MarkAsSpamSensitiveWordList = $MarkAsSpamSensitiveWordList + MarkAsSpamSpfRecordHardFail = 'On' + MarkAsSpamFromAddressAuthFail = 'On' + MarkAsSpamNdrBackscatter = 'On' + MarkAsSpamBulkMail = 'On' + InlineSafetyTipsEnabled = $true + PhishZapEnabled = $true + SpamZapEnabled = $true + EnableLanguageBlockList = $Settings.EnableLanguageBlockList + LanguageBlockList = $Settings.LanguageBlockList.value + EnableRegionBlockList = $Settings.EnableRegionBlockList + RegionBlockList = $Settings.RegionBlockList.value + } + + if ($CurrentState.Name -eq $PolicyName) { + try { + $cmdParams.Add('Identity', $PolicyName) + $null = New-ExoRequest -TenantId $Tenant -cmdlet 'Set-HostedContentFilterPolicy' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Updated Spam Filter policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to update Spam Filter policy $PolicyName." -sev Error -LogData $_ + } + } else { + try { + $cmdParams.Add('Name', $PolicyName) + $null = New-ExoRequest -TenantId $Tenant -cmdlet 'New-HostedContentFilterPolicy' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Created Spam Filter policy $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to create Spam Filter policy $PolicyName." -sev Error -LogData $_ + } + } + } + + if ($RuleStateIsCorrect -eq $false) { + $cmdParams = @{ + Priority = 0 + RecipientDomainIs = $AcceptedDomains.Name + } + + if ($RuleState.HostedContentFilterPolicy -ne $PolicyName) { + $cmdParams.Add('HostedContentFilterPolicy', $PolicyName) + } + + if ($RuleState.Name -eq $PolicyName) { + try { + $cmdParams.Add('Identity', "$PolicyName") + $null = New-ExoRequest -TenantId $Tenant -cmdlet 'Set-HostedContentFilterRule' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Updated Spam Filter rule $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to update Spam Filter rule $PolicyName." -sev Error -LogData $_ + } + } else { + try { + $cmdParams.Add('Name', "$PolicyName") + $null = New-ExoRequest -TenantId $Tenant -cmdlet 'New-HostedContentFilterRule' -cmdParams $cmdParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Created Spam Filter rule $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to create Spam Filter rule $PolicyName." -sev Error -LogData $_ + } + } + } + } + + if ($Settings.alert -eq $true) { + + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message 'Spam Filter Policy is enabled' -sev Info + } else { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message 'Spam Filter Policy is not enabled' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'SpamFilterPolicy' -FieldValue $StateIsCorrect -StoreAs [bool] -Tenant $Tenant + } + +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index a9ba02025ac7..9fadf659d79a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardSpoofWarn { CAT Exchange Standards TAG - "lowimpact" "CIS" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.SpoofWarn.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} + {"type":"autoComplete","multiple":false,"label":"Select value","name":"standards.SpoofWarn.state","options":[{"label":"Enabled","value":"enabled"},{"label":"Disabled","value":"disabled"}]} IMPACT Low Impact + ADDEDDATE + 2021-11-16 POWERSHELLEQUIVALENT - et-ExternalInOutlook –Enabled \$true or \$false + Set-ExternalInOutlook –Enabled \$true or \$false RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK @@ -35,40 +37,43 @@ function Invoke-CIPPStandardSpoofWarn { $CurrentInfo = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-ExternalInOutlook') if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'SpoofingWarnings' -FieldValue $CurrentInfo.Enabled -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'SpoofingWarnings' -FieldValue $CurrentInfo.Enabled -StoreAs bool -Tenant $Tenant } + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'SpoofWarn: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'SpoofWarn: Invalid state parameter set' -sev Error Return } If ($Settings.remediate -eq $true) { $status = if ($Settings.enable -and $Settings.disable) { # Handle pre standards v2.0 legacy settings when this was 2 separate standards - Write-LogMessage -API 'Standards' -tenant $tenant -message 'You cannot both enable and disable the Spoof Warnings setting' -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'You cannot both enable and disable the Spoof Warnings setting' -sev Error Return - } elseif ($Settings.state -eq 'enabled' -or $Settings.enable) { $true } else { $false } + } elseif ($state -eq 'enabled' -or $Settings.enable) { $true } else { $false } if ($CurrentInfo.Enabled -eq $status) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Outlook external spoof warnings are already set to $status." -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Outlook external spoof warnings are already set to $status." -sev Info } else { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-ExternalInOutlook' -cmdParams @{ Enabled = $status; } - Write-LogMessage -API 'Standards' -tenant $tenant -message "Outlook external spoof warnings set to $status." -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-ExternalInOutlook' -cmdParams @{ Enabled = $status; } + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Outlook external spoof warnings set to $status." -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Could not set Outlook external spoof warnings to $status. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set Outlook external spoof warnings to $status. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } } if ($Settings.alert -eq $true) { if ($CurrentInfo.Enabled -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Outlook external spoof warnings are enabled.' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Outlook external spoof warnings are enabled.' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Outlook external spoof warnings are not enabled.' -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Outlook external spoof warnings are not enabled.' -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 index fbb236903975..f380385c7424 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 @@ -1,4 +1,4 @@ -function Invoke-CIPPStandardStaleEntraDevices { +function Invoke-CIPPStandardStaleEntraDevices { <# .FUNCTIONALITY Internal @@ -13,14 +13,15 @@ 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 + ADDEDDATE + 2025-01-19 POWERSHELLEQUIVALENT Remove-MgDevice, Update-MgDevice or Graph API RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 index 23f6ae97a643..8bcb90248721 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTAP.ps1 @@ -13,14 +13,16 @@ function Invoke-CIPPStandardTAP { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select TAP Lifetime","name":"standards.TAP.config","options":[{"label":"Only Once","value":"true"},{"label":"Multiple Logons","value":"false"}]} + {"type":"autoComplete","multiple":false,"creatable":false,"label":"Select TAP Lifetime","name":"standards.TAP.config","options":[{"label":"Only Once","value":"true"},{"label":"Multiple Logons","value":"false"}]} IMPACT Low Impact + ADDEDDATE + 2022-03-15 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK @@ -31,20 +33,24 @@ function Invoke-CIPPStandardTAP { ##$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 } + + # Get config value using null-coalescing operator + $config = $Settings.config.value ?? $Settings.config + if ($null -eq $config) { $config = $True } + $StateIsCorrect = ($CurrentState.state -eq 'enabled') -and - ([System.Convert]::ToBoolean($CurrentState.isUsableOnce) -eq [System.Convert]::ToBoolean($Settings.config)) + ([System.Convert]::ToBoolean($CurrentState.isUsableOnce) -eq [System.Convert]::ToBoolean($config)) if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TemporaryAccessPass' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'TemporaryAccessPass' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant } If ($Settings.remediate -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Temporary Access Passwords is already enabled.' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Temporary Access Passwords is already enabled.' -sev Info } else { try { - Set-CIPPAuthenticationPolicy -Tenant $tenant -APIName 'Standards' -AuthenticationMethodId 'TemporaryAccessPass' -Enabled $true -TAPisUsableOnce $Settings.config + Set-CIPPAuthenticationPolicy -Tenant $Tenant -APIName 'Standards' -AuthenticationMethodId 'TemporaryAccessPass' -Enabled $true -TAPisUsableOnce $config } catch { } } @@ -52,9 +58,9 @@ function Invoke-CIPPStandardTAP { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Temporary Access Passwords is enabled.' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Temporary Access Passwords is enabled.' -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Temporary Access Passwords is not enabled.' -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Temporary Access Passwords is not enabled.' -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 index d5a1a5db6b41..5c56f3973b0e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 @@ -1,71 +1,72 @@ -Function Invoke-CIPPStandardTeamsEmailIntegration { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) TeamsEmailIntegration - .SYNOPSIS - (Label) Disallow emails to be sent to channel email addresses - .DESCRIPTION - (Helptext) Should users be allowed to send emails directly to a channel email addresses? - (DocsDescription) Teams channel email addresses are an optional feature that allows users to email the Teams channel directly. - .NOTES - CAT - Teams Standards - TAG - "lowimpact" - ADDEDCOMPONENT - {"type":"switch","name":"standards.TeamsEmailIntegration.AllowEmailIntoChannel","label":"Allow channel emails"} - IMPACT - Low Impact - POWERSHELLEQUIVALENT - Set-CsTeamsClientConfiguration -AllowEmailIntoChannel \$false - RECOMMENDEDBY - "CIS 3.0" - 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) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsEmailIntegration' - - $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsClientConfiguration' -CmdParams @{Identity = 'Global' } - | Select-Object AllowEmailIntoChannel - - if ($null -eq $Settings.AllowEmailIntoChannel) { $Settings.AllowEmailIntoChannel = $false } - - $StateIsCorrect = ($CurrentState.AllowEmailIntoChannel -eq $Settings.AllowEmailIntoChannel) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Email Integration settings already set.' -sev Info - } else { - $cmdparams = @{ - Identity = 'Global' - AllowEmailIntoChannel = $Settings.AllowEmailIntoChannel - } - - try { - New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsClientConfiguration' -CmdParams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams Email Integration settings' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Email Integration settings. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Email Integration settings is set correctly.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Email Integration settings is not set correctly.' -sev Alert - } - } - - if ($Setings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TeamsEmailIntoChannel' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +Function Invoke-CIPPStandardTeamsEmailIntegration { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsEmailIntegration + .SYNOPSIS + (Label) Disallow emails to be sent to channel email addresses + .DESCRIPTION + (Helptext) Should users be allowed to send emails directly to a channel email addresses? + (DocsDescription) Teams channel email addresses are an optional feature that allows users to email the Teams channel directly. + .NOTES + CAT + Teams Standards + TAG + ADDEDCOMPONENT + {"type":"switch","name":"standards.TeamsEmailIntegration.AllowEmailIntoChannel","label":"Allow channel emails"} + IMPACT + Low Impact + ADDEDDATE + 2024-07-30 + POWERSHELLEQUIVALENT + Set-CsTeamsClientConfiguration -AllowEmailIntoChannel \$false + RECOMMENDEDBY + "CIS 3.0" + 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) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsEmailIntegration' + + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsClientConfiguration' -CmdParams @{Identity = 'Global' } + | Select-Object AllowEmailIntoChannel + + if ($null -eq $Settings.AllowEmailIntoChannel) { $Settings.AllowEmailIntoChannel = $false } + + $StateIsCorrect = ($CurrentState.AllowEmailIntoChannel -eq $Settings.AllowEmailIntoChannel) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Email Integration settings already set.' -sev Info + } else { + $cmdparams = @{ + Identity = 'Global' + AllowEmailIntoChannel = $Settings.AllowEmailIntoChannel + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsClientConfiguration' -CmdParams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams Email Integration settings' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Email Integration settings. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Email Integration settings is set correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Email Integration settings is not set correctly.' -sev Alert + } + } + + if ($Setings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TeamsEmailIntoChannel' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 index 464324ff4b61..2bf0c363a414 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 @@ -1,67 +1,71 @@ -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) - - $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsMeetingPolicy' -CmdParams @{Identity = 'Global' } - | Select-Object EnrollUserOverride - - $StateIsCorrect = ($CurrentState.EnrollUserOverride -eq $Settings.EnrollUserOverride.value) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Teams Enroll User Override settings already set to $($Settings.EnrollUserOverride.value)." -sev Info - } else { - $cmdparams = @{ - Identity = 'Global' - EnrollUserOverride = $Settings.EnrollUserOverride.value - } - - try { - New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsMeetingPolicy' -CmdParams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Teams Enroll User Override setting to $($Settings.EnrollUserOverride.value)." -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Enroll User Override setting to $($Settings.EnrollUserOverride.value)." -sev Error -LogData $ErrorMessage - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Enroll User Override settings is set correctly.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Enroll User Override settings is not set correctly.' -sev Alert - } - } - - if ($Setings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TeamsEnrollUser' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +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 + ADDEDCOMPONENT + {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"name":"standards.TeamsEnrollUser.EnrollUserOverride","label":"Voice and Face Enrollment","options":[{"label":"Disabled","value":"Disabled"},{"label":"Enabled","value":"Enabled"}]} + IMPACT + Low Impact + ADDEDDATE + 2024-11-12 + 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) + + # Get EnrollUserOverride value using null-coalescing operator + $enrollUserOverride = $Settings.EnrollUserOverride.value ?? $Settings.EnrollUserOverride + + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsMeetingPolicy' -cmdParams @{Identity = 'Global' } + | Select-Object EnrollUserOverride + + $StateIsCorrect = ($CurrentState.EnrollUserOverride -eq $enrollUserOverride) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Teams Enroll User Override settings already set to $enrollUserOverride." -sev Info + } else { + $cmdParams = @{ + Identity = 'Global' + EnrollUserOverride = $enrollUserOverride + } + + try { + $null = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsMeetingPolicy' -cmdParams $cmdParams + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Updated Teams Enroll User Override setting to $enrollUserOverride." -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Enroll User Override setting to $enrollUserOverride." -sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Enroll User Override settings is set correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Enroll User Override settings is not set correctly.' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TeamsEnrollUser' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 index 3c79a6fd30be..5324de381633 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 @@ -1,78 +1,79 @@ -Function Invoke-CIPPStandardTeamsExternalAccessPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) TeamsExternalAccessPolicy - .SYNOPSIS - (Label) External Access Settings for Microsoft Teams - .DESCRIPTION - (Helptext) Sets the properties of the Global external access policy. - (DocsDescription) Sets the properties of the Global external access policy. External access policies determine whether or not your users can: 1) communicate with users who have Session Initiation Protocol (SIP) accounts with a federated organization; 2) communicate with users who are using custom applications built with Azure Communication Services; 3) access Skype for Business Server over the Internet, without having to log on to your internal network; 4) communicate with users who have SIP accounts with a public instant messaging (IM) provider such as Skype; and, 5) communicate with people who are using Teams with an account that's not managed by an organization. - .NOTES - CAT - Teams Standards - TAG - "mediumimpact" - ADDEDCOMPONENT - {"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 - Set-CsExternalAccessPolicy - 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 - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsExternalAccessPolicy' - - $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsExternalAccessPolicy' -CmdParams @{Identity = 'Global' } - | Select-Object * - - if ($null -eq $Settings.EnableFederationAccess) { $Settings.EnableFederationAccess = $false } - if ($null -eq $Settings.EnablePublicCloudAccess) { $Settings.EnablePublicCloudAccess = $false } - if ($null -eq $Settings.EnableTeamsConsumerAccess) { $Settings.EnableTeamsConsumerAccess = $false } - - $StateIsCorrect = ($CurrentState.EnableFederationAccess -eq $Settings.EnableFederationAccess) -and - ($CurrentState.EnablePublicCloudAccess -eq $Settings.EnablePublicCloudAccess) -and - ($CurrentState.EnableTeamsConsumerAccess -eq $Settings.EnableTeamsConsumerAccess) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'External Access Policy already set.' -sev Info - } else { - $cmdparams = @{ - Identity = 'Global' - EnableFederationAccess = $Settings.EnableFederationAccess - EnablePublicCloudAccess = $Settings.EnablePublicCloudAccess - EnableTeamsConsumerAccess = $Settings.EnableTeamsConsumerAccess - } - - try { - New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsExternalAccessPolicy' -CmdParams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated External Access Policy' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set External Access Policy. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'External Access Policy is set correctly.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'External Access Policy is not set correctly.' -sev Alert - } - } - - if ($Setings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TeamsExternalAccessPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +Function Invoke-CIPPStandardTeamsExternalAccessPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsExternalAccessPolicy + .SYNOPSIS + (Label) External Access Settings for Microsoft Teams + .DESCRIPTION + (Helptext) Sets the properties of the Global external access policy. + (DocsDescription) Sets the properties of the Global external access policy. External access policies determine whether or not your users can: 1) communicate with users who have Session Initiation Protocol (SIP) accounts with a federated organization; 2) communicate with users who are using custom applications built with Azure Communication Services; 3) access Skype for Business Server over the Internet, without having to log on to your internal network; 4) communicate with users who have SIP accounts with a public instant messaging (IM) provider such as Skype; and, 5) communicate with people who are using Teams with an account that's not managed by an organization. + .NOTES + CAT + Teams Standards + TAG + ADDEDCOMPONENT + {"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 + ADDEDDATE + 2024-07-30 + POWERSHELLEQUIVALENT + Set-CsExternalAccessPolicy + 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 + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsExternalAccessPolicy' + + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsExternalAccessPolicy' -CmdParams @{Identity = 'Global' } + | Select-Object * + + if ($null -eq $Settings.EnableFederationAccess) { $Settings.EnableFederationAccess = $false } + if ($null -eq $Settings.EnablePublicCloudAccess) { $Settings.EnablePublicCloudAccess = $false } + if ($null -eq $Settings.EnableTeamsConsumerAccess) { $Settings.EnableTeamsConsumerAccess = $false } + + $StateIsCorrect = ($CurrentState.EnableFederationAccess -eq $Settings.EnableFederationAccess) -and + ($CurrentState.EnablePublicCloudAccess -eq $Settings.EnablePublicCloudAccess) -and + ($CurrentState.EnableTeamsConsumerAccess -eq $Settings.EnableTeamsConsumerAccess) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'External Access Policy already set.' -sev Info + } else { + $cmdparams = @{ + Identity = 'Global' + EnableFederationAccess = $Settings.EnableFederationAccess + EnablePublicCloudAccess = $Settings.EnablePublicCloudAccess + EnableTeamsConsumerAccess = $Settings.EnableTeamsConsumerAccess + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsExternalAccessPolicy' -CmdParams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated External Access Policy' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set External Access Policy. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'External Access Policy is set correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'External Access Policy is not set correctly.' -sev Alert + } + } + + if ($Setings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TeamsExternalAccessPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 index 1fc934983092..356b514e7eb0 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 @@ -1,86 +1,87 @@ -Function Invoke-CIPPStandardTeamsExternalFileSharing { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) TeamsExternalFileSharing - .SYNOPSIS - (Label) Define approved cloud storage services for external file sharing in Teams - .DESCRIPTION - (Helptext) Ensure external file sharing in Teams is enabled for only approved cloud storage services. - (DocsDescription) Ensure external file sharing in Teams is enabled for only approved cloud storage services. - .NOTES - CAT - Teams Standards - TAG - "lowimpact" - ADDEDCOMPONENT - {"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 - Set-CsTeamsClientConfiguration -AllowGoogleDrive \$false -AllowShareFile \$false -AllowBox \$false -AllowDropBox \$false -AllowEgnyte \$false - RECOMMENDEDBY - "CIS 3.0" - 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) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsExternalFileSharing' - - $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsClientConfiguration' - | Select-Object AllowGoogleDrive, AllowShareFile, AllowBox, AllowDropBox, AllowEgnyte - - if ($null -eq $Settings.AllowGoogleDrive) { $Settings.AllowGoogleDrive = $false } - if ($null -eq $Settings.AllowShareFile) { $Settings.AllowShareFile = $false } - if ($null -eq $Settings.AllowBox) { $Settings.AllowBox = $false } - if ($null -eq $Settings.AllowDropBox) { $Settings.AllowDropBox = $false } - if ($null -eq $Settings.AllowEgnyte) { $Settings.AllowEgnyte = $false } - - $StateIsCorrect = ($CurrentState.AllowGoogleDrive -eq $Settings.AllowGoogleDrive) -and - ($CurrentState.AllowShareFile -eq $Settings.AllowShareFile) -and - ($CurrentState.AllowBox -eq $Settings.AllowBox) -and - ($CurrentState.AllowDropBox -eq $Settings.AllowDropBox) -and - ($CurrentState.AllowEgnyte -eq $Settings.AllowEgnyte) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams External File Sharing already set.' -sev Info - } else { - $cmdparams = @{ - AllowGoogleDrive = $Settings.AllowGoogleDrive - AllowShareFile = $Settings.AllowShareFile - AllowBox = $Settings.AllowBox - AllowDropBox = $Settings.AllowDropBox - AllowEgnyte = $Settings.AllowEgnyte - } - - try { - New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsClientConfiguration' -CmdParams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams External File Sharing' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams External File Sharing. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams External File Sharing is set correctly.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams External File Sharing is not set correctly.' -sev Alert - } - } - - if ($Setings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TeamsExternalFileSharing' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +Function Invoke-CIPPStandardTeamsExternalFileSharing { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsExternalFileSharing + .SYNOPSIS + (Label) Define approved cloud storage services for external file sharing in Teams + .DESCRIPTION + (Helptext) Ensure external file sharing in Teams is enabled for only approved cloud storage services. + (DocsDescription) Ensure external file sharing in Teams is enabled for only approved cloud storage services. + .NOTES + CAT + Teams Standards + TAG + ADDEDCOMPONENT + {"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 + ADDEDDATE + 2024-07-28 + POWERSHELLEQUIVALENT + Set-CsTeamsClientConfiguration -AllowGoogleDrive \$false -AllowShareFile \$false -AllowBox \$false -AllowDropBox \$false -AllowEgnyte \$false + RECOMMENDEDBY + "CIS 3.0" + 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) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsExternalFileSharing' + + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsClientConfiguration' + | Select-Object AllowGoogleDrive, AllowShareFile, AllowBox, AllowDropBox, AllowEgnyte + + if ($null -eq $Settings.AllowGoogleDrive) { $Settings.AllowGoogleDrive = $false } + if ($null -eq $Settings.AllowShareFile) { $Settings.AllowShareFile = $false } + if ($null -eq $Settings.AllowBox) { $Settings.AllowBox = $false } + if ($null -eq $Settings.AllowDropBox) { $Settings.AllowDropBox = $false } + if ($null -eq $Settings.AllowEgnyte) { $Settings.AllowEgnyte = $false } + + $StateIsCorrect = ($CurrentState.AllowGoogleDrive -eq $Settings.AllowGoogleDrive) -and + ($CurrentState.AllowShareFile -eq $Settings.AllowShareFile) -and + ($CurrentState.AllowBox -eq $Settings.AllowBox) -and + ($CurrentState.AllowDropBox -eq $Settings.AllowDropBox) -and + ($CurrentState.AllowEgnyte -eq $Settings.AllowEgnyte) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams External File Sharing already set.' -sev Info + } else { + $cmdparams = @{ + AllowGoogleDrive = $Settings.AllowGoogleDrive + AllowShareFile = $Settings.AllowShareFile + AllowBox = $Settings.AllowBox + AllowDropBox = $Settings.AllowDropBox + AllowEgnyte = $Settings.AllowEgnyte + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsClientConfiguration' -CmdParams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams External File Sharing' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams External File Sharing. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams External File Sharing is set correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams External File Sharing is not set correctly.' -sev Alert + } + } + + if ($Setings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TeamsExternalFileSharing' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 index aea9e7a3e6b0..a17b92451ff6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 @@ -1,117 +1,119 @@ -Function Invoke-CIPPStandardTeamsFederationConfiguration { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) TeamsFederationConfiguration - .SYNOPSIS - (Label) Federation Configuration for Microsoft Teams - .DESCRIPTION - (Helptext) Sets the properties of the Global federation configuration. - (DocsDescription) Sets the properties of the Global federation configuration. Federation configuration settings determine whether or not your users can communicate with users who have SIP accounts with a federated organization. - .NOTES - CAT - Teams Standards - TAG - "mediumimpact" - ADDEDCOMPONENT - {"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 - Set-CsTenantFederationConfiguration - 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 - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsFederationConfiguration' - - $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTenantFederationConfiguration' -CmdParams @{Identity = 'Global' } - | Select-Object * - - Switch ($Settings.DomainControl.value) { - 'AllowAllExternal' { - $AllowFederatedUsers = $true - $AllowedDomainsAsAList = 'AllowAllKnownDomains' - $BlockedDomains = @() - } - 'BlockAllExternal' { - $AllowFederatedUsers = $false - $AllowedDomainsAsAList = 'AllowAllKnownDomains' - $BlockedDomains = @() - } - 'AllowSpecificExternal' { - $AllowFederatedUsers = $true - $BlockedDomains = @() - if ($null -ne $Settings.DomainList) { - $AllowedDomainsAsAList = @($Settings.DomainList).Split(',').Trim() - } else { - $AllowedDomainsAsAList = @() - } - } - 'BlockSpecificExternal' { - $AllowFederatedUsers = $true - $AllowedDomainsAsAList = 'AllowAllKnownDomains' - if ($null -ne $Settings.DomainList) { - $BlockedDomains = @($Settings.DomainList).Split(',').Trim() - } else { - $BlockedDomains = @() - } - } - Default { - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Federation Configuration: Invalid $($Settings.DomainControl.value) parameter" -sev Error - Return - } - } - - # TODO : Add proper validation for the domain list - # $CurrentState.AllowedDomains returns a PSObject System.Object and adds a Domain= for each allowed domain, ex {Domain=example.com, Domain=example2.com} - - $StateIsCorrect = ($CurrentState.AllowTeamsConsumer -eq $Settings.AllowTeamsConsumer) -and - ($CurrentState.AllowPublicUsers -eq $Settings.AllowPublicUsers) -and - ($CurrentState.AllowFederatedUsers -eq $AllowFederatedUsers) -and - ($CurrentState.AllowedDomains -eq $AllowedDomainsAsAList) -and - ($CurrentState.BlockedDomains -eq $BlockedDomains) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Federation Configuration already set.' -sev Info - } else { - $cmdparams = @{ - Identity = 'Global' - AllowTeamsConsumer = $Settings.AllowTeamsConsumer - AllowPublicUsers = $Settings.AllowPublicUsers - AllowFederatedUsers = $AllowFederatedUsers - AllowedDomainsAsAList = $AllowedDomainsAsAList - BlockedDomains = $BlockedDomains - } - - try { - New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTenantFederationConfiguration' -CmdParams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Federation Configuration Policy' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Federation Configuration Policy. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Federation Configuration is set correctly.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Federation Configuration is not set correctly.' -sev Alert - } - } - - if ($Setings.report -eq $true) { - Add-CIPPBPAField -FieldName 'FederationConfiguration' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +Function Invoke-CIPPStandardTeamsFederationConfiguration { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsFederationConfiguration + .SYNOPSIS + (Label) Federation Configuration for Microsoft Teams + .DESCRIPTION + (Helptext) Sets the properties of the Global federation configuration. + (DocsDescription) Sets the properties of the Global federation configuration. Federation configuration settings determine whether or not your users can communicate with users who have SIP accounts with a federated organization. + .NOTES + CAT + Teams Standards + TAG + ADDEDCOMPONENT + {"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","required":true,"multiple":false,"creatable":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 + ADDEDDATE + 2024-07-31 + POWERSHELLEQUIVALENT + Set-CsTenantFederationConfiguration + 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 + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsFederationConfiguration' + + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTenantFederationConfiguration' -CmdParams @{Identity = 'Global' } + | Select-Object * + + $DomainControl = $Settings.DomainControl.value ?? $Settings.DomainControl + Switch ($DomainControl) { + 'AllowAllExternal' { + $AllowFederatedUsers = $true + $AllowedDomainsAsAList = 'AllowAllKnownDomains' + $BlockedDomains = @() + } + 'BlockAllExternal' { + $AllowFederatedUsers = $false + $AllowedDomainsAsAList = 'AllowAllKnownDomains' + $BlockedDomains = @() + } + 'AllowSpecificExternal' { + $AllowFederatedUsers = $true + $BlockedDomains = @() + if ($null -ne $Settings.DomainList) { + $AllowedDomainsAsAList = @($Settings.DomainList).Split(',').Trim() + } else { + $AllowedDomainsAsAList = @() + } + } + 'BlockSpecificExternal' { + $AllowFederatedUsers = $true + $AllowedDomainsAsAList = 'AllowAllKnownDomains' + if ($null -ne $Settings.DomainList) { + $BlockedDomains = @($Settings.DomainList).Split(',').Trim() + } else { + $BlockedDomains = @() + } + } + Default { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Federation Configuration: Invalid $DomainControl parameter" -sev Error + Return + } + } + + # TODO : Add proper validation for the domain list + # $CurrentState.AllowedDomains returns a PSObject System.Object and adds a Domain= for each allowed domain, ex {Domain=example.com, Domain=example2.com} + + $StateIsCorrect = ($CurrentState.AllowTeamsConsumer -eq $Settings.AllowTeamsConsumer) -and + ($CurrentState.AllowPublicUsers -eq $Settings.AllowPublicUsers) -and + ($CurrentState.AllowFederatedUsers -eq $AllowFederatedUsers) -and + ($CurrentState.AllowedDomains -eq $AllowedDomainsAsAList) -and + ($CurrentState.BlockedDomains -eq $BlockedDomains) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Federation Configuration already set.' -sev Info + } else { + $cmdparams = @{ + Identity = 'Global' + AllowTeamsConsumer = $Settings.AllowTeamsConsumer + AllowPublicUsers = $Settings.AllowPublicUsers + AllowFederatedUsers = $AllowFederatedUsers + AllowedDomainsAsAList = $AllowedDomainsAsAList + BlockedDomains = $BlockedDomains + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTenantFederationConfiguration' -CmdParams $cmdparams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Federation Configuration Policy' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Federation Configuration Policy. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Federation Configuration is set correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Federation Configuration is not set correctly.' -sev Alert + } + } + + if ($Setings.report -eq $true) { + Add-CIPPBPAField -FieldName 'FederationConfiguration' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 index 4d0cfd8ff359..e0c747739a8e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 @@ -1,82 +1,88 @@ -Function Invoke-CIPPStandardTeamsGlobalMeetingPolicy { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) TeamsGlobalMeetingPolicy - .SYNOPSIS - (Label) Define Global Meeting Policy for Teams - .DESCRIPTION - (Helptext) Defines the CIS recommended global meeting policy for Teams. This includes AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl - (DocsDescription) Defines the CIS recommended global meeting policy for Teams. This includes AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl - .NOTES - CAT - Teams Standards - TAG - "lowimpact" - ADDEDCOMPONENT - {"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 - Set-CsTeamsMeetingPolicy -AllowAnonymousUsersToJoinMeeting \$false -AllowAnonymousUsersToStartMeeting \$false -AutoAdmittedUsers EveryoneInCompanyExcludingGuests -AllowPSTNUsersToBypassLobby \$false -MeetingChatEnabledType EnabledExceptAnonymous -DesignatedPresenterRoleMode \$DesignatedPresenterRoleMode -AllowExternalParticipantGiveRequestControl \$false - RECOMMENDEDBY - "CIS 3.0" - 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 - #> - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsGlobalMeetingPolicy' - - param($Tenant, $Settings) - $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsMeetingPolicy' -CmdParams @{Identity = 'Global' } - | Select-Object AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl - - $StateIsCorrect = ($CurrentState.AllowAnonymousUsersToJoinMeeting -eq $Settings.AllowAnonymousUsersToJoinMeeting) -and - ($CurrentState.AllowAnonymousUsersToStartMeeting -eq $false) -and - ($CurrentState.AutoAdmittedUsers -eq 'EveryoneInCompanyExcludingGuests') -and - ($CurrentState.AllowPSTNUsersToBypassLobby -eq $false) -and - ($CurrentState.MeetingChatEnabledType -eq $Settings.MeetingChatEnabledType.value) -and - ($CurrentState.DesignatedPresenterRoleMode -eq $Settings.DesignatedPresenterRoleMode.value) -and - ($CurrentState.AllowExternalParticipantGiveRequestControl -eq $false) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Global Policy already set.' -sev Info - } else { - $cmdparams = @{ - Identity = 'Global' - AllowAnonymousUsersToJoinMeeting = $Settings.AllowAnonymousUsersToJoinMeeting - AllowAnonymousUsersToStartMeeting = $false - AutoAdmittedUsers = 'EveryoneInCompanyExcludingGuests' - AllowPSTNUsersToBypassLobby = $false - MeetingChatEnabledType = $Settings.MeetingChatEnabledType.value - DesignatedPresenterRoleMode = $Settings.DesignatedPresenterRoleMode.value - AllowExternalParticipantGiveRequestControl = $false - } - - try { - New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsMeetingPolicy' -CmdParams $cmdparams - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams Global Policy' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Global Policy. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Global Policy is set correctly.' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Global Policy is not set correctly.' -sev Alert - } - } - - if ($Setings.report -eq $true) { - Add-CIPPBPAField -FieldName 'TeamsGlobalMeetingPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant - } -} +Function Invoke-CIPPStandardTeamsGlobalMeetingPolicy { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsGlobalMeetingPolicy + .SYNOPSIS + (Label) Define Global Meeting Policy for Teams + .DESCRIPTION + (Helptext) Defines the CIS recommended global meeting policy for Teams. This includes AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl + (DocsDescription) Defines the CIS recommended global meeting policy for Teams. This includes AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl + .NOTES + CAT + Teams Standards + TAG + ADDEDCOMPONENT + {"type":"autoComplete","required":true,"multiple":false,"creatable":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","required":true,"multiple":false,"creatable":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"}]} + {"type":"switch","name":"standards.TeamsGlobalMeetingPolicy.AllowExternalParticipantGiveRequestControl","label":"External participants can give or request control"} + IMPACT + Low Impact + ADDEDDATE + 2024-11-12 + POWERSHELLEQUIVALENT + Set-CsTeamsMeetingPolicy -AllowAnonymousUsersToJoinMeeting \$false -AllowAnonymousUsersToStartMeeting \$false -AutoAdmittedUsers EveryoneInCompanyExcludingGuests -AllowPSTNUsersToBypassLobby \$false -MeetingChatEnabledType EnabledExceptAnonymous -DesignatedPresenterRoleMode \$DesignatedPresenterRoleMode -AllowExternalParticipantGiveRequestControl \$false + RECOMMENDEDBY + "CIS 3.0" + 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 + #> + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsGlobalMeetingPolicy' + + param($Tenant, $Settings) + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsMeetingPolicy' -CmdParams @{Identity = 'Global' } + | Select-Object AllowAnonymousUsersToJoinMeeting, AllowAnonymousUsersToStartMeeting, AutoAdmittedUsers, AllowPSTNUsersToBypassLobby, MeetingChatEnabledType, DesignatedPresenterRoleMode, AllowExternalParticipantGiveRequestControl + + $MeetingChatEnabledType = $Settings.MeetingChatEnabledType.value ?? $Settings.MeetingChatEnabledType + $DesignatedPresenterRoleMode = $Settings.DesignatedPresenterRoleMode.value ?? $Settings.DesignatedPresenterRoleMode + + $StateIsCorrect = ($CurrentState.AllowAnonymousUsersToJoinMeeting -eq $Settings.AllowAnonymousUsersToJoinMeeting) -and + ($CurrentState.AllowAnonymousUsersToStartMeeting -eq $false) -and + ($CurrentState.AutoAdmittedUsers -eq 'EveryoneInCompanyExcludingGuests') -and + ($CurrentState.AllowPSTNUsersToBypassLobby -eq $false) -and + ($CurrentState.MeetingChatEnabledType -eq $MeetingChatEnabledType) -and + ($CurrentState.DesignatedPresenterRoleMode -eq $DesignatedPresenterRoleMode) -and + ($CurrentState.AllowExternalParticipantGiveRequestControl -eq $false) + + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Global Policy already set.' -sev Info + } else { + $cmdParams = @{ + Identity = 'Global' + AllowAnonymousUsersToJoinMeeting = $Settings.AllowAnonymousUsersToJoinMeeting + AllowAnonymousUsersToStartMeeting = $false + AutoAdmittedUsers = 'EveryoneInCompanyExcludingGuests' + AllowPSTNUsersToBypassLobby = $false + MeetingChatEnabledType = $MeetingChatEnabledType + DesignatedPresenterRoleMode = $DesignatedPresenterRoleMode + AllowExternalParticipantGiveRequestControl = $Settings.AllowExternalParticipantGiveRequestControl + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsMeetingPolicy' -CmdParams $cmdParams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams Global Policy' -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Global Policy. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Global Policy is set correctly.' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Global Policy is not set correctly.' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'TeamsGlobalMeetingPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 6c14e3df7ebf..c23c34f9ed9e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -13,11 +13,12 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { CAT Exchange Standards TAG - "lowimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.TeamsMeetingsByDefault.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} + {"type":"autoComplete","multiple":false,"label":"Select value","name":"standards.TeamsMeetingsByDefault.state","options":[{"label":"Enabled","value":"true"},{"label":"Disabled","value":"false"}]} IMPACT Low Impact + ADDEDDATE + 2024-05-31 POWERSHELLEQUIVALENT Set-OrganizationConfig -OnlineMeetingsByDefaultEnabled RECOMMENDEDBY @@ -30,19 +31,22 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'TeamsMeetingsByDefault' + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + $CurrentState = (New-ExoRequest -tenantid $Tenant -cmdlet 'Get-OrganizationConfig').OnlineMeetingsByDefaultEnabled - $WantedState = if ($Settings.state -eq 'true') { $true } else { $false } + $WantedState = if ($state -eq 'true') { $true } else { $false } $StateIsCorrect = if ($CurrentState -eq $WantedState) { $true } else { $false } if ($Settings.report -eq $true) { # Default is not set, not set means it's enabled if ($null -eq $CurrentState ) { $CurrentState = $true } - Add-CIPPBPAField -FieldName 'TeamsMeetingsByDefault' -FieldValue $CurrentState -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'TeamsMeetingsByDefault' -FieldValue $CurrentState -StoreAs bool -Tenant $Tenant } # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.state) -or $Settings.state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'TeamsMeetingsByDefault: Invalid state parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($state) -or $state -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'TeamsMeetingsByDefault: Invalid state parameter set' -sev Error Return } @@ -50,23 +54,23 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { Write-Host 'Time to remediate' if ($StateIsCorrect -eq $false) { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ OnlineMeetingsByDefaultEnabled = $WantedState } -useSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "Successfully set the tenant TeamsMeetingsByDefault state to $($Settings.state)" -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-OrganizationConfig' -cmdParams @{ OnlineMeetingsByDefaultEnabled = $WantedState } -useSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Successfully set the tenant TeamsMeetingsByDefault state to $state" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set the tenant TeamsMeetingsByDefault state to $($Settings.state). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set the tenant TeamsMeetingsByDefault state to $state. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant TeamsMeetingsByDefault state is already set correctly to $($Settings.state)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant TeamsMeetingsByDefault state is already set correctly to $state" -sev Info } } if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant TeamsMeetingsByDefault is set correctly to $($Settings.state)" -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant TeamsMeetingsByDefault is set correctly to $state" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant TeamsMeetingsByDefault is not set correctly to $($Settings.state)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "The tenant TeamsMeetingsByDefault is not set correctly to $state" -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 index 14f3c3660d12..ca5c223d8ecc 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 @@ -1,99 +1,102 @@ -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.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.value) -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.value - 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 - } -} +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 + ADDEDCOMPONENT + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowOwnerDeleteMessage","label":"Allow Owner to Delete Messages","defaultValue":false} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowUserDeleteMessage","label":"Allow User to Delete Messages","defaultValue":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowUserEditMessage","label":"Allow User to Edit Messages","defaultValue":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowUserDeleteChat","label":"Allow User to Delete Chats","defaultValue":true} + {"type":"autoComplete","required":true,"multiple":false,"creatable":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","defaultValue":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.DeleteCustomEmojis","label":"Allow Deleting Custom Emojis","defaultValue":false} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowSecurityEndUserReporting","label":"Allow reporting message as security concern","defaultValue":true} + {"type":"switch","name":"standards.TeamsMessagingPolicy.AllowCommunicationComplianceEndUserReporting","label":"Allow reporting message as inappropriate content","defaultValue":true} + IMPACT + Medium Impact + ADDEDDATE + 2025-01-10 + 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.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 } + + $ReadReceiptsEnabledType = $Settings.ReadReceiptsEnabledType.value ?? $Settings.ReadReceiptsEnabledType + + $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 $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 = $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 73b7d7e97614..a65dd264850d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 @@ -13,13 +13,14 @@ function Invoke-CIPPStandardTenantDefaultTimezone { CAT SharePoint Standards TAG - "lowimpact" ADDEDCOMPONENT {"type":"TimezoneSelect","name":"standards.TenantDefaultTimezone.Timezone","label":"Timezone"} IMPACT Low Impact + ADDEDDATE + 2024-04-20 POWERSHELLEQUIVALENT - Update-MgBetaAdminSharepointSetting + Update-MgBetaAdminSharePointSetting RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 index ad965f1d28d5..d7dd378a2562 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 @@ -13,9 +13,11 @@ function Invoke-CIPPStandardTransportRuleTemplate { CAT Templates DISABLEDFEATURES - + IMPACT - Medium + Medium Impact + ADDEDDATE + 2023-12-30 ADDEDCOMPONENT {"type":"autoComplete","name":"transportRuleTemplate","label":"Select Transport Rule Template","api":{"url":"/api/ListTransportRulesTemplates","labelField":"name","valueField":"GUID","queryKey":"ListTransportRulesTemplates"}} UPDATECOMMENTBLOCK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 index 333de3e01992..4840372a6166 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUndoOauth.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardUndoOauth { CAT Entra (AAD) Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2022-01-07 POWERSHELLEQUIVALENT Update-MgPolicyAuthorizationPolicy RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserPreferredLanguage.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserPreferredLanguage.ps1 new file mode 100644 index 000000000000..77784c0524bb --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserPreferredLanguage.ps1 @@ -0,0 +1,71 @@ +function Invoke-CIPPStandardUserPreferredLanguage { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) UserPreferredLanguage + .SYNOPSIS + (Label) Preferred language for all users + .DESCRIPTION + (Helptext) Sets the preferred language property for all users in the tenant. This will override the user's language settings. + (DocsDescription) Sets the preferred language property for all users in the tenant. This will override the user's language settings. + .NOTES + CAT + Entra (AAD) Standards + TAG + ADDEDCOMPONENT + {"type":"autoComplete","multiple":false,"creatable":false,"name":"standards.UserPreferredLanguage.preferredLanguage","label":"Preferred Language","api":{"url":"/languageList.json","labelField":"language","valueField":"tag"}} + IMPACT + High Impact + ADDEDDATE + 2025-02-26 + POWERSHELLEQUIVALENT + Update-MgUser -UserId user@domain.com -BodyParameter @{preferredLanguage='en-US'} + 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) + + $preferredLanguage = $Settings.preferredLanguage.value + $IncorrectUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=userPrincipalName,displayName,preferredLanguage,userType,onPremisesSyncEnabled&`$filter=preferredLanguage ne '$preferredLanguage' and userType eq 'Member' and onPremisesSyncEnabled ne true&`$count=true&ConsistencyLevel=eventual" -tenantid $Tenant + + If ($Settings.remediate -eq $true) { + if (($IncorrectUsers | Measure-Object).Count -gt 0) { + try { + ForEach ($user in $IncorrectUsers) { + $cmdparams = @{ + tenantid = $Tenant + uri = "https://graph.microsoft.com/beta/users/$($user.userPrincipalName)" + AsApp = $true + Type = 'PATCH' + Body = @{ + preferredLanguage = $preferredLanguage + } | ConvertTo-Json + ContentType = 'application/json; charset=utf-8' + } + $null = New-GraphPOSTRequest @cmdparams + Write-LogMessage -API 'Standards' -tenant $tenant -message "Preferred language for $($user.userPrincipalName) has been set to $preferredLanguage" -sev Info + } + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set preferred language to $preferredLanguage for all users." -sev Error -LogData $ErrorMessage + } + } + } + + If ($Settings.alert -eq $true) { + if (($IncorrectUsers.userPrincipalName | Measure-Object).Count -gt 0) { + Write-LogMessage -API 'Standards' -tenant $tenant -message "The following accounts do not have the preferred language set to $preferredLanguage : $($IncorrectUsers.userPrincipalName -join ', ')" -sev Alert + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'No accounts do not have the preferred language set to the preferred language' -sev Info + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'IncorrectUsers' -FieldValue $IncorrectUsers -StoreAs json -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index 265d37507f8b..aac6b135b896 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardUserSubmissions { CAT Exchange Standards TAG - "mediumimpact" ADDEDCOMPONENT - {"type":"select","multiple":false,"label":"Select value","name":"standards.UserSubmissions.state","options":[{"label":"Enabled","value":"enable"},{"label":"Disabled","value":"disable"}]} + {"type":"autoComplete","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 + ADDEDDATE + 2024-06-28 POWERSHELLEQUIVALENT New-ReportSubmissionPolicy or Set-ReportSubmissionPolicy and New-ReportSubmissionRule or Set-ReportSubmissionRule RECOMMENDEDBY @@ -31,16 +32,19 @@ function Invoke-CIPPStandardUserSubmissions { param($Tenant, $Settings) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'UserSubmissions' + # Get state value using null-coalescing operator + $state = $Settings.state.value ?? $Settings.state + # Input validation if ($Settings.remediate -eq $true -or $Settings.alert -eq $true) { - if (!($Settings.state -eq 'enable' -or $Settings.state -eq 'disable')) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'UserSubmissions: Invalid state parameter set' -sev Error + if (!($state -eq 'enable' -or $state -eq 'disable')) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'UserSubmissions: Invalid state parameter set' -sev Error Return } if (!([string]::IsNullOrWhiteSpace($Settings.email))) { if ($Settings.email -notmatch '@') { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'UserSubmissions: Invalid Email parameter set' -sev Error + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'UserSubmissions: Invalid Email parameter set' -sev Error Return } } @@ -65,7 +69,7 @@ function Invoke-CIPPStandardUserSubmissions { ($PolicyState.ReportPhishToCustomizedAddress -eq $true) -and ($PolicyState.ReportPhishAddresses -eq $Settings.email) $RuleIsCorrect = ($RuleState.State -eq 'Enabled') -and - ($RuleSteate.SentTo -eq $Settings.email) + ($RuleState.SentTo -eq $Settings.email) } } else { if ($PolicyState.length -eq 0) { @@ -85,9 +89,9 @@ function Invoke-CIPPStandardUserSubmissions { if ($Settings.report -eq $true) { if ($PolicyState.length -eq 0) { - Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $false -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $false -StoreAs bool -Tenant $Tenant } else { - Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant + Add-CIPPBPAField -FieldName 'UserSubmissionPolicy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant } } @@ -97,13 +101,16 @@ function Invoke-CIPPStandardUserSubmissions { if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission policy is already configured' -sev Info } else { - if ($Settings.state -eq 'enable') { + if ($state -eq 'enable') { if (([string]::IsNullOrWhiteSpace($Settings.email))) { $PolicyParams = @{ EnableReportToMicrosoft = $true ReportJunkToCustomizedAddress = $false + ReportJunkAddresses = $null ReportNotJunkToCustomizedAddress = $false + ReportNotJunkAddresses = $null ReportPhishToCustomizedAddress = $false + ReportPhishAddresses = $null } } else { $PolicyParams = @{ @@ -130,20 +137,20 @@ function Invoke-CIPPStandardUserSubmissions { if ($PolicyState.length -eq 0) { try { - New-ExoRequest -tenantid $Tenant -cmdlet 'New-ReportSubmissionPolicy' -cmdparams $PolicyParams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message 'User Submission policy created.' -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'New-ReportSubmissionPolicy' -cmdParams $PolicyParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission policy created.' -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create User Submission policy. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create User Submission policy. Error: $($ErrorMessage.NormalizedError)" -sev Error } } else { try { $PolicyParams.Add('Identity', 'DefaultReportSubmissionPolicy') - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-ReportSubmissionPolicy' -cmdParams $PolicyParams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message "User Submission policy state set to $($Settings.state)." -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-ReportSubmissionPolicy' -cmdParams $PolicyParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message "User Submission policy state set to $state." -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set User Submission policy state to $($Settings.state). Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set User Submission policy state to $state. Error: $($ErrorMessage.NormalizedError)" -sev Error } } @@ -152,20 +159,20 @@ function Invoke-CIPPStandardUserSubmissions { try { $RuleParams.Add('Name', 'DefaultReportSubmissionRule') $RuleParams.Add('ReportSubmissionPolicy', 'DefaultReportSubmissionPolicy') - New-ExoRequest -tenantid $Tenant -cmdlet 'New-ReportSubmissionRule' -cmdparams $RuleParams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message 'User Submission rule created.' -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'New-ReportSubmissionRule' -cmdParams $RuleParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission rule created.' -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create User Submission rule. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to create User Submission rule. Error: $($ErrorMessage.NormalizedError)" -sev Error } } else { try { $RuleParams.Add('Identity', 'DefaultReportSubmissionRule') - New-ExoRequest -tenantid $Tenant -cmdlet 'Set-ReportSubmissionRule' -cmdParams $RuleParams -UseSystemMailbox $true - Write-LogMessage -API 'Standards' -tenant $tenant -message 'User Submission rule set to enabled.' -sev Info + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Set-ReportSubmissionRule' -cmdParams $RuleParams -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission rule set to enabled.' -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to enable User Submission rule. Error: $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to enable User Submission rule. Error: $($ErrorMessage.NormalizedError)" -sev Error } } } @@ -175,12 +182,12 @@ function Invoke-CIPPStandardUserSubmissions { if ($Settings.alert -eq $true) { if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'User Submission policy is properly configured.' -sev Info + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission policy is properly configured.' -sev Info } else { if ($Policy.EnableReportToMicrosoft -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'User Submission policy is enabled but incorrectly configured' -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission policy is enabled but incorrectly configured' -sev Alert } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'User Submission policy is disabled.' -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission policy is disabled.' -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 index b621e3e85ea6..6b0cc1e1641d 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOAuthTokens.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardallowOAuthTokens { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2022-12-18 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 index fb07572ffb32..99383d1356ed 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardallowOTPTokens.ps1 @@ -13,10 +13,11 @@ function Invoke-CIPPStandardallowOTPTokens { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2023-12-06 POWERSHELLEQUIVALENT Update-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 index cbb3e14e1329..908e76feb7d7 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 @@ -13,13 +13,14 @@ function Invoke-CIPPStandardcalDefault { CAT Exchange Standards TAG - "lowimpact" DISABLEDFEATURES ADDEDCOMPONENT - {"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"}]} + {"type":"autoComplete","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 + ADDEDDATE + 2023-04-27 POWERSHELLEQUIVALENT Set-MailboxFolderPermission RECOMMENDEDBY @@ -32,9 +33,11 @@ function Invoke-CIPPStandardcalDefault { param($Tenant, $Settings, $QueueItem) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'calDefault' + # Get permissionlevel value using null-coalescing operator + $permissionLevel = $Settings.permissionlevel.value ?? $Settings.permissionlevel + # Input validation - $Settings.permissionlevel = $Settings.permissionlevel.value ? $Settings.permissionlevel.value : $Settings.permissionlevel - if ([string]::IsNullOrWhiteSpace($Settings.permissionlevel) -or $Settings.permissionlevel -eq 'Select a value') { + if ([string]::IsNullOrWhiteSpace($permissionLevel) -or $permissionLevel -eq 'Select a value') { Write-LogMessage -API 'Standards' -tenant $tenant -message 'calDefault: Invalid permissionlevel parameter set' -sev Error Return } @@ -66,18 +69,18 @@ function Invoke-CIPPStandardcalDefault { 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 + New-ExoRequest -tenantid $Tenant -cmdlet 'Set-MailboxFolderPermission' -cmdParams @{Identity = "$($Mailbox.UserPrincipalName):$($_.FolderId)"; User = 'Default'; AccessRights = $permissionLevel } -Anchor $Mailbox.UserPrincipalName + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set default folder permission for $($Mailbox.UserPrincipalName):\$($_.Name) to $permissionLevel" -sev Debug $SuccessCounter++ } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + $ErrorMessage = Get-CippException -Exception $_ 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 + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } } 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 + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Could not set default calendar permissions for $($Mailbox.UserPrincipalName). Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } $processedMailboxes++ if ($processedMailboxes % 25 -eq 0) { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 index dc6b2184a4d5..bfa15dd5d440 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandarddisableMacSync { CAT SharePoint Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgAdminSharepointSetting + Update-MgAdminSharePointSetting RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 index 420f3c11498f..ac60619aef3e 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 @@ -1,101 +1,102 @@ -function Invoke-CIPPStandardintuneBrandingProfile { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) intuneBrandingProfile - .SYNOPSIS - (Label) Set Intune Company Portal branding profile - .DESCRIPTION - (Helptext) Sets the branding profile for the Intune Company Portal app. This is a tenant wide setting and overrules any settings set on the app level. - (DocsDescription) Sets the branding profile for the Intune Company Portal app. This is a tenant wide setting and overrules any settings set on the app level. - .NOTES - CAT - Intune Standards - TAG - "lowimpact" - ADDEDCOMPONENT - {"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 - 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/intune-standards#low-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'intuneBrandingProfile' - - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/intuneBrandingProfiles/c3a59481-1bf2-46ce-94b3-66eec07a8d60/' -tenantid $Tenant -AsApp $true - - $StateIsCorrect = ((-not $Settings.displayName) -or ($CurrentState.displayName -eq $Settings.displayName)) -and - ((-not $Settings.showLogo) -or ($CurrentState.showLogo -eq $Settings.showLogo)) -and - ((-not $Settings.showDisplayNameNextToLogo) -or ($CurrentState.showDisplayNameNextToLogo -eq $Settings.showDisplayNameNextToLogo)) -and - ((-not $Settings.contactITName) -or ($CurrentState.contactITName -eq $Settings.contactITName)) -and - ((-not $Settings.contactITPhoneNumber) -or ($CurrentState.contactITPhoneNumber -eq $Settings.contactITPhoneNumber)) -and - ((-not $Settings.contactITEmailAddress) -or ($CurrentState.contactITEmailAddress -eq $Settings.contactITEmailAddress)) -and - ((-not $Settings.contactITNotes) -or ($CurrentState.contactITNotes -eq $Settings.contactITNotes)) -and - ((-not $Settings.onlineSupportSiteName) -or ($CurrentState.onlineSupportSiteName -eq $Settings.onlineSupportSiteName)) -and - ((-not $Settings.onlineSupportSiteUrl) -or ($CurrentState.onlineSupportSiteUrl -eq $Settings.onlineSupportSiteUrl)) -and - ((-not $Settings.privacyUrl) -or ($CurrentState.privacyUrl -eq $Settings.privacyUrl)) - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is already correctly configured' -sev Info - } else { - $Body = @{} - if ($Settings.displayName) { $Body.displayName = $Settings.displayName } - if ($Settings.showLogo) { $Body.showLogo = $Settings.showLogo } - if ($Settings.showDisplayNameNextToLogo) { $Body.showDisplayNameNextToLogo = $Settings.showDisplayNameNextToLogo } - if ($Settings.contactITName) { $Body.contactITName = $Settings.contactITName } - if ($Settings.contactITPhoneNumber) { $Body.contactITPhoneNumber = $Settings.contactITPhoneNumber } - if ($Settings.contactITEmailAddress) { $Body.contactITEmailAddress = $Settings.contactITEmailAddress } - if ($Settings.contactITNotes) { $Body.contactITNotes = $Settings.contactITNotes } - if ($Settings.onlineSupportSiteName) { $Body.onlineSupportSiteName = $Settings.onlineSupportSiteName } - if ($Settings.onlineSupportSiteUrl) { $Body.onlineSupportSiteUrl = $Settings.onlineSupportSiteUrl } - if ($Settings.privacyUrl) { $Body.privacyUrl = $Settings.privacyUrl } - - $cmdparams = @{ - tenantid = $tenant - uri = 'https://graph.microsoft.com/beta/deviceManagement/intuneBrandingProfiles/c3a59481-1bf2-46ce-94b3-66eec07a8d60/' - AsApp = $true - Type = 'PATCH' - Body = ($Body | ConvertTo-Json) - ContentType = 'application/json; charset=utf-8' - } - - try { - New-GraphPostRequest @cmdparams - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully updated Intune Branding Profile' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to update Intune Branding Profile. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is correctly configured' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is not correctly configured' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'intuneBrandingProfile' -FieldValue [bool]$StateIsCorrect -StoreAs bool -Tenant $tenant - } -} +function Invoke-CIPPStandardintuneBrandingProfile { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) intuneBrandingProfile + .SYNOPSIS + (Label) Set Intune Company Portal branding profile + .DESCRIPTION + (Helptext) Sets the branding profile for the Intune Company Portal app. This is a tenant wide setting and overrules any settings set on the app level. + (DocsDescription) Sets the branding profile for the Intune Company Portal app. This is a tenant wide setting and overrules any settings set on the app level. + .NOTES + CAT + Intune Standards + TAG + ADDEDCOMPONENT + {"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 + ADDEDDATE + 2024-06-20 + POWERSHELLEQUIVALENT + 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/intune-standards#low-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'intuneBrandingProfile' + + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/intuneBrandingProfiles/c3a59481-1bf2-46ce-94b3-66eec07a8d60/' -tenantid $Tenant -AsApp $true + + $StateIsCorrect = ((-not $Settings.displayName) -or ($CurrentState.displayName -eq $Settings.displayName)) -and + ((-not $Settings.showLogo) -or ($CurrentState.showLogo -eq $Settings.showLogo)) -and + ((-not $Settings.showDisplayNameNextToLogo) -or ($CurrentState.showDisplayNameNextToLogo -eq $Settings.showDisplayNameNextToLogo)) -and + ((-not $Settings.contactITName) -or ($CurrentState.contactITName -eq $Settings.contactITName)) -and + ((-not $Settings.contactITPhoneNumber) -or ($CurrentState.contactITPhoneNumber -eq $Settings.contactITPhoneNumber)) -and + ((-not $Settings.contactITEmailAddress) -or ($CurrentState.contactITEmailAddress -eq $Settings.contactITEmailAddress)) -and + ((-not $Settings.contactITNotes) -or ($CurrentState.contactITNotes -eq $Settings.contactITNotes)) -and + ((-not $Settings.onlineSupportSiteName) -or ($CurrentState.onlineSupportSiteName -eq $Settings.onlineSupportSiteName)) -and + ((-not $Settings.onlineSupportSiteUrl) -or ($CurrentState.onlineSupportSiteUrl -eq $Settings.onlineSupportSiteUrl)) -and + ((-not $Settings.privacyUrl) -or ($CurrentState.privacyUrl -eq $Settings.privacyUrl)) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is already correctly configured' -sev Info + } else { + $Body = @{} + if ($Settings.displayName) { $Body.displayName = $Settings.displayName } + if ($Settings.showLogo) { $Body.showLogo = $Settings.showLogo } + if ($Settings.showDisplayNameNextToLogo) { $Body.showDisplayNameNextToLogo = $Settings.showDisplayNameNextToLogo } + if ($Settings.contactITName) { $Body.contactITName = $Settings.contactITName } + if ($Settings.contactITPhoneNumber) { $Body.contactITPhoneNumber = $Settings.contactITPhoneNumber } + if ($Settings.contactITEmailAddress) { $Body.contactITEmailAddress = $Settings.contactITEmailAddress } + if ($Settings.contactITNotes) { $Body.contactITNotes = $Settings.contactITNotes } + if ($Settings.onlineSupportSiteName) { $Body.onlineSupportSiteName = $Settings.onlineSupportSiteName } + if ($Settings.onlineSupportSiteUrl) { $Body.onlineSupportSiteUrl = $Settings.onlineSupportSiteUrl } + if ($Settings.privacyUrl) { $Body.privacyUrl = $Settings.privacyUrl } + + $cmdparams = @{ + tenantid = $tenant + uri = 'https://graph.microsoft.com/beta/deviceManagement/intuneBrandingProfiles/c3a59481-1bf2-46ce-94b3-66eec07a8d60/' + AsApp = $true + Type = 'PATCH' + Body = ($Body | ConvertTo-Json) + ContentType = 'application/json; charset=utf-8' + } + + try { + New-GraphPostRequest @cmdparams + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully updated Intune Branding Profile' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to update Intune Branding Profile. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is correctly configured' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Intune Branding Profile is not correctly configured' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'intuneBrandingProfile' -FieldValue [bool]$StateIsCorrect -StoreAs bool -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 index f6840bafc092..bd58f15be325 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 @@ -7,17 +7,18 @@ function Invoke-CIPPStandardintuneDeviceReg { .SYNOPSIS (Label) Set Maximum Number of Devices per user .DESCRIPTION - (Helptext) sets the maximum number of devices that can be registered by a user. A value of 0 disables device registration by users - (DocsDescription) sets the maximum number of devices that can be registered by a user. A value of 0 disables device registration by users + (Helptext) Sets the maximum number of devices that can be registered by a user. A value of 0 disables device registration by users + (DocsDescription) Sets the maximum number of devices that can be registered by a user. A value of 0 disables device registration by users .NOTES CAT Intune Standards TAG - "mediumimpact" ADDEDCOMPONENT - {"type":"number","name":"standards.intuneDeviceReg.max","label":"Maximum devices (Enter 2147483647 for unlimited.)"} + {"type":"number","name":"standards.intuneDeviceReg.max","label":"Maximum devices (Enter 2147483647 for unlimited.)","required":true} IMPACT Medium Impact + ADDEDDATE + 2023-03-27 POWERSHELLEQUIVALENT Update-MgBetaPolicyDeviceRegistrationPolicy RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 index 3cab0708f09d..6705a03031e6 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 @@ -13,14 +13,16 @@ function Invoke-CIPPStandardintuneDeviceRetirementDays { CAT Intune Standards TAG - "lowimpact" ADDEDCOMPONENT {"type":"number","name":"standards.intuneDeviceRetirementDays.days","label":"Maximum days (0 equals disabled)"} IMPACT Low Impact + ADDEDDATE + 2023-05-19 POWERSHELLEQUIVALENT Graph API RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 index 9939dd0005c6..e898d3e88d0a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneRequireMFA.ps1 @@ -13,9 +13,10 @@ function Invoke-CIPPStandardintuneRequireMFA { CAT Intune Standards TAG - "mediumimpact" IMPACT Medium Impact + ADDEDDATE + 2023-10-23 POWERSHELLEQUIVALENT Update-MgBetaPolicyDeviceRegistrationPolicy RECOMMENDEDBY diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 index da89f92a6795..866fabf1043c 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardlaps.ps1 @@ -13,13 +13,15 @@ function Invoke-CIPPStandardlaps { CAT Entra (AAD) Standards TAG - "lowimpact" ADDEDCOMPONENT IMPACT Low Impact + ADDEDDATE + 2023-04-25 POWERSHELLEQUIVALENT Portal or Graph API RECOMMENDEDBY + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index 277263b94e61..4369a0c46b14 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -13,16 +13,18 @@ function Invoke-CIPPStandardsharingCapability { CAT SharePoint Standards TAG - "highimpact" "CIS" ADDEDCOMPONENT - {"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"}]} + {"type":"autoComplete","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 + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgBetaAdminSharepointSetting + Update-MgBetaAdminSharePointSetting RECOMMENDEDBY "CIS" + "CIPP" UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block .LINK @@ -35,38 +37,45 @@ function Invoke-CIPPStandardsharingCapability { $CurrentInfo = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'sharingCapability' -FieldValue $CurrentInfo.sharingCapability -StoreAs string -Tenant $tenant + Add-CIPPBPAField -FieldName 'sharingCapability' -FieldValue $CurrentInfo.sharingCapability -StoreAs string -Tenant $Tenant } + # Get level value using null-coalescing operator + $level = $Settings.Level.value ?? $Settings.Level + # Input validation - if (([string]::IsNullOrWhiteSpace($Settings.Level -or $Settings.Level -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true))) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'sharingCapability: Invalid sharingCapability parameter set' -sev Error + if (([string]::IsNullOrWhiteSpace($level) -or $level -eq 'Select a value') -and ($Settings.remediate -eq $true -or $Settings.alert -eq $true)) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'sharingCapability: Invalid sharingCapability parameter set' -sev Error Return } If ($Settings.remediate -eq $true) { - if ($CurrentInfo.sharingCapability -eq $Settings.Level) { - Write-Host "Sharing level is already set to $($Settings.Level)" - Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is already set to $($Settings.Level)" -sev Info + if ($CurrentInfo.sharingCapability -eq $level) { + Write-Host "Sharing level is already set to $level" + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Sharing level is already set to $level" -sev Info } else { - Write-Host "Setting sharing level to $($Settings.Level) from $($CurrentInfo.sharingCapability)" + Write-Host "Setting sharing level to $level from $($CurrentInfo.sharingCapability)" try { - $null = New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type patch -Body "{`"sharingCapability`":`"$($Settings.Level)`"}" -ContentType 'application/json' - Write-LogMessage -API 'Standards' -tenant $tenant -message "Set sharing level to $($Settings.Level) from $($CurrentInfo.sharingCapability)" -sev Info + $body = @{ + sharingCapability = $level + } + $bodyJson = ConvertTo-Json -InputObject $body -Compress + $null = New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -AsApp $true -Type patch -Body $bodyJson -ContentType 'application/json' + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set sharing level to $level from $($CurrentInfo.sharingCapability)" -sev Info } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set sharing level to $($Settings.Level): $ErrorMessage" -sev Error + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set sharing level to $level : $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage } } } if ($Settings.alert -eq $true) { - if ($CurrentInfo.sharingCapability -eq $Settings.Level) { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is set to $($Settings.Level)" -sev Info + if ($CurrentInfo.sharingCapability -eq $level) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Sharing level is set to $level" -sev Info } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message "Sharing level is not set to $($Settings.Level)" -sev Alert + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Sharing level is not set to $level" -sev Alert } } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 index 098b0ef3e17e..079b6e319d3a 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 @@ -1,90 +1,94 @@ -function Invoke-CIPPStandardsharingDomainRestriction { - <# - .FUNCTIONALITY - Internal - .COMPONENT - (APIName) sharingDomainRestriction - .SYNOPSIS - (Label) Restrict sharing to a specific domain - .DESCRIPTION - (Helptext) Restricts sharing to only users with the specified domain. This is useful for organizations that only want to share with their own domain. - (DocsDescription) Restricts sharing to only users with the specified domain. This is useful for organizations that only want to share with their own domain. - .NOTES - CAT - SharePoint Standards - TAG - "highimpact" - "CIS" - ADDEDCOMPONENT - {"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 - Update-MgAdminSharepointSetting - 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/sharepoint-standards#high-impact - #> - - param($Tenant, $Settings) - ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'sharingDomainRestriction' - - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true - - if ($Settings.Mode -eq 'none' -or $null -eq $Settings.Mode) { - $StateIsCorrect = $CurrentState.sharingDomainRestrictionMode -eq 'none' - } else { - $SelectedDomains = [String[]]$Settings.Domains.Split(',').Trim() - $StateIsCorrect = ($CurrentState.sharingDomainRestrictionMode -eq $Settings.Mode) -and - ($Settings.Mode -eq 'allowList' -and (!(Compare-Object -ReferenceObject $CurrentState.sharingAllowedDomainList -DifferenceObject $SelectedDomains))) -or - ($Settings.Mode -eq 'blockList' -and (!(Compare-Object -ReferenceObject $CurrentState.sharingBlockedDomainList -DifferenceObject $SelectedDomains))) - } - - if ($Settings.remediate -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is already correctly configured' -sev Info - } else { - $Body = @{ - sharingDomainRestrictionMode = $Settings.Mode - } - - if ($Settings.Mode -eq 'AllowList') { - $Body.Add('sharingAllowedDomainList', $SelectedDomains) - } elseif ($Settings.Mode -eq 'BlockList') { - $Body.Add('sharingBlockedDomainList', $SelectedDomains) - } - - $cmdparams = @{ - tenantid = $tenant - uri = 'https://graph.microsoft.com/beta/admin/sharepoint/settings' - AsApp = $true - Type = 'PATCH' - Body = ($Body | ConvertTo-Json) - ContentType = 'application/json' - } - - try { - New-GraphPostRequest @cmdparams - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully updated Sharing Domain Restriction settings' -sev Info - } catch { - $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to update Sharing Domain Restriction settings. Error: $ErrorMessage" -sev Error - } - } - } - - if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is correctly configured' -sev Info - } else { - Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is not correctly configured' -sev Alert - } - } - - if ($Settings.report -eq $true) { - Add-CIPPBPAField -FieldName 'sharingDomainRestriction' -FieldValue [bool]$StateIsCorrect -StoreAs bool -Tenant $tenant - } -} +function Invoke-CIPPStandardsharingDomainRestriction { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) sharingDomainRestriction + .SYNOPSIS + (Label) Restrict sharing to a specific domain + .DESCRIPTION + (Helptext) Restricts sharing to only users with the specified domain. This is useful for organizations that only want to share with their own domain. + (DocsDescription) Restricts sharing to only users with the specified domain. This is useful for organizations that only want to share with their own domain. + .NOTES + CAT + SharePoint Standards + TAG + "CIS" + ADDEDCOMPONENT + {"type":"autoComplete","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 + ADDEDDATE + 2024-06-20 + POWERSHELLEQUIVALENT + Update-MgAdminSharePointSetting + 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/sharepoint-standards#high-impact + #> + + param($Tenant, $Settings) + ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'sharingDomainRestriction' + + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/admin/sharepoint/settings' -tenantid $Tenant -AsApp $true + + # Get mode value using null-coalescing operator + $mode = $Settings.Mode.value ?? $Settings.Mode + + if ($mode -eq 'none' -or $null -eq $mode) { + $StateIsCorrect = $CurrentState.sharingDomainRestrictionMode -eq 'none' + } else { + $SelectedDomains = [String[]]$Settings.Domains.Split(',').Trim() + $StateIsCorrect = ($CurrentState.sharingDomainRestrictionMode -eq $mode) -and + ($mode -eq 'allowList' -and (!(Compare-Object -ReferenceObject $CurrentState.sharingAllowedDomainList -DifferenceObject $SelectedDomains))) -or + ($mode -eq 'blockList' -and (!(Compare-Object -ReferenceObject $CurrentState.sharingBlockedDomainList -DifferenceObject $SelectedDomains))) + } + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is already correctly configured' -sev Info + } else { + $Body = @{ + sharingDomainRestrictionMode = $mode + } + + if ($mode -eq 'AllowList') { + $Body.Add('sharingAllowedDomainList', $SelectedDomains) + } elseif ($mode -eq 'BlockList') { + $Body.Add('sharingBlockedDomainList', $SelectedDomains) + } + + $cmdParams = @{ + tenantid = $tenant + uri = 'https://graph.microsoft.com/beta/admin/sharepoint/settings' + AsApp = $true + Type = 'PATCH' + Body = ($Body | ConvertTo-Json) + ContentType = 'application/json' + } + + try { + $null = New-GraphPostRequest @cmdParams + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Successfully updated Sharing Domain Restriction settings' -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to update Sharing Domain Restriction settings. Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is correctly configured' -sev Info + } else { + Write-LogMessage -API 'Standards' -tenant $tenant -message 'Sharing Domain Restriction is not correctly configured' -sev Alert + } + } + + if ($Settings.report -eq $true) { + Add-CIPPBPAField -FieldName 'sharingDomainRestriction' -FieldValue [bool]$StateIsCorrect -StoreAs bool -Tenant $tenant + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 index 416af1a6ded7..7b0d2b43b2cb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 @@ -13,12 +13,13 @@ function Invoke-CIPPStandardunmanagedSync { CAT SharePoint Standards TAG - "highimpact" ADDEDCOMPONENT IMPACT High Impact + ADDEDDATE + 2022-06-15 POWERSHELLEQUIVALENT - Update-MgAdminSharepointSetting + Update-MgAdminSharePointSetting RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 index e111bbf55d2e..7fbc388cbbec 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessPermissions.ps1 @@ -128,6 +128,9 @@ function Test-CIPPAccessPermissions { $Messages.Add('You have all the required permissions.') | Out-Null } + $ApplicationToken = Get-GraphToken -returnRefresh $true -SkipCache $true -AsApp $true + $ApplicationTokenDetails = Read-JwtAccessDetails -Token $ApplicationToken.access_token -erroraction SilentlyContinue | Select-Object + $LastUpdate = [DateTime]::SpecifyKind($GraphPermissions.Timestamp.DateTime, [DateTimeKind]::Utc) $CpvTable = Get-CippTable -tablename 'cpvtenants' $CpvRefresh = Get-CippAzDataTableEntity @CpvTable -Filter "PartitionKey eq 'Tenant'" @@ -162,13 +165,14 @@ function Test-CIPPAccessPermissions { } $AccessCheck = [PSCustomObject]@{ - AccessTokenDetails = $AccessTokenDetails - Messages = @($Messages) - ErrorMessages = @($ErrorMessages) - MissingPermissions = @($MissingPermissions) - CPVRefreshList = @($CPVRefreshList) - Links = @($Links) - Success = $Success + AccessTokenDetails = $AccessTokenDetails + ApplicationTokenDetails = $ApplicationTokenDetails + Messages = @($Messages) + ErrorMessages = @($ErrorMessages) + MissingPermissions = @($MissingPermissions) + CPVRefreshList = @($CPVRefreshList) + Links = @($Links) + Success = $Success } $Table = Get-CIPPTable -TableName AccessChecks diff --git a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 index 596fc6a8e19c..56a6074c91b0 100644 --- a/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPGDAPRelationships.ps1 @@ -57,12 +57,14 @@ function Test-CIPPGDAPRelationships { ) $RoleAssignableGroups = $SAMUserMemberships | Where-Object { $_.isAssignableToRole } $NestedGroups = foreach ($Group in $RoleAssignableGroups) { + Write-Information "Getting nested group memberships for $($Group.displayName)" New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/$($Group.id)/memberOf?`$select=id,displayName" -NoAuthCheck $true } foreach ($Group in $ExpectedGroups) { $GroupFound = $false foreach ($Membership in ($SAMUserMemberships + $NestedGroups)) { - if ($Membership.displayName -match $Group -and (($CIPPGroupCount -gt 0 -and $Group -match 'M365 GDAP') -or $Group -notmatch 'M365 GDAP')) { + if ($Membership.displayName -match $Group) { + Write-Information "Found $Group in group memberships" $GroupFound = $true } } diff --git a/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 b/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 index a7f5ed0d676a..021678392573 100644 --- a/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPRerun.ps1 @@ -22,7 +22,9 @@ function Test-CIPPRerun { $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 + if ($AllRerunData) { + Remove-AzDataTableEntity @RerunTable -Entity $AllRerunData -Force + } return $false } @@ -67,7 +69,7 @@ function Test-CIPPRerun { } catch { $ErrorMessage = Get-CippException -Exception $_ Write-Host "Could not detect if this is a rerun: $($ErrorMessage.NormalizedError)" - Write-LogMessage -headers $Headers -API $API -message "Could not detect if this is a rerun: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData $ErrorMessage + Write-LogMessage -headers $Headers -API $API -message "Could not detect if this is a rerun: $($ErrorMessage.NormalizedError)" -Sev 'Error' -LogData (Get-CippException -Exception $_) return $false } } diff --git a/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 b/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 index 396757529a9f..5cfdcd6b5827 100644 --- a/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 +++ b/Modules/CIPPCore/Public/Tools/Import-CommunityTemplate.ps1 @@ -76,6 +76,8 @@ function Import-CommunityTemplate { '*DriverUpdateProfiles*' { 'windowsDriverUpdateProfiles' } '*SettingsCatalog*' { 'Catalog' } '*configurationPolicies*' { 'Catalog' } + '*managedAppPolicies*' { 'AppProtection' } + '*deviceAppManagement*' { 'AppProtection' } } $id = $Template.id $RawJson = $Template | Select-Object * -ExcludeProperty id, lastModifiedDateTime, 'assignments', '#microsoft*', '*@odata.navigationLink', '*@odata.associationLink', '*@odata.context', 'ScopeTagIds', 'supportsScopeTags', 'createdDateTime', '@odata.id', '@odata.editLink', 'lastModifiedDateTime@odata.type', 'roleScopeTagIds@odata.type', createdDateTime, 'createdDateTime@odata.type' diff --git a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 index 16f7890c4e94..5ff8f3631212 100644 --- a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 @@ -1,45 +1,47 @@ function Invoke-CippGraphWebhookRenewal { - $RenewalDate = (Get-Date).AddDays(1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + $RenewalDate = (Get-Date).AddDays(1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ') $body = @{ - "expirationDateTime" = "$RenewalDate" + 'expirationDateTime' = "$RenewalDate" } | ConvertTo-Json - $WebhookTable = Get-CIPPTable -TableName webhookTable - $WebhookData = Get-AzDataTableEntity @WebhookTable | Where-Object { $null -ne $_.SubscriptionID -and $_.SubscriptionID -ne '' -and ((Get-Date($_.Expiration)) -le ((Get-Date).AddHours(2))) } + try { + $WebhookData = Get-AzDataTableEntity @WebhookTable | Where-Object { $null -ne $_.SubscriptionID -and $_.SubscriptionID -ne '' -and ((Get-Date($_.Expiration)) -le ((Get-Date).AddHours(2))) } + } catch { + $WebhookData = @() + } - foreach ($UpdateSub in $WebhookData) { - try { - $TenantFilter = $UpdateSub.PartitionKey + if (($WebhookData | Measure-Object).Count -gt 0) { + foreach ($UpdateSub in $WebhookData) { try { - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/subscriptions/$($UpdateSub.SubscriptionID)" -tenantid $TenantFilter -type PATCH -body $body -Verbose - $UpdateSub.Expiration = $RenewalDate - $null = Add-AzDataTableEntity @WebhookTable -Entity $UpdateSub -Force - Write-LogMessage -Headers'CIPP' -API 'Renew_Graph_Subscriptions' -message "Renewed Subscription:$($UpdateSub.SubscriptionID)" -Sev "Info" -tenant $TenantFilter - - } catch { - # Rebuild creation parameters - $BaseURL = "$(([uri]($UpdateSub.WebhookNotificationUrl)).Host)" - if ($UpdateSub.TypeofSubscription) { - $TypeofSubscription = "$($UpdateSub.TypeofSubscription)" - } else { - $TypeofSubscription = 'updated' + $TenantFilter = $UpdateSub.PartitionKey + try { + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/subscriptions/$($UpdateSub.SubscriptionID)" -tenantid $TenantFilter -type PATCH -body $body -Verbose + $UpdateSub.Expiration = $RenewalDate + $null = Add-AzDataTableEntity @WebhookTable -Entity $UpdateSub -Force + Write-LogMessage -API 'Renew_Graph_Subscriptions' -message "Renewed Subscription:$($UpdateSub.SubscriptionID)" -Sev 'Info' -tenant $TenantFilter + + } catch { + # Rebuild creation parameters + $BaseURL = "$(([uri]($UpdateSub.WebhookNotificationUrl)).Host)" + if ($UpdateSub.TypeofSubscription) { + $TypeofSubscription = "$($UpdateSub.TypeofSubscription)" + } else { + $TypeofSubscription = 'updated' + } + $Resource = "$($UpdateSub.Resource)" + $EventType = "$($UpdateSub.EventType)" + + Write-LogMessage -API 'Renew_Graph_Subscriptions' -message "Recreating: $($UpdateSub.SubscriptionID) as renewal failed." -Sev 'Info' -tenant $TenantFilter + $CreateResult = New-CIPPGraphSubscription -TenantFilter $TenantFilter -TypeofSubscription $TypeofSubscription -BaseURL $BaseURL -Resource $Resource -EventType $EventType -Headers 'GraphSubscriptionRenewal' -Recreate + + if ($CreateResult -match 'Created Webhook subscription for') { + Remove-AzDataTableEntity -Force @WebhookTable -Entity $UpdateSub + } } - $Resource = "$($UpdateSub.Resource)" - $EventType = "$($UpdateSub.EventType)" - - Write-LogMessage -Headers'CIPP' -API 'Renew_Graph_Subscriptions' -message "Recreating: $($UpdateSub.SubscriptionID) as renewal failed." -Sev "Info" -tenant $TenantFilter - $CreateResult = New-CIPPGraphSubscription -TenantFilter $TenantFilter -TypeofSubscription $TypeofSubscription -BaseURL $BaseURL -Resource $Resource -EventType $EventType -Headers 'GraphSubscriptionRenewal' -Recreate - - if ($CreateResult -match 'Created Webhook subscription for') { - Remove-AzDataTableEntity -Force @WebhookTable -Entity $UpdateSub - } - + } catch { + Write-LogMessage -API 'Renew_Graph_Subscriptions' -message "Failed to renew Webhook Subscription: $($UpdateSub.SubscriptionID). Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $($_.Exception.message)" -Sev 'Error' -tenant $TenantFilter } - - - } catch { - Write-LogMessage -Headers'CIPP' -API 'Renew_Graph_Subscriptions' -message "Failed to renew Webhook Subscription: $($UpdateSub.SubscriptionID). Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $($_.Exception.message)" -Sev "Error" -tenant $TenantFilter } } } diff --git a/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 b/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 index a68ab8923a8b..2e32b90c2de2 100644 --- a/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/New-CIPPGraphSubscription.ps1 @@ -93,6 +93,9 @@ function New-CIPPGraphSubscription { expirationDateTime = $expiredate } | ConvertTo-Json + if ($BaseURL -match 'localhost' -or $BaseURL -match '127.0.0.1') { + return 'Cannot create graph subscription for local development' + } $GraphRequest = New-GraphPostRequest -uri 'https://graph.microsoft.com/beta/subscriptions' -tenantid $TenantFilter -type POST -body $params -verbose #If creation is succesfull, we store the GUID in the storage table webhookTable to make sure we can check against this later on. diff --git a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 index e820377bd909..1ba31ee67107 100644 --- a/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Test-CIPPAuditLogRules.ps1 @@ -4,9 +4,11 @@ function Test-CIPPAuditLogRules { [Parameter(Mandatory = $true)] $TenantFilter, [Parameter(Mandatory = $true)] - $SearchId + $Rows ) + $FunctionStartTime = Get-Date + $Results = [PSCustomObject]@{ TotalLogs = 0 MatchedLogs = 0 @@ -14,6 +16,9 @@ function Test-CIPPAuditLogRules { DataToProcess = @() } + # Get the CacheWebhooks table for removing processed rows + $CacheWebhooksTable = Get-CippTable -TableName 'CacheWebhooks' + $ExtendedPropertiesIgnoreList = @( 'OAuth2:Authorize' 'OAuth2:Token' @@ -35,23 +40,25 @@ function Test-CIPPAuditLogRules { LogType = $_.Type } } - #write-warning 'Getting audit records from Graph API' + try { - $LogCount = Get-CippAuditLogSearchResults -TenantFilter $TenantFilter -QueryId $SearchId -CountOnly + $LogCount = $Rows.count $RunGuid = (New-Guid).Guid - Write-Warning "Logs to process: $LogCount - SearchId: $SearchId - RunGuid: $($RunGuid) - $($TenantFilter)" + Write-Warning "Logs to process: $LogCount - RunGuid: $($RunGuid) - $($TenantFilter)" $Results.TotalLogs = $LogCount - Write-Information "RunGuid: $RunGud - Collecting logs" - $SearchResults = Get-CippAuditLogSearchResults -TenantFilter $TenantFilter -QueryId $SearchId + Write-Information "RunGuid: $RunGuid - Collecting logs" + $SearchResults = $Rows } 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 + Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit logs' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter throw $_ } if ($LogCount -gt 0) { - $LocationTable = Get-CIPPTable -TableName 'knownlocationdb' + $LocationTable = Get-CIPPTable -TableName 'knownlocationdbv2' $ProcessedData = foreach ($AuditRecord in $SearchResults) { + $RecordStartTime = Get-Date + Write-Host "Processing RowKey $($AuditRecord.id)" $RootProperties = $AuditRecord | Select-Object * -ExcludeProperty auditData $Data = $AuditRecord.auditData | Select-Object *, CIPPAction, CIPPClause, CIPPGeoLocation, CIPPBadRepIP, CIPPHostedIP, CIPPIPDetected, CIPPLocationInfo, CIPPExtendedProperties, CIPPDeviceProperties, CIPPParameters, CIPPModifiedProperties, AuditRecord -ErrorAction SilentlyContinue try { @@ -87,7 +94,8 @@ function Test-CIPPAuditLogRules { } } - if ($Data.clientip) { + if ($Data.clientip -and $Data.clientip -notmatch '[X]+') { + # Ignore IP addresses that have been redacted if ($Data.clientip -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$') { $Data.clientip = $Data.clientip -replace ':\d+$', '' # Remove the port number if present } @@ -98,7 +106,12 @@ function Test-CIPPAuditLogRules { $Trusted = $true } if (!$Trusted) { + $CacheLookupStartTime = Get-Date $Location = Get-CIPPAzDataTableEntity @LocationTable -Filter "RowKey eq '$($Data.clientIp)'" | Select-Object -Last 1 + $CacheLookupEndTime = Get-Date + $CacheLookupSeconds = ($CacheLookupEndTime - $CacheLookupStartTime).TotalSeconds + Write-Warning "Cache lookup for IP $($Data.clientip) took $CacheLookupSeconds seconds" + if ($Location) { $Country = $Location.CountryOrRegion $City = $Location.City @@ -107,7 +120,11 @@ function Test-CIPPAuditLogRules { $ASName = $Location.ASName } else { try { + $IPLookupStartTime = Get-Date $Location = Get-CIPPGeoIPLocation -IP $Data.clientip + $IPLookupEndTime = Get-Date + $IPLookupSeconds = ($IPLookupEndTime - $IPLookupStartTime).TotalSeconds + Write-Warning "IP lookup for $($Data.clientip) took $IPLookupSeconds seconds" } catch { #write-warning "Unable to get IP location for $($Data.clientip): $($_.Exception.Message)" } @@ -119,7 +136,7 @@ function Test-CIPPAuditLogRules { $IP = $Data.ClientIP $LocationInfo = @{ RowKey = [string]$Data.clientip - PartitionKey = [string]$Data.id + PartitionKey = 'ip' Tenant = [string]$TenantFilter CountryOrRegion = "$Country" City = "$City" @@ -147,6 +164,18 @@ function Test-CIPPAuditLogRules { #write-warning "Audit log: Error processing data: $($_.Exception.Message)`r`n$($_.InvocationInfo.PositionMessage)" Write-LogMessage -API 'Webhooks' -message 'Error Processing Audit Log Data' -LogData (Get-CippException -Exception $_) -sev Error -tenant $TenantFilter } + $RecordEndTime = Get-Date + $RecordSeconds = ($RecordEndTime - $RecordStartTime).TotalSeconds + Write-Warning "Task took $RecordSeconds seconds for RowKey $($AuditRecord.id)" + Write-Host "Removing row $($AuditRecord.id) from cache" + try { + Write-Information 'Removing processed rows from cache' + $RowEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($AuditRecord.id)'" + Remove-AzDataTableEntity @CacheWebhooksTable -Entity $RowEntity -Force + Write-Information "Removed row $($AuditRecord.id) from cache" + } catch { + Write-Information "Error removing rows from cache: $($_.Exception.Message)" + } } #write-warning "Processed Data: $(($ProcessedData | Measure-Object).Count) - This should be higher than 0 in many cases, because the where object has not run yet." #write-warning "Creating filters - $(($ProcessedData.operation | Sort-Object -Unique) -join ',') - $($TenantFilter)" @@ -179,10 +208,11 @@ function Test-CIPPAuditLogRules { $MatchedRules = [System.Collections.Generic.List[string]]::new() $DataToProcess = foreach ($clause in $Where) { - #write-warning "Webhook: Processing clause: $($clause.clause)" + $ClauseStartTime = Get-Date + Write-Warning "Webhook: Processing clause: $($clause.clause)" $ReturnedData = $ProcessedData | Where-Object { Invoke-Expression $clause.clause } if ($ReturnedData) { - #write-warning "Webhook: There is matching data: $(($ReturnedData.operation | Select-Object -Unique) -join ', ')" + Write-Warning "Webhook: There is matching data: $(($ReturnedData.operation | Select-Object -Unique) -join ', ')" $ReturnedData = foreach ($item in $ReturnedData) { $item.CIPPAction = $clause.expectedAction $item.CIPPClause = $clause.CIPPClause -join ' and ' @@ -190,12 +220,49 @@ function Test-CIPPAuditLogRules { $item } } + $ClauseEndTime = Get-Date + $ClauseSeconds = ($ClauseEndTime - $ClauseStartTime).TotalSeconds + Write-Warning "Task took $ClauseSeconds seconds for clause: $($clause.clause)" $ReturnedData } $Results.MatchedRules = @($MatchedRules | Select-Object -Unique) $Results.MatchedLogs = ($DataToProcess | Measure-Object).Count $Results.DataToProcess = $DataToProcess } - Write-Warning "Finished - RunGuid: $($RunGuid) - $($TenantFilter)" - $Results + + if ($DataToProcess) { + $CippConfigTable = Get-CippTable -tablename Config + $CippConfig = Get-CIPPAzDataTableEntity @CippConfigTable -Filter "PartitionKey eq 'InstanceProperties' and RowKey eq 'CIPPURL'" + $CIPPURL = 'https://{0}' -f $CippConfig.Value + foreach ($AuditLog in $DataToProcess) { + Write-Information "Processing $($AuditLog.operation)" + $Webhook = @{ + Data = $AuditLog + CIPPURL = [string]$CIPPURL + TenantFilter = $TenantFilter + } + try { + Invoke-CippWebhookProcessing @Webhook + } catch { + Write-Information "Error sending final step of auditlog processing: $($_.Exception.Message)" + } + } + } + + try { + Write-Information 'Removing processed rows from cache' + foreach ($Row in $Rows) { + if ($Row.id) { + $RowEntity = Get-CIPPAzDataTableEntity @CacheWebhooksTable -Filter "PartitionKey eq '$TenantFilter' and RowKey eq '$($Row.id)'" + if ($RowEntity) { + Remove-AzDataTableEntity @CacheWebhooksTable -Entity $RowEntity -Force + Write-Information "Removed row $($Row.id) from cache at final pass." + } + } + } + } catch { + Write-Information "Error removing rows from cache: $($_.Exception.Message)" + } + + return $Results } diff --git a/Modules/CippEntrypoints/CippEntrypoints.psm1 b/Modules/CippEntrypoints/CippEntrypoints.psm1 index 4378bc872d98..1b8732c5b702 100644 --- a/Modules/CippEntrypoints/CippEntrypoints.psm1 +++ b/Modules/CippEntrypoints/CippEntrypoints.psm1 @@ -2,8 +2,16 @@ using namespace System.Net function Receive-CippHttpTrigger { <# + .SYNOPSIS + Execute HTTP trigger function + .DESCRIPTION + Execute HTTP trigger function from an azure function app + .PARAMETER Request + The request object from the function app + .PARAMETER TriggerMetadata + The trigger metadata object from the function app .FUNCTIONALITY - Entrypoint + Entrypoint #> Param( $Request, @@ -62,6 +70,16 @@ function Receive-CippHttpTrigger { } function Receive-CippOrchestrationTrigger { + <# + .SYNOPSIS + Execute durable orchestrator function + .DESCRIPTION + Execute orchestrator from azure function app + .PARAMETER Context + The context object from the function app + .FUNCTIONALITY + Entrypoint + #> param($Context) try { @@ -71,7 +89,7 @@ function Receive-CippOrchestrationTrigger { $OrchestratorInput = $Context.Input } Write-Information "Orchestrator started $($OrchestratorInput.OrchestratorName)" - + Write-Warning "Receive-CippOrchestrationTrigger - $($OrchestratorInput.OrchestratorName)" $DurableRetryOptions = @{ FirstRetryInterval = (New-TimeSpan -Seconds 5) MaxNumberOfAttempts = if ($OrchestratorInput.MaxAttempts) { $OrchestratorInput.MaxAttempts } else { 1 } @@ -129,10 +147,22 @@ function Receive-CippOrchestrationTrigger { } catch { Write-Information "Orchestrator error $($_.Exception.Message) line $($_.InvocationInfo.ScriptLineNumber)" } + return $true } function Receive-CippActivityTrigger { + <# + .SYNOPSIS + Execute durable activity function + .DESCRIPTION + Execute durable activity function from an orchestrator + .PARAMETER Item + The item to process + .FUNCTIONALITY + Entrypoint + #> Param($Item) + Write-Warning "Hey Boo, the activity function is running. Here's some info: $($Item | ConvertTo-Json -Depth 10 -Compress)" try { $Start = Get-Date Set-Location (Get-Item $PSScriptRoot).Parent.Parent.FullName @@ -157,8 +187,9 @@ function Receive-CippActivityTrigger { if ($Item.FunctionName) { $FunctionName = 'Push-{0}' -f $Item.FunctionName try { + Write-Warning "Activity starting Function: Push-$FunctionName." Invoke-Command -ScriptBlock { & $FunctionName -Item $Item } - + Write-Warning "Activity completed Function: Push-$FunctionName." if ($TaskStatus) { $QueueTask.Status = 'Completed' $null = Set-CippQueueTask @QueueTask @@ -199,9 +230,20 @@ function Receive-CippActivityTrigger { $null = Set-CippQueueTask @QueueTask } } + return $true } function Receive-CIPPTimerTrigger { + <# + .SYNOPSIS + This function is used to execute timer functions based on the cron schedule. + .DESCRIPTION + This function is used to execute timer functions based on the cron schedule. + .PARAMETER Timer + The timer trigger object from the function app + .FUNCTIONALITY + Entrypoint + #> param($Timer) $UtcNow = (Get-Date).ToUniversalTime() @@ -255,6 +297,7 @@ function Receive-CIPPTimerTrigger { Add-CIPPAzDataTableEntity @Table -Entity $FunctionStatus -Force } + return $true } Export-ModuleMember -Function @('Receive-CippHttpTrigger', 'Receive-CippOrchestrationTrigger', 'Receive-CippActivityTrigger', 'Receive-CIPPTimerTrigger') diff --git a/Modules/CippExtensions/ConversionTable.csv b/Modules/CippExtensions/ConversionTable.csv index 4463224224a6..e38e1d159430 100644 --- a/Modules/CippExtensions/ConversionTable.csv +++ b/Modules/CippExtensions/ConversionTable.csv @@ -228,9 +228,9 @@ Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE_NOPREREQ,2cf302fe-62db-4e20-b573-e0998b1208b5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,CRMINSTANCE_GCC,483cc331-f4df-4a3b-b8ca-fe1a247569f6,Microsoft Dynamics CRM Online Instance Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,CDS_FIELD_SERVICE_CONTRACTOR_GCC,2457fe40-65be-48a1-935f-924ad6e62dba,Common Data Service Field service Part Time Contractors for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government @@ -253,27 +253,27 @@ Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAG Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_CDS_RETAIL,93cc200d-a47f-4c56-aec1-83f8b0d0425a,Common Data Service for Dynamics 365 Retail Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,FLOW_FOR_IOM_USL,9e6d1620-dce9-4655-8933-af8fa5bccc9c,Data Integration for IOM with Power Automate USL Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_RETAIL,117e3aa0-8d08-4a19-a6a5-90b7a96e2128,Dynamics 365 Commerce -Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_ACC_PROTECTION,4c00c16c-0304-4421-b598-555c3e78edcb,Dynamics 365 Fraud Protection - Account Protection Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_LOSS_PREVENTION,ecc62904-fa88-4552-a62c-fe582fb31444,Dynamics 365 Fraud Protection - Loss Prevention Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_PURCH_PROTECTION,d703990f-006e-459b-b8dd-1267c4533a22,Dynamics 365 Fraud Protection - Purchase Protection @@ -296,14 +296,14 @@ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,POWERAPPS FOR DYNAMICS 365 Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,DYNAMICS 365 FOR CUSTOMER SERVICE Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,D365_FIELD_SERVICE_ATTACH,55c9148b-d5f0-4101-b5a0-b2727cfc0916,Dynamics 365 for Field Service Attach Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Field Service Enterprise Edition,DYN365_ENTERPRISE_FIELD_SERVICE,c7d15985-e746-4f01-b113-20b575898250,DYN365_ENTERPRISE_FIELD_SERVICE,8c66ef8a-177f-4c0d-853c-d4f219331d09,Dynamics 365 for Field Service @@ -393,13 +393,13 @@ Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54- Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Forms_Pro_SalesEnt_GCC,33850b82-0a37-4ebb-a0b2-ee163facd716,Microsoft Dynamics 365 Customer Voice for Sales Enterprise for GCC Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User @@ -411,12 +411,12 @@ Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3 Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,DYN365_SALES_INSIGHTS,fedc185f-0711-4cc0-80ed-0a92da1a8384,Dynamics 365 AI for Sales (Embedded) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials @@ -432,7 +432,7 @@ Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd9 Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_CDS_SUPPLYCHAINMANAGEMENT,b6a8b974-2956-4e14-ae81-f0384c363528,Common Data Service for Dynamics 365 Supply Chain Management Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM -Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,D365_SCM_Attach,b21c777f-c2d5-486e-88f6-fc0a3e474271,Dynamics 365 for Supply Chain Management Attach Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Marketing Business Edition,DYN365_BUSINESS_MARKETING,238e2f8d-e429-4035-94db-6926be4ffe7b,DYN365_BUSINESS_Marketing,393a0c96-9ba1-4af0-8975-fa2f853a25ac,Dynamics 365 Marketing @@ -521,7 +521,7 @@ Dynamics 365 P1 Tria for Information Workers,DYN365_ENTERPRISE_P1_IW,338148b6-1b Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365CDSforProjectOperations,7df1d500-ca5c-4229-8cea-815bc88798c9,Common Data Service for Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperationsCDS,18fa3aba-b085-4105-87d7-55617b8585e6,Dynamics 365 Project Operations CDS Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperations,69f07c66-bee4-4222-b051-195095efee5b,Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 @@ -4797,18 +4797,18 @@ Power Pages authenticated users T2 min 100 units - 100 users/per site/month capa Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T2_min_100_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,7cae5432-61bb-48c3-b75c-831394ec13a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,DYN365_CDS_VIRAL,17ab22cd-a0b3-4536-910a-cb6eb12696c0,Common Data Service Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,POWER_PAGES_VTRIAL,6817d093-2d30-4249-8bd6-774f01efa78c,Power Pages vTrial for Makers @@ -5146,7 +5146,7 @@ Windows 365 Business 2 vCPU 4 GB 64 GB,CPC_B_2C_4RAM_64GB,42e6818f-8966-444b-b7a Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,Windows 365 Business 2 vCPU, 8 GB, 128 GB +Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,"Windows 365 Business 2 vCPU, 8 GB, 128 GB" Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) @@ -5177,14 +5177,14 @@ Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67 Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,CPC_B_8C_32RAM_512GB,4229a0b4-7f34-4835-b068-6dc8d10be57c,Windows 365 Business 8 vCPU 32 GB 512 GB -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,Windows 365 Business 16 vCPU, 64 GB, 512 GB -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,Windows 365 Business 16 vCPU, 64 GB, 1 TB +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,"Windows 365 Business 16 vCPU, 64 GB, 512 GB" +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,"Windows 365 Business 16 vCPU, 64 GB, 1 TB" Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,CPC_E_1C_2GB_64GB,86d70dbb-d4c6-4662-ba17-3014204cbb28,Windows 365 Enterprise 1 vCPU 2 GB 64 GB Windows 365 Enterprise 2 vCPU 4 GB 64 GB,CPC_E_2C_4GB_64GB,7bb14422-3b90-4389-a7be-f1b745fc037f,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation diff --git a/Modules/CippExtensions/Public/ConversionTable.csv b/Modules/CippExtensions/Public/ConversionTable.csv index 4463224224a6..e38e1d159430 100644 --- a/Modules/CippExtensions/Public/ConversionTable.csv +++ b/Modules/CippExtensions/Public/ConversionTable.csv @@ -228,9 +228,9 @@ Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE Dynamics 365 - Additional Non-Production Instance for Government,CRMTESTINSTANCE_NOPREREQ,2cf302fe-62db-4e20-b573-e0998b1208b5,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,CRMINSTANCE_GCC,483cc331-f4df-4a3b-b8ca-fe1a247569f6,Microsoft Dynamics CRM Online Instance Dynamics 365 Enterprise Edition - Additional Production Instance for Government,CRMINSTANCE_GCC,2bd3cb20-1bb6-446b-b4d0-089af3a05c52,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On -Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization,CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ENGINE_ADDON,24435e4b-87d0-4d7d-8beb-63a9b1573022,Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,CRM_AUTO_ROUTING_ADDON,2ba394e0-6f18-4b77-b45f-a5663bbab540,RETIRED - Field Service – Automated Routing Engine Add-On +"Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization",CRM_AUTO_ROUTING_ADDON,977464c4-bfaf-4b67-b761-a9bb735a2196,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,CDS_FIELD_SERVICE_CONTRACTOR_GCC,2457fe40-65be-48a1-935f-924ad6e62dba,Common Data Service Field service Part Time Contractors for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government Dynamics 365 Field Service Contractor for Government,D365_FIELD_SERVICE_CONTRACTOR_GOV,e7965e3a-1f49-4d67-a3de-ad1ce460bbcc,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government @@ -253,27 +253,27 @@ Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAG Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 for Case Management Enterprise Edition,DYN365_ENTERPRISE_CASE_MANAGEMENT,d39fb075-21ae-42d0-af80-22a2599749e0,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Case Management, Enterprise Edition for Government,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,EXCHANGE_S_FOUNDATION_GOV,922ba911-5694-4e99-a794-73aed9bfeec8,Exchange Foundation for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",D365_ENTERPRISE_CASE_MANAGEMENT_GOV,5cd0b796-9ac8-4792-9f0b-796ca9044e4a,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,79bb0a8d-e686-4e16-ac59-2b3fd0014a61,Dynamics 365 for Case Management for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Case Management, Enterprise Edition for Government",DYN365_ENTERPRISE_CASE_MANAGEMENT_GOV,ff5a82be-1edd-4d48-94e0-52527825b589,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_CDS_RETAIL,93cc200d-a47f-4c56-aec1-83f8b0d0425a,Common Data Service for Dynamics 365 Retail Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,FLOW_FOR_IOM_USL,9e6d1620-dce9-4655-8933-af8fa5bccc9c,Data Integration for IOM with Power Automate USL Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_RETAIL,117e3aa0-8d08-4a19-a6a5-90b7a96e2128,Dynamics 365 Commerce -Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_ACC_PROTECTION,4c00c16c-0304-4421-b598-555c3e78edcb,Dynamics 365 Fraud Protection - Account Protection Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_LOSS_PREVENTION,ecc62904-fa88-4552-a62c-fe582fb31444,Dynamics 365 Fraud Protection - Loss Prevention Dynamics 365 Commerce,DYN365_RETAIL,79909bd8-4c69-4202-939e-11bc4385b134,DYN365_FP_PURCH_PROTECTION,d703990f-006e-459b-b8dd-1267c4533a22,Dynamics 365 Fraud Protection - Purchase Protection @@ -296,14 +296,14 @@ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_ Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,POWERAPPS FOR DYNAMICS 365 Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,DYNAMICS 365 FOR CUSTOMER SERVICE Dynamics 365 for Customer Service Enterprise Edition,DYN365_ENTERPRISE_CUSTOMER_SERVICE,749742bf-0d37-4158-a120-33567104deeb,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Customer Service, Enterprise Edition for Government,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,dc6643d9-1e72-4dce-9f64-1d6eac1f1c5a,Dynamics 365 for Customer Service for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,Forms_Pro_Service_GCC,bb681a9b-58f5-42ee-9926-674325be8aaa,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise for GCC +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Customer Service, Enterprise Edition for Government",DYN365_ENTERPRISE_CUSTOMER_SERVICE_GOV,3c74d823-8f01-4fe8-82d5-f089a5504cec,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,D365_FIELD_SERVICE_ATTACH,55c9148b-d5f0-4101-b5a0-b2727cfc0916,Dynamics 365 for Field Service Attach Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer,D365_FIELD_SERVICE_ATTACH,a36cdaa2-a806-4b6e-9ae0-28dbd993c20e,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Field Service Enterprise Edition,DYN365_ENTERPRISE_FIELD_SERVICE,c7d15985-e746-4f01-b113-20b575898250,DYN365_ENTERPRISE_FIELD_SERVICE,8c66ef8a-177f-4c0d-853c-d4f219331d09,Dynamics 365 for Field Service @@ -393,13 +393,13 @@ Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54- Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,PROJECT ONLINE ESSENTIALS Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SHAREPOINT ONLINE (PLAN 2) Dynamics 365 for Sales Enterprise Edition,DYN365_ENTERPRISE_SALES,1e1a282c-9c54-43a2-9310-98ef728faace,SHAREPOINTWAC,e95bec33-7c88-4a70-8e19-b10bd9d0c014,OFFICE ONLINE -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government -Dynamics 365 for Sales, Enterprise Edition for Government,DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTWAC_GOV,8f9f0f3b-ca90-406c-a842-95579171f8ec,Office for the Web for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,PROJECT_ESSENTIALS_GOV,fdcb7064-f45c-46fa-b056-7e0e9fdf4bf3,Project Online Essentials for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government +"Dynamics 365 for Sales, Enterprise Edition for Government",DYN365_ENTERPRISE_SALES_GOV,28b275ce-aec7-4c26-82e2-1ffbc2746ad4,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,DYN365_ENTERPRISE_SALES_GOV,213be507-d547-4f79-bc2c-6196bc54c4a3,Dynamics 365 for Sales for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Forms_Pro_SalesEnt_GCC,33850b82-0a37-4ebb-a0b2-ee163facd716,Microsoft Dynamics 365 Customer Voice for Sales Enterprise for GCC Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User @@ -411,12 +411,12 @@ Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3 Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,SHAREPOINTENTERPRISE_GOV,153f85dd-d912-4762-af6c-d6e0fb4f6692,SharePoint Plan 2G Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,FLOW_DYN_APPS_GOV,2c6af4f1-e7b6-4d59-bbc8-eaa884f42d69,Power Automate for Dynamics 365 for Government Dynamics 365 for Sales Enterprise for Government,D365_ENTERPRISE_SALES_GOV,e85b3345-2fd5-45cf-a196-7968d3e18e56,POWERAPPS_DYN_APPS_GOV,3089c02b-e533-4b73-96a5-01fa648c3c3c,PowerApps for Dynamics 365 for Government -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox,Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,DYN365_ENTERPRISE_P1,d56f3deb-50d8-465a-bedb-f079817ccac1,Dynamics 365 Customer Engagement Plan +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,Forms_Pro_Service,67bf4812-f90b-4db9-97e7-c0bbbf7b2d09,Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox",Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox,494721b8-1f30-4315-aba6-70ca169358d9,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,DYN365_SALES_INSIGHTS,fedc185f-0711-4cc0-80ed-0a92da1a8384,Dynamics 365 AI for Sales (Embedded) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,SHAREPOINTENTERPRISE,5dbe027f-2339-4123-9542-606e4d348a72,SharePoint (Plan 2) Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd96877,PROJECT_ESSENTIALS,1259157c-8581-4875-bca7-2ffb18c51bda,Project Online Essentials @@ -432,7 +432,7 @@ Dynamics 365 Sales Premium,DYN365_SALES_PREMIUM,2edaa1dc-966d-4475-93d6-8ee8dfd9 Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_CDS_SUPPLYCHAINMANAGEMENT,b6a8b974-2956-4e14-ae81-f0384c363528,Common Data Service for Dynamics 365 Supply Chain Management Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,CDS_FOR_IOM,2bb89402-51e9-4c5a-be33-e954a9dd1ba6,Dataverse for IOM -Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,D365_SCM_Attach,b21c777f-c2d5-486e-88f6-fc0a3e474271,Dynamics 365 for Supply Chain Management Attach Dynamics 365 for Supply Chain Management Attach to Qualifying Dynamics 365 Base Offer,DYN365_SCM_ATTACH,090b4a96-8114-4c95-9c91-60e81ef53302,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Dynamics 365 for Marketing Business Edition,DYN365_BUSINESS_MARKETING,238e2f8d-e429-4035-94db-6926be4ffe7b,DYN365_BUSINESS_Marketing,393a0c96-9ba1-4af0-8975-fa2f853a25ac,Dynamics 365 Marketing @@ -521,7 +521,7 @@ Dynamics 365 P1 Tria for Information Workers,DYN365_ENTERPRISE_P1_IW,338148b6-1b Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365CDSforProjectOperations,7df1d500-ca5c-4229-8cea-815bc88798c9,Common Data Service for Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperationsCDS,18fa3aba-b085-4105-87d7-55617b8585e6,Dynamics 365 Project Operations CDS Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,Power_Pages_Internal_User,60bf28f9-2b70-4522-96f7-335f5e06c941,Power Pages Internal User -Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service +Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,DYN365_REGULATORY_SERVICE,c7657ae3-c0b0-4eed-8c1d-6a7967bd9c65,"Dynamics 365 for Finance and Operations, Enterprise edition - Regulatory Service" Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,D365_ProjectOperations,69f07c66-bee4-4222-b051-195095efee5b,Dynamics 365 Project Operations Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,POWERAPPS_DYN_APPS,874fc546-6efe-4d22-90b8-5c4e7aa59f4b,Power Apps for Dynamics 365 Dynamics 365 Project Operations,DYN365_PROJECT_OPERATIONS,98619618-9dc8-48c6-8f0c-741890ba5f93,FLOW_DYN_APPS,7e6d7d78-73de-46ba-83b1-6d25117334ba,Power Automate for Dynamics 365 @@ -4797,18 +4797,18 @@ Power Pages authenticated users T2 min 100 units - 100 users/per site/month capa Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T2_min_100_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,7cae5432-61bb-48c3-b75c-831394ec13a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site Power Pages authenticated users T2 min 100 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T2_CN_CN,7d2bb54a-a870-41c2-98d1-1f3b5b523275,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN,Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack,878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC,53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD,398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH -Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH,Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH,01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack CN_CN",Power Pages authenticated users T3_CN_CN,2cfd692f-a352-4fa8-b960-e3ad0c9b1178,PowerPages_Authenticated_User_CN,967d9574-a076-4bb7-ab89-f41f64bc142e,Power Pages Authenticated Users per site monthly capacity China +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User,0d3366f3-266e-4117-b422-7cabbc165e7c,Power Pages Authenticated Users per site monthly capacity +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack",878b8bbd-3cd0-4b44-9a56-3406741e65e0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_GCC","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_GCC",53265c61-c78c-4223-ab30-422da0c97fbb,PowerPages_Authenticated_User_GCC,cdf787bd-1546-48d2-9e93-b21f9ea7067a,Power Pages Authenticated Users per site monthly capacity GCC +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_DOD","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_DOD",398d37b5-8deb-48db-8f7f-703eb2fb7c72,PowerPages_Authenticated_User_DoD,03300fea-7a88-45a6-b5bd-29653803c591,Power Pages Authenticated Users per site monthly capacity DoD +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,DV_PowerPages_Authenticated_User,7aae746a-3463-4737-b295-3c1a16c31438,Dataverse for Power Pages Authenticated users per site +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_User_GCCH,18e74ca2-b5f0-4802-9a8b-00d2ff1e8322,Power Pages Authenticated Users per site monthly capacity GCCH +"Power Pages authenticated users T3 min 1,000 units - 100 users/per site/month capacity pack_USGOV_GCCHIGH","Power_Pages_authenticated_users_T3_min_1,000_units_100_users/per_site/month_capacity_pack_USGOV_GCCHIGH",01d46c34-3525-47d5-bd1a-5f19979938a0,PowerPages_Authenticated_Users_GCCH,5410f688-68f2-47a5-9b8f-7466194a806a,Power Pages Authenticated Users per site mthly capacity GCCH New Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,DYN365_CDS_VIRAL,17ab22cd-a0b3-4536-910a-cb6eb12696c0,Common Data Service Power Pages vTrial for Makers,Power_Pages_vTrial_for_Makers,3f9f06f5-3c31-472c-985f-62d9c10ec167,POWER_PAGES_VTRIAL,6817d093-2d30-4249-8bd6-774f01efa78c,Power Pages vTrial for Makers @@ -5146,7 +5146,7 @@ Windows 365 Business 2 vCPU 4 GB 64 GB,CPC_B_2C_4RAM_64GB,42e6818f-8966-444b-b7a Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,Windows 365 Business 2 vCPU, 8 GB, 128 GB +Windows 365 Business 2 vCPU 8 GB 128 GB,CPC_B_2C_8RAM_128GB,71f21848-f89b-4aaa-a2dc-780c8e8aac5b,CPC_SS_2,9d2eed2c-b0c0-4a89-940c-bc303444a41b,"Windows 365 Business 2 vCPU, 8 GB, 128 GB" Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 2 vCPU 8 GB 256 GB,CPC_B_2C_8RAM_256GB,750d9542-a2f8-41c7-8c81-311352173432,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) @@ -5177,14 +5177,14 @@ Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67 Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) Windows 365 Business 8 vCPU 32 GB 512 GB,CPC_B_8C_32RAM_512GB,8ee402cd-e6a8-4b67-a411-54d1f37a2049,CPC_B_8C_32RAM_512GB,4229a0b4-7f34-4835-b068-6dc8d10be57c,Windows 365 Business 8 vCPU 32 GB 512 GB -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 512 GB,Windows_365_Business_16_vCPU,_64_GB,_512_GB,93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,Windows 365 Business 16 vCPU, 64 GB, 512 GB -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) -Windows 365 Business 16 vCPU, 64 GB, 1 TB,Windows_365_Business_16_vCPU,_64_GB,_1_TB,24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,Windows 365 Business 16 vCPU, 64 GB, 1 TB +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 512 GB","Windows_365_Business_16_vCPU,_64_GB,_512_GB",93d9955a-ec70-44d5-8faa-a194492390f7,CPC_B_16C_64GB_512GB,cbbedc49-52d5-4fd6-82ac-a5bc51634dc3,"Windows 365 Business 16 vCPU, 64 GB, 512 GB" +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_CUSTOMER_PLAN1,6f23d6a9-adbf-481c-8538-b4c095654487,Microsoft 365 Lighthouse (Plan 1) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,M365_LIGHTHOUSE_PARTNER_PLAN1,d55411c9-cfff-40a9-87c7-240f14df7da5,Microsoft 365 Lighthouse (Plan 2) +"Windows 365 Business 16 vCPU, 64 GB, 1 TB","Windows_365_Business_16_vCPU,_64_GB,_1_TB",24be3cd7-82ca-41a5-94a7-4903373cdcae,CPC_B_16C_64GB_1TB,37c961db-2cfd-4e13-b81e-b0059ce10e34,"Windows 365 Business 16 vCPU, 64 GB, 1 TB" Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation Windows 365 Enterprise 1 vCPU 2 GB 64 GB,CPC_E_1C_2GB_64GB,0c278af4-c9c1-45de-9f4b-cd929e747a2c,CPC_E_1C_2GB_64GB,86d70dbb-d4c6-4662-ba17-3014204cbb28,Windows 365 Enterprise 1 vCPU 2 GB 64 GB Windows 365 Enterprise 2 vCPU 4 GB 64 GB,CPC_E_2C_4GB_64GB,7bb14422-3b90-4389-a7be-f1b745fc037f,EXCHANGE_S_FOUNDATION,113feb6c-3fe4-4440-bddc-54d774bf0318,Exchange Foundation diff --git a/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 b/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 index 440e24842e1c..4b79384771d8 100644 --- a/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 +++ b/Modules/CippExtensions/Public/Halo/New-HaloPSATicket.ps1 @@ -8,8 +8,48 @@ function New-HaloPSATicket { #Get Halo PSA Token based on the config we have. $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).HaloPSA - + $TicketTable = Get-CIPPTable -TableName 'PSATickets' $token = Get-HaloToken -configuration $Configuration + # sha hash title + $TitleHash = Get-StringHash -String $title + + if ($Configuration.ConsolidateTickets) { + $ExistingTicket = Get-CIPPAzDataTableEntity @TicketTable -Filter "PartitionKey eq 'HaloPSA' and RowKey eq '$($client)-$($TitleHash)'" + if ($ExistingTicket) { + Write-Information "Ticket already exists in HaloPSA: $($ExistingTicket.TicketID)" + + $Ticket = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Tickets/$($ExistingTicket.TicketID)?includedetails=true&includelastaction=false&nocache=undefined&includeusersassets=false&isdetailscreen=true" -ContentType 'application/json; charset=utf-8' -Method Get -Headers @{Authorization = "Bearer $($token.access_token)" } + if (!$Ticket.hasbeenclosed) { + Write-Information 'Ticket is still open, adding new note' + $Object = [PSCustomObject]@{ + ticket_id = $ExistingTicket.TicketID + outcome = 'Private Note' + outcome_id = 7 + hiddenfromuser = $true + note_html = $description + } + $body = ConvertTo-Json -Compress -Depth 10 -InputObject @($Object) + try { + if ($PSCmdlet.ShouldProcess('Add note to HaloPSA ticket', 'Add note')) { + $Action = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/actions" -ContentType 'application/json; charset=utf-8' -Method Post -Body $body -Headers @{Authorization = "Bearer $($token.access_token)" } + Write-Information "Note added to ticket in HaloPSA: $($Action.id)" + } + return + } catch { + $Message = if ($_.ErrorDetails.Message) { + Get-NormalizedError -Message $_.ErrorDetails.Message + } else { + $_.Exception.message + } + Write-LogMessage -message "Failed to add note to HaloPSA ticket: $Message" -API 'HaloPSATicket' -sev Error -LogData (Get-CippException -Exception $_) + Write-Information "Failed to add note to HaloPSA ticket: $Message" + Write-Information "Body we tried to ship: $body" + return + } + } + } + } + $Object = [PSCustomObject]@{ files = $null usertype = 1 @@ -41,6 +81,18 @@ function New-HaloPSATicket { if ($PSCmdlet.ShouldProcess('Send ticket to HaloPSA', 'Create ticket')) { $Ticket = Invoke-RestMethod -Uri "$($Configuration.ResourceURL)/Tickets" -ContentType 'application/json; charset=utf-8' -Method Post -Body $body -Headers @{Authorization = "Bearer $($token.access_token)" } Write-Information "Ticket created in HaloPSA: $($Ticket.id)" + + if ($Configuration.ConsolidateTickets) { + $TicketObject = [PSCustomObject]@{ + PartitionKey = 'HaloPSA' + RowKey = "$($client)-$($TitleHash)" + Title = $title + ClientId = $client + TicketID = $Ticket.id + } + Add-CIPPAzDataTableEntity @TicketTable -Entity $TicketObject -Force + Write-Information 'Ticket added to consolidation table' + } } } catch { $Message = if ($_.ErrorDetails.Message) { diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 index 921a6d1e1ac3..fddf4c1666a4 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneExtensionScheduler.ps1 @@ -16,7 +16,11 @@ function Invoke-NinjaOneExtensionScheduler { Write-Host "Ninja Time Setting: $TimeSetting" - $LastRunTime = Get-Date(($Settings | Where-Object { $_.RowKey -eq 'NinjaLastRunTime' }).SettingValue) + try { + $LastRunTime = Get-Date(($Settings | Where-Object { $_.RowKey -eq 'NinjaLastRunTime' }).SettingValue) + } catch { + $LastRunTime = $Null + } Write-Host "Last Run: $LastRunTime" diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 index 813ce65b3af5..7f5826e18556 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneTenantSync.ps1 @@ -274,92 +274,29 @@ function Invoke-NinjaOneTenantSync { [System.Collections.Generic.List[PSCustomObject]]$NinjaLicenseUpdates = @() [System.Collections.Generic.List[PSCustomObject]]$NinjaLicenseCreation = @() - # Build bulk requests array. - [System.Collections.Generic.List[PSCustomObject]]$TenantRequests = @( - @{ - id = 'Users' - method = 'GET' - url = '/users?$top=999' - }, - @{ - id = 'TenantDetails' - method = 'GET' - url = '/organization' - }, - @{ - id = 'AllRoles' - method = 'GET' - url = '/directoryRoles' - }, - @{ - id = 'RawDomains' - method = 'GET' - url = '/domains' - }, - @{ - id = 'Licenses' - method = 'GET' - url = '/subscribedSkus' - }, - @{ - id = 'Devices' - method = 'GET' - url = '/deviceManagement/managedDevices?$top=999' - }, - @{ - id = 'DeviceCompliancePolicies' - method = 'GET' - url = '/deviceManagement/deviceCompliancePolicies/' - }, - <#@{ - id = 'DeviceApps' - method = 'GET' - url = '/deviceAppManagement/mobileApps' - },#> - @{ - id = 'Groups' - method = 'GET' - url = '/groups' - }, - @{ - id = 'ConditionalAccess' - method = 'GET' - url = '/identity/conditionalAccess/policies' - }, - @{ - id = 'SecureScore' - method = 'GET' - url = '/security/secureScores?$top=999' - }, - @{ - id = 'SecureScoreControlProfiles' - method = 'GET' - url = '/security/secureScoreControlProfiles?$top=999' - }, - @{ - id = 'Subscriptions' - method = 'GET' - url = '/directory/subscriptions' - } - - ) - - Write-Verbose "$(Get-Date) - Fetching Bulk Data" - try { - $TenantResults = New-GraphBulkRequest -Requests $TenantRequests -tenantid $TenantFilter -NoAuthCheck $True - } catch { - Throw "Failed to fetch bulk company data: $_" - } - - Write-Information 'Fetched Bulk M365 Data' - - $Users = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Users' - - $SecureScore = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'SecureScore' - - $Subscriptions = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Subscriptions' - - [System.Collections.Generic.List[PSCustomObject]]$SecureScoreProfiles = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'SecureScoreControlProfiles' + # Replace direct Graph/Exchange calls with cached data + $ExtensionCache = Get-ExtensionCacheData -TenantFilter $Customer.defaultDomainName + + # Map cached data to variables + $Users = $ExtensionCache.Users + $licensedUsers = $Users | Where-Object { $null -ne $_.assignedLicenses.skuId } + $AllRoles = $ExtensionCache.AllRoles + $Devices = $ExtensionCache.Devices + $DeviceCompliancePolicies = $ExtensionCache.DeviceCompliancePolicies + $OneDriveDetails = $ExtensionCache.OneDriveUsage + $CASFull = $ExtensionCache.CASMailbox + $MailboxDetailedFull = $ExtensionCache.Mailboxes + $MailboxStatsFull = $ExtensionCache.MailboxUsage + $Permissions = $ExtensionCache.MailboxPermissions + $SecureScore = $ExtensionCache.SecureScore + $Subscriptions = $ExtensionCache.Subscriptions + $SecureScoreProfiles = $ExtensionCache.SecureScoreControlProfiles + $TenantDetails = $ExtensionCache.TenantDetails + $RawDomains = $ExtensionCache.Domains + $AllGroups = $ExtensionCache.Groups + $Licenses = $ExtensionCache.Licenses + $RawDomains = $ExtensionCache.Domains + $AllConditionalAccessPolicies = $ExtensionCache.ConditionalAccessPolicies $CurrentSecureScore = ($SecureScore | Sort-Object createDateTime -Descending | Select-Object -First 1) $MaxSecureScoreRank = ($SecureScoreProfiles.rank | Measure-Object -Maximum).maximum @@ -384,136 +321,58 @@ function Invoke-NinjaOneTenantSync { } } - $TenantDetails = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'TenantDetails' - - Write-Verbose "$(Get-Date) - Parsing Users" # Grab licensed users $licensedUsers = $Users | Where-Object { $null -ne $_.AssignedLicenses.SkuId } | Sort-Object UserPrincipalName - Write-Verbose "$(Get-Date) - Parsing Roles" - # Get All Roles - $AllRoles = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'AllRoles' - - $SelectList = 'id', 'displayName', 'userPrincipalName' - - [System.Collections.Generic.List[PSCustomObject]]$RolesRequestArray = @() - foreach ($Role in $AllRoles) { - $RolesRequestArray.add(@{ - id = $Role.id - method = 'GET' - url = "/directoryRoles/$($Role.id)/members?`$select=$($selectlist -join ',')" - }) - } - - try { - $MemberReturn = New-GraphBulkRequest -Requests $RolesRequestArray -tenantid $TenantFilter -NoAuthCheck $True - } catch { - $MemberReturn = $null - } - - Write-Information 'Fetched M365 Roles' - - $Roles = foreach ($Result in $MemberReturn) { + $Roles = foreach ($Role in $AllRoles) { + # Get members from cache + $Members = ($ExtensionCache."AllRoles_$($Role.id)") [PSCustomObject]@{ ID = $Result.id - DisplayName = ($AllRoles | Where-Object { $_.id -eq $Result.id }).displayName - Description = ($AllRoles | Where-Object { $_.id -eq $Result.id }).description - Members = $Result.body.value - ParsedMembers = $Result.body.value.Displayname -join ', ' + DisplayName = $Role.displayName + Description = $Role.description + Members = $Members + ParsedMembers = $Members.displayName -join ', ' } } - - $AdminUsers = (($Roles | Where-Object { $_.Displayname -match 'Administrator' }).Members | Where-Object { $null -ne $_.displayName }) Write-Verbose "$(Get-Date) - Fetching Domains" - try { - $RawDomains = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'RawDomains' - } catch { - $RawDomains = $null - } - $customerDomains = ($RawDomains | Where-Object { $_.IsVerified -eq $True }).id -join ', ' | Out-String + $customerDomains = ($RawDomains | Where-Object { $_.IsVerified -eq $true }).id -join ', ' | Out-String Write-Verbose "$(Get-Date) - Parsing Licenses" - # Get Licenses - $Licenses = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Licenses' # Get the license overview for the tenant if ($Licenses) { $LicensesParsed = $Licenses | Where-Object { $_.PrepaidUnits.Enabled -gt 0 } | Select-Object @{N = 'License Name'; E = { (Get-Culture).TextInfo.ToTitleCase((convert-skuname -skuname $_.SkuPartNumber).Tolower()) } }, @{N = 'Active'; E = { $_.PrepaidUnits.Enabled } }, @{N = 'Consumed'; E = { $_.ConsumedUnits } }, @{N = 'Unused'; E = { $_.PrepaidUnits.Enabled - $_.ConsumedUnits } } } - Write-Verbose "$(Get-Date) - Parsing Devices" - # Get all devices from Intune - $devices = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Devices' - - Write-Verbose "$(Get-Date) - Parsing Device Compliance Polcies" - # Fetch Compliance Policy Status - $DeviceCompliancePolicies = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'DeviceCompliancePolicies' - - # Get the status of each device for each policy - [System.Collections.Generic.List[PSCustomObject]]$PolicyRequestArray = @() - foreach ($CompliancePolicy in $DeviceCompliancePolicies) { - $PolicyRequestArray.add(@{ - id = $CompliancePolicy.id - method = 'GET' - url = "/deviceManagement/deviceCompliancePolicies/$($CompliancePolicy.id)/deviceStatuses" - }) - } - - try { - $PolicyReturn = New-GraphBulkRequest -Requests $PolicyRequestArray -tenantid $TenantFilter -NoAuthCheck $True - } catch { - $PolicyReturn = $null - } - - Write-Information 'Fetched M365 Device Compliance' + Write-Verbose "$(Get-Date) - Parsing Device Compliance Policies" - $DeviceComplianceDetails = foreach ($Result in $PolicyReturn) { + $DeviceComplianceDetails = foreach ($Policy in $DeviceCompliancePolicies) { + $DeviceStatuses = $ExtensionCache."DeviceCompliancePolicy_$($Policy.id)" [pscustomobject]@{ - ID = ($DeviceCompliancePolicies | Where-Object { $_.id -eq $Result.id }).id - DisplayName = ($DeviceCompliancePolicies | Where-Object { $_.id -eq $Result.id }).DisplayName - DeviceStatuses = $Result.body.value + ID = $Policy.id + DisplayName = $Policy.displayName + DeviceStatuses = $DeviceStatuses } } Write-Verbose "$(Get-Date) - Parsing Groups" - # Fetch Groups - $AllGroups = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'Groups' - - # Fetch the App status for each device - [System.Collections.Generic.List[PSCustomObject]]$GroupRequestArray = @() - foreach ($Group in $AllGroups) { - $GroupRequestArray.add(@{ - id = $Group.id - method = 'GET' - url = "/groups/$($Group.id)/members" - }) - } - - try { - $GroupMembersReturn = New-GraphBulkRequest -Requests $GroupRequestArray -tenantid $TenantFilter -NoAuthCheck $True - } catch { - $GroupMembersReturn = $null - } - - Write-Information 'Fetched M365 Group Membership' - $Groups = foreach ($Result in $GroupMembersReturn) { + $Groups = foreach ($Group in $AllGroups) { + $Members = $ExtensionCache."Groups_$($Result.id)" [pscustomobject]@{ - ID = $Result.id - DisplayName = ($AllGroups | Where-Object { $_.id -eq $Result.id }).DisplayName - Members = $result.body.value + ID = $Group.id + DisplayName = $Group.displayName + Members = $Members } } - Write-Verbose "$(Get-Date) - Parsing Conditional Access Polcies" - # Fetch and parse conditional access polcies - $AllConditionalAccessPolcies = Get-GraphBulkResultByID -value -Results $TenantResults -ID 'ConditionalAccess' - $ConditionalAccessMembers = foreach ($CAPolicy in $AllConditionalAccessPolcies) { + $ConditionalAccessMembers = foreach ($CAPolicy in $AllConditionalAccessPolicies) { #Setup User Array [System.Collections.Generic.List[PSCustomObject]]$CAMembers = @() @@ -568,49 +427,6 @@ function Invoke-NinjaOneTenantSync { } } - Write-Verbose "$(Get-Date) - Fetching One Drive Details" - try { - $OneDriveDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOneDriveUsageAccountDetail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv - } catch { - Write-Error "Failed to fetch Onedrive Details: $_" - $OneDriveDetails = $null - } - - Write-Verbose "$(Get-Date) - Fetching CAS Mailbox Details" - try { - $CASFull = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/CasMailbox" -Tenantid $Customer.defaultDomainName -scope ExchangeOnline -noPagination $true - } catch { - Write-Error "Failed to fetch CAS Details: $_" - $CASFull = $null - } - - Write-Verbose "$(Get-Date) - Fetching Mailbox Details" - try { - $MailboxDetailedFull = New-ExoRequest -TenantID $Customer.defaultDomainName -cmdlet 'Get-Mailbox' - } catch { - Write-Error "Failed to fetch Mailbox Details: $_" - $MailboxDetailedFull = $null - } - - Write-Verbose "$(Get-Date) - Fetching Blocked Mailbox Details" - try { - $BlockedSenders = New-ExoRequest -TenantID $Customer.defaultDomainName -cmdlet 'Get-BlockedSenderAddress' - } catch { - Write-Error "Failed to fetch Blocked Sender Details: $_" - $BlockedSenders = $null - } - - Write-Verbose "$(Get-Date) - Fetching Mailbox Stats" - try { - $MailboxStatsFull = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/reports/getMailboxUsageDetail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv - } catch { - Write-Error "Failed to fetch Mailbox Stats: $_" - $MailboxStatsFull = $null - } - - Write-Information 'Fetched M365 Additional Data' - - $FetchEnd = Get-Date ############################ Format and Synchronize to NinjaOne ############################ @@ -773,7 +589,7 @@ function Invoke-NinjaOneTenantSync { }, @{ Name = 'View Devices in CIPP' - Link = "https://$($CIPPURL)/endpoint/MEM/devices?customerId=$($Customer.defaultDomainName)" + Link = "https://$($CIPPURL)/endpoint/MEM/devices?tenantFilter=$($Customer.defaultDomainName)" Icon = 'far fa-eye' } ) @@ -891,7 +707,6 @@ function Invoke-NinjaOneTenantSync { Write-Information 'Processed Devices' - ########## Create / Update User Objects if ($Configuration.LicensedOnly -eq $True) { @@ -975,20 +790,15 @@ function Invoke-NinjaOneTenantSync { $MailboxDetailedRequest = $MailboxDetailedFull | Where-Object { $_.ExternalDirectoryObjectId -eq $User.iD } $StatsRequest = $MailboxStatsFull | Where-Object { $_.'User Principal Name' -eq $User.UserPrincipalName } - #try { - # $PermsRequest = New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenantfilter)/Mailbox('$($User.ID)')/MailboxPermission" -Tenantid $tenantfilter -scope ExchangeOnline -noPagination $true -NoAuthCheck $True - #} catch { - # $PermsRequest = $null - #} - - #$ParsedPerms = foreach ($Perm in $PermsRequest) { - # if ($Perm.User -ne 'NT AUTHORITY\SELF') { - # [pscustomobject]@{ - # User = $Perm.User - # AccessRights = $Perm.PermissionList.AccessRights -join ', ' - # } - # } - #} + + $ParsedPerms = foreach ($Perm in $Permissions) { + if ($Perm.User -ne 'NT AUTHORITY\SELF') { + [pscustomobject]@{ + User = $Perm.User + AccessRights = $Perm.PermissionList.AccessRights -join ', ' + } + } + } try { $TotalItemSize = [math]::Round($StatsRequest.'Storage Used (Byte)' / 1Gb, 2) @@ -1007,7 +817,7 @@ function Invoke-NinjaOneTenantSync { MailboxImapEnabled = $CASRequest.ImapEnabled MailboxPopEnabled = $CASRequest.PopEnabled MailboxActiveSyncEnabled = $CASRequest.ActiveSyncEnabled - #Permissions = $ParsedPerms + 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.'Item Count', 2) @@ -1713,47 +1523,47 @@ function Invoke-NinjaOneTenantSync { $ManagementLinksData = @( @{ Name = 'M365 Admin Portal' - Link = "https://portal.office.com/Partner/BeginClientSession.aspx?CTID=$($customer.CustomerId)&CSDEST=o365admincenter" + Link = "https://portal.office.com/Partner/BeginClientSession.aspx?CTID=$($customer.customerId)&CSDEST=o365admincenter" Icon = 'fas fa-cogs' }, @{ Name = 'Exchange Portal' - Link = "https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=$($Customer.DefaultDomainName)#" + Link = "https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=$($Customer.defaultDomainName)#" Icon = 'fas fa-mail-bulk' }, @{ Name = 'Entra Portal' - Link = "https://entra.microsoft.com/$($Customer.DefaultDomainName)" + Link = "https://entra.microsoft.com/$($Customer.defaultDomainName)" Icon = 'fas fa-users-cog' }, @{ Name = 'Intune Portal' - Link = "https://endpoint.microsoft.com/$($customer.DefaultDomainName)/" + Link = "https://endpoint.microsoft.com/$($customer.defaultDomainName)/" Icon = 'fas fa-laptop' }, @{ Name = 'Sharepoint Admin' - Link = "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=$($Customer.CustomerId)&CSDEST=SharePoint" + Link = "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=$($Customer.customerId)&CSDEST=SharePoint" Icon = 'fas fa-shapes' }, @{ Name = 'Teams Admin' - Link = "https://admin.teams.microsoft.com/?delegatedOrg=$($Customer.DefaultDomainName)" + Link = "https://admin.teams.microsoft.com/?delegatedOrg=$($Customer.defaultDomainName)" Icon = 'fas fa-users' }, @{ Name = 'Security Portal' - Link = "https://security.microsoft.com/?tid=$($Customer.CustomerId)" + Link = "https://security.microsoft.com/?tid=$($Customer.customerId)" Icon = 'fas fa-building-shield' }, @{ Name = 'Compliance Portal' - Link = "https://purview.microsoft.com/?tid=$($Customer.CustomerId)" + Link = "https://purview.microsoft.com/?tid=$($Customer.customerId)" Icon = 'fas fa-user-shield' }, @{ Name = 'Azure Portal' - Link = "https://portal.azure.com/$($customer.DefaultDomainName)" + Link = "https://portal.azure.com/$($customer.defaultDomainName)" Icon = 'fas fa-server' } @@ -1765,37 +1575,32 @@ function Invoke-NinjaOneTenantSync { @{ Name = 'CIPP Tenant Dashboard' - Link = "https://$CIPPUrl/home?customerId=$($Customer.CustomerId)" + Link = "https://$CIPPUrl?tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-shield-halved' }, - @{ - Name = 'Edit Tenant' - Link = "https://$CIPPUrl/tenant/administration/tenants/Edit?customerId=$($Customer.customerId)&tenantFilter=$($Customer.defaultDomainName)" - Icon = 'fas fa-cog' - }, @{ Name = 'List Users' - Link = "https://$CIPPUrl/identity/administration/users?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/identity/administration/users?tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-user' }, @{ Name = 'List Groups' - Link = "https://$CIPPUrl/identity/administration/groups?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/identity/administration/groups?tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-users' }, @{ Name = 'List Devices' - Link = "https://$CIPPUrl/endpoint/MEM/devices?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/endpoint/MEM/devices?tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-laptop' }, @{ Name = 'Create User' - Link = "https://$CIPPUrl/identity/administration/users/add?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/identity/administration/users/add?tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-user-plus' }, @{ Name = 'Create Group' - Link = "https://$CIPPUrl/identity/administration/groups/add?customerId=73be1f98-1003-4e1a-8e8a-4ffbff7ff2d6" + Link = "https://$CIPPUrl/identity/administration/groups/add?tenantFilter=$($Customer.defaultDomainName)" Icon = 'fas fa-user-group' } ) @@ -1881,7 +1686,7 @@ function Invoke-NinjaOneTenantSync { # Create the Users Card - $TitleLink = "https://$CIPPUrl/identity/administration/users?customerId=$($Customer.customerId)" + $TitleLink = "https://$CIPPUrl/identity/administration/users?tenantFilter=$($Customer.defaultDomainName)" $UsersCardBodyHTML = $UsersEnabledChartHTML + $UsersTypesChartHTML @@ -1963,7 +1768,7 @@ function Invoke-NinjaOneTenantSync { # Create the Devices Card - $TitleLink = "https://$CIPPUrl/endpoint/MEM/devices?customerId=$($Customer.customerId)" + $TitleLink = "https://$CIPPUrl/endpoint/MEM/devices?tenantFilter=$($Customer.defaultDomainName)" $DeviceCardBodyHTML = $DeviceComplianceChartHTML + $DeviceOsChartHTML + $DeviceOnlineChartHTML @@ -1996,7 +1801,7 @@ function Invoke-NinjaOneTenantSync { # Recommended Actions HTML $RecommendedActionsHTML = $Top5Actions | Select-Object 'Recommended Action', @{n = 'Score Impact'; e = { "+$($_.'Score Impact')%" } }, Category, @{n = 'Link'; e = { '' } } | ConvertTo-Html -As Table -Fragment - $TitleLink = "https://security.microsoft.com/securescore?viewid=overview&tid=$($Customer.CustomerId)" + $TitleLink = "https://security.microsoft.com/securescore?viewid=overview&tid=$($Customer.customerId)" $SecureScoreCardBodyHTML = $SecureScoreHTML + [System.Web.HttpUtility]::HtmlDecode($RecommendedActionsHTML) -replace '
', '' $SecureScoreCardBodyHTML = $SecureScoreCardBodyHTML -replace '', '' @@ -2012,44 +1817,39 @@ function Invoke-NinjaOneTenantSync { try { $StandardsDefinitions = Get-Content 'config/standards.json' | ConvertFrom-Json -Depth 100 - - $Table = Get-CippTable -tablename 'standards' - - $Filter = "PartitionKey eq 'standards'" - - $AllStandards = (Get-CIPPAzDataTableEntity @Table -Filter $Filter).JSON | ConvertFrom-Json -Depth 100 - - $AppliedStandards = ($AllStandards | Where-Object { $_.Tenant -eq $Customer.defaultDomainName -or $_.Tenant -eq 'AllTenants' }) - - $ParsedStandards = foreach ($Standard in $AppliedStandards) { - [PSCustomObject]$Standards = $Standard.Standards - $Standards.PSObject.Properties | ForEach-Object { - $CheckValue = $_ - if ($CheckValue.value) { - $MatchedStandard = $StandardsDefinitions | Where-Object { ($_.name -split 'standards.')[1] -eq $CheckValue.name } - if (($MatchedStandard | Measure-Object).count -eq 1) { - '
  • ' + $($MatchedStandard.label) + ' (' + ($($Standard.Tenant)) + ')
  • ' - } + $AppliedStandards = Get-CIPPStandards -TenantFilter $Customer.defaultDomainName + $Templates = Get-CIPPTable 'templates' + $StandardTemplates = Get-CIPPAzDataTableEntity @Templates | Where-Object { $_.PartitionKey -eq 'StandardsTemplateV2' } + + $ParsedStandards = foreach ($Standard in $AppliedStandards) { + $Template = ($StandardTemplates | Where-Object { $_.RowKey -eq $Standard.TemplateId }).JSON | ConvertFrom-Json + $StandardInfo = $StandardsDefinitions | Where-Object { ($_.name -replace 'standards.', '') -eq $Standard.Standard } + $StandardLabel = $StandardInfo.label + $ParsedActions = foreach ($Action in $Standard.Settings.PSObject.Properties) { + if ($Action.Value -eq $true -and $Action.Name -in @('remediate', 'report', 'alert')) { + (Get-Culture).TextInfo.ToTitleCase($Action.Name) } } - + [PSCustomObject]@{ + Standard = $StandardLabel + Template = $Template.templateName + Actions = $ParsedActions -join ', ' + } } + $ParsedStandardsHTML = $ParsedStandards | ConvertTo-Html -As Table -Fragment + $StandardsTableHTML = '
    ' + (([System.Web.HttpUtility]::HtmlDecode($ParsedStandardsHTML) -replace '
    ', '') -replace '', '') + '' } catch { - $ParsedStandards = 'No standards applied or error retrieving standards' + $StandardsTableHTML = 'No standards applied or error retrieving standards' } - - $TitleLink = "https://$CIPPUrl/tenant/standards/list-applied-standards?customerId=$($Customer.customerId)" - - $CIPPStandardsBodyHTML = '
      ' + $ParsedStandards + '
    ' - - $CIPPStandardsSummaryCardHTML = Get-NinjaOneCard -Title 'CIPP Applied Standards' -Body $CIPPStandardsBodyHTML -Icon 'fas fa-shield-halved' -TitleLink $TitleLink + $TitleLink = "https://$CIPPUrl/tenant/standards/list-standards" + $CIPPStandardsSummaryCardHTML = Get-NinjaOneCard -Title 'CIPP Applied Standards' -Body $StandardsTableHTML -Icon 'fas fa-shield-halved' -TitleLink $TitleLink ### License Card Write-Information 'License Details' $LicenseTableHTML = $LicensesParsed | Sort-Object 'License Name' | ConvertTo-Html -As Table -Fragment $LicenseTableHTML = '
    ' + (([System.Web.HttpUtility]::HtmlDecode($LicenseTableHTML) -replace '
    ', '') -replace '', '') + '' - $TitleLink = "https://$CIPPUrl/tenant/administration/list-licenses?customerId=$($Customer.customerId)" + $TitleLink = "https://$CIPPUrl/tenant/reports/list-licenses?tenantFilter=$($Customer.defaultDomainName)" $LicensesSummaryCardHTML = Get-NinjaOneCard -Title 'Licenses' -Body $LicenseTableHTML -Icon 'fas fa-chart-bar' -TitleLink $TitleLink @@ -2097,7 +1897,7 @@ function Invoke-NinjaOneTenantSync { ) Description = 'Unused Licenses' Colour = $ResultColour - Link = "https://$CIPPUrl/tenant/standards/bpa-report?SearchNow=true&Report=CIPP+Best+Practices+v1.5+-+Tenant+view&tenantFilter=$($Customer.customerId)" + Link = "https://$CIPPUrl/tenant/standards/bpa-report?tenantFilter=$($Customer.defaultDomainName)" }) @@ -2128,7 +1928,7 @@ function Invoke-NinjaOneTenantSync { ) Description = 'Password Never Expires' Colour = $ResultColour - Link = "https://$CIPPUrl/tenant/standards/bpa-report?SearchNow=true&Report=CIPP+Best+Practices+v1.5+-+Tenant+view&tenantFilter=$($Customer.customerId)" + Link = "https://$CIPPUrl/tenant/standards/bpa-report?tenantFilter=$($Customer.defaultDomainName)" }) # oAuth App Consent @@ -2143,7 +1943,7 @@ function Invoke-NinjaOneTenantSync { ) Description = 'OAuth App Consent' Colour = $ResultColour - Link = "https://entra.microsoft.com/$($Customer.customerId)/#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/UserSettings" + Link = "https://entra.microsoft.com/$($Customer.defaultDomainName)/#view/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/~/UserSettings" }) } @@ -2167,7 +1967,7 @@ function Invoke-NinjaOneTenantSync { Value = ($licensedUsers | Measure-Object).count Description = 'Licensed Users' Colour = '#CCCCCC' - Link = "https://$CIPPUrl/identity/administration/users?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/identity/administration/users?tenantFilter=$($Customer.defaultDomainName)" }) # Devices @@ -2175,7 +1975,7 @@ function Invoke-NinjaOneTenantSync { Value = ($Devices | Measure-Object).count Description = 'Devices' Colour = '#CCCCCC' - Link = "https://$CIPPUrl/endpoint/MEM/devices?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/endpoint/MEM/devices?tenantFilter=$($Customer.defaultDomainName)" }) # Groups @@ -2183,7 +1983,7 @@ function Invoke-NinjaOneTenantSync { Value = ($AllGroups | Measure-Object).count Description = 'Groups' Colour = '#CCCCCC' - Link = "https://$CIPPUrl/identity/administration/groups?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/identity/administration/groups?tenantFilter=$($Customer.defaultDomainName)" }) # Roles @@ -2191,7 +1991,7 @@ function Invoke-NinjaOneTenantSync { Value = ($AllRoles | Measure-Object).count Description = 'Roles' Colour = '#CCCCCC' - Link = "https://$CIPPUrl/identity/administration/roles?customerId=$($Customer.customerId)" + Link = "https://$CIPPUrl/identity/administration/roles?tenantFilter=$($Customer.defaultDomainName)" }) @@ -2285,7 +2085,7 @@ function Invoke-NinjaOneTenantSync {
    $($ParsedUsers.count) users found in Tenant
    - Only the first 100 users are displayed here. To see all users please view users in CIPP. + Only the first 100 users are displayed here. To see all users please view users in CIPP.
    @@ -2331,6 +2131,7 @@ function Invoke-NinjaOneTenantSync { } catch { $Message = if ($_.ErrorDetails.Message) { Get-NormalizedError -Message $_.ErrorDetails.Message + Write-Information (Get-CippException -Exception $_ | ConvertTo-Json) } else { $_.Exception.message } diff --git a/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 b/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 index a4afea1d7c17..5e9834f3beb8 100644 --- a/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 +++ b/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 @@ -6,15 +6,16 @@ function New-PwPushLink { $Table = Get-CIPPTable -TableName Extensionsconfig $Configuration = ((Get-CIPPAzDataTableEntity @Table).config | ConvertFrom-Json).PWPush if ($Configuration.Enabled -eq $true) { - Set-PwPushConfig -Configuration $Configuration - $PushParams = @{ - Payload = $Payload - } - if ($Configuration.ExpireAfterDays) { $PushParams.ExpireAfterDays = $Configuration.ExpireAfterDays } - if ($Configuration.ExpireAfterViews) { $PushParams.ExpireAfterViews = $Configuration.ExpireAfterViews } - if ($Configuration.DeletableByViewer) { $PushParams.DeletableByViewer = $Configuration.DeletableByViewer } - if ($Configuration.AccountId) { $PushParams.AccountId = $Configuration.AccountId.value } try { + Set-PwPushConfig -Configuration $Configuration + $PushParams = @{ + Payload = $Payload + } + if ($Configuration.ExpireAfterDays) { $PushParams.ExpireAfterDays = $Configuration.ExpireAfterDays } + if ($Configuration.ExpireAfterViews) { $PushParams.ExpireAfterViews = $Configuration.ExpireAfterViews } + if ($Configuration.DeletableByViewer) { $PushParams.DeletableByViewer = $Configuration.DeletableByViewer } + if ($Configuration.AccountId) { $PushParams.AccountId = $Configuration.AccountId.value } + if ($PSCmdlet.ShouldProcess('Create a new PwPush link')) { $Link = New-Push @PushParams if ($Configuration.RetrievalStep) { diff --git a/Modules/CippExtensions/Public/PwPush/Set-PwPushConfig.ps1 b/Modules/CippExtensions/Public/PwPush/Set-PwPushConfig.ps1 index 6c816f6f5fc6..845b8e3caf49 100644 --- a/Modules/CippExtensions/Public/PwPush/Set-PwPushConfig.ps1 +++ b/Modules/CippExtensions/Public/PwPush/Set-PwPushConfig.ps1 @@ -19,21 +19,20 @@ function Set-PwPushConfig { } if (![string]::IsNullOrEmpty($Configuration.EmailAddress) -or $Configuration.UseBearerAuth -eq $true) { $ApiKey = Get-ExtensionAPIKey -Extension 'PWPush' - - if (![string]::IsNullOrEmpty($ApiKey)) { - $InitParams.APIKey = $ApiKey - } - if (![string]::IsNullOrEmpty($Configuration.EmailAddress)) { - $InitParams.EmailAddress = $Configuration.EmailAddress - } if ($Configuration.UseBearerAuth -eq $true) { - $InitParams.AccountType = 'Pro' + $InitParams.Bearer = $ApiKey + } elseif (![string]::IsNullOrEmpty($ApiKey)) { + if (![string]::IsNullOrEmpty($Configuration.EmailAddress)) { + $InitParams.EmailAddress = $Configuration.EmailAddress + } + $InitParams.APIKey = $ApiKey } } $Module = Get-Module PassPushPosh -ListAvailable - Write-Host $Module.Version + Write-Information "PWPush Version: $($Module.Version)" if ($PSCmdlet.ShouldProcess('Initialize-PassPushPosh')) { + Write-Information ($InitParams | ConvertTo-Json) Initialize-PassPushPosh @InitParams } } diff --git a/Modules/PassPushPosh/1.2.1/PSGetModuleInfo.xml b/Modules/PassPushPosh/1.3.2/PSGetModuleInfo.xml similarity index 71% rename from Modules/PassPushPosh/1.2.1/PSGetModuleInfo.xml rename to Modules/PassPushPosh/1.3.2/PSGetModuleInfo.xml index 0189606b3555..0621c3dcbeb3 100644 --- a/Modules/PassPushPosh/1.2.1/PSGetModuleInfo.xml +++ b/Modules/PassPushPosh/1.3.2/PSGetModuleInfo.xml @@ -7,13 +7,13 @@ PassPushPosh - 1.2.0 + 1.3.2 Module PassPushPosh is a PowerShell Module for accessing the Password Pusher application via API. It supports creating, retrieving, and deleting anonymous and authenticated pushes and getting Push and Dashboard data for authenticated users. Adam Burley AdamBurley Adam Burley, 2022 -
    2025-02-06T18:21:26-05:00
    +
    2025-03-01T20:45:35-05:00
    https://www.gnu.org/licenses/gpl-3.0.en.html @@ -41,12 +41,24 @@ - DscResource + Workflow + + RoleCapability + + + + DscResource + + + + Cmdlet + + Function @@ -55,6 +67,7 @@ Get-Dashboard Get-Push Get-PushAccount + Get-PushApiVersion Get-PushAuditLog Get-SecretLink Initialize-PassPushPosh @@ -63,14 +76,6 @@ - - RoleCapability - - - - Workflow - - Command @@ -79,6 +84,7 @@ Get-Dashboard Get-Push Get-PushAccount + Get-PushApiVersion Get-PushAuditLog Get-SecretLink Initialize-PassPushPosh @@ -87,14 +93,10 @@ - - Cmdlet - - - 1.2.0 - Add compatibility with Premium and Pro API endpoints and branding._x000D__x000A_ 1.0.0 - Major refactor, add capabilities and improve testing and build process._x000D__x000A_ 0.3.0 - Remove route translations from URI segments for compatibility with PasswordPusher v1.42.0. See pglombardo/PasswordPusher/pull/2353 + 1.3.2 - Bug fix for push JSON changes, add Version endpoint_x000D__x000A_ 1.2.0 - Add compatibility with Premium and Pro API endpoints and branding._x000D__x000A_ 1.0.0 - Major refactor, add capabilities and improve testing and build process._x000D__x000A_ 0.3.0 - Remove route translations from URI segments for compatibility with PasswordPusher v1.42.0. See pglombardo/PasswordPusher/pull/2353 @@ -111,19 +113,19 @@ Adam Burley, 2022 PassPushPosh is a PowerShell Module for accessing the Password Pusher application via API. It supports creating, retrieving, and deleting anonymous and authenticated pushes and getting Push and Dashboard data for authenticated users. False - 1.2.0 - Add compatibility with Premium and Pro API endpoints and branding._x000D__x000A_ 1.0.0 - Major refactor, add capabilities and improve testing and build process._x000D__x000A_ 0.3.0 - Remove route translations from URI segments for compatibility with PasswordPusher v1.42.0. See pglombardo/PasswordPusher/pull/2353 + 1.3.2 - Bug fix for push JSON changes, add Version endpoint_x000D__x000A_ 1.2.0 - Add compatibility with Premium and Pro API endpoints and branding._x000D__x000A_ 1.0.0 - Major refactor, add capabilities and improve testing and build process._x000D__x000A_ 0.3.0 - Remove route translations from URI segments for compatibility with PasswordPusher v1.42.0. See pglombardo/PasswordPusher/pull/2353 True True - 2 - 221 - 14279 - 2/6/2025 6:21:26 PM -05:00 - 2/6/2025 6:21:26 PM -05:00 - 2/6/2025 6:40:00 PM -05:00 - PSEdition_Core Windows Linux MacOS Password PSModule PSFunction_Get-Dashboard PSCommand_Get-Dashboard PSFunction_Get-Push PSCommand_Get-Push PSFunction_Get-PushAccount PSCommand_Get-PushAccount PSFunction_Get-PushAuditLog PSCommand_Get-PushAuditLog PSFunction_Get-SecretLink PSCommand_Get-SecretLink PSFunction_Initialize-PassPushPosh PSCommand_Initialize-PassPushPosh PSFunction_New-Push PSCommand_New-Push PSFunction_Remove-Push PSCommand_Remove-Push PSIncludes_Function + 4 + 247 + 16233 + 3/1/2025 8:45:35 PM -05:00 + 3/1/2025 8:45:35 PM -05:00 + 3/2/2025 9:40:00 AM -05:00 + PSEdition_Core Windows Linux MacOS Password PSModule PSFunction_Get-Dashboard PSCommand_Get-Dashboard PSFunction_Get-Push PSCommand_Get-Push PSFunction_Get-PushAccount PSCommand_Get-PushAccount PSFunction_Get-PushApiVersion PSCommand_Get-PushApiVersion PSFunction_Get-PushAuditLog PSCommand_Get-PushAuditLog PSFunction_Get-SecretLink PSCommand_Get-SecretLink PSFunction_Initialize-PassPushPosh PSCommand_Initialize-PassPushPosh PSFunction_New-Push PSCommand_New-Push PSFunction_Remove-Push PSCommand_Remove-Push PSIncludes_Function False - 2025-02-06T18:40:00Z - 1.2.0 + 2025-03-02T09:40:00Z + 1.3.2 Adam Burley false Module @@ -133,7 +135,7 @@ Burley.dev
    - C:\GitHub\CIPP Workspace\CIPP-API\Modules\PassPushPosh\1.2.0 + C:\GitHub\CIPP Workspace\CIPP-API\Modules\PassPushPosh\1.3.2 diff --git a/Modules/PassPushPosh/1.2.1/PassPushPosh.psd1 b/Modules/PassPushPosh/1.3.2/PassPushPosh.psd1 similarity index 95% rename from Modules/PassPushPosh/1.2.1/PassPushPosh.psd1 rename to Modules/PassPushPosh/1.3.2/PassPushPosh.psd1 index 0e676121021f..7243d064ae4e 100644 --- a/Modules/PassPushPosh/1.2.1/PassPushPosh.psd1 +++ b/Modules/PassPushPosh/1.3.2/PassPushPosh.psd1 @@ -3,7 +3,7 @@ # # Generated by: Adam Burley # -# Generated on: 2/8/2025 +# Generated on: 3/1/2025 # @{ @@ -12,7 +12,7 @@ RootModule = 'PassPushPosh.psm1' # Version number of this module. -ModuleVersion = '1.2.1' +ModuleVersion = '1.3.2' # Supported PSEditions CompatiblePSEditions = 'Core' @@ -69,7 +69,7 @@ PowerShellVersion = '7.0' # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = @('Get-Dashboard','Get-Push','Get-PushAccount','Get-PushAuditLog','Get-SecretLink','Initialize-PassPushPosh','New-Push','Remove-Push') +FunctionsToExport = @('Get-Dashboard','Get-Push','Get-PushAccount','Get-PushApiVersion','Get-PushAuditLog','Get-SecretLink','Initialize-PassPushPosh','New-Push','Remove-Push') # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() @@ -108,6 +108,7 @@ PrivateData = @{ # ReleaseNotes of this module ReleaseNotes = ' + 1.3.2 - Bug fix for push JSON changes, add Version endpoint 1.2.0 - Add compatibility with Premium and Pro API endpoints and branding. 1.0.0 - Major refactor, add capabilities and improve testing and build process. 0.3.0 - Remove route translations from URI segments for compatibility with PasswordPusher v1.42.0. See pglombardo/PasswordPusher/pull/2353' diff --git a/Modules/PassPushPosh/1.2.1/PassPushPosh.psm1 b/Modules/PassPushPosh/1.3.2/PassPushPosh.psm1 similarity index 63% rename from Modules/PassPushPosh/1.2.1/PassPushPosh.psm1 rename to Modules/PassPushPosh/1.3.2/PassPushPosh.psm1 index e4d7643eec11..d1276e11e6cd 100644 --- a/Modules/PassPushPosh/1.2.1/PassPushPosh.psm1 +++ b/Modules/PassPushPosh/1.3.2/PassPushPosh.psm1 @@ -3,8 +3,6 @@ class PasswordPush { [string]$Note [string]$Payload - [string] hidden $__UrlToken - [string] hidden $__LinkBase [bool]$RetrievalStep [bool]$IsExpired [bool]$IsDeleted @@ -16,11 +14,12 @@ class PasswordPush { [DateTime]$DateCreated [DateTime]$DateUpdated [DateTime]$DateExpired - # Added by constructors: - #[string]$URLToken - #[string]$Link - #[string]$LinkDirect - #[string]$LinkRetrievalStep + [int]$AccountId + [string]$UrlToken + [string]$Link + [string]$LinkDirect + [string]$LinkRetrievalStep + #[PSCustomObject[]]$Files # Added if present PasswordPush() { # Blank constructor @@ -28,16 +27,7 @@ class PasswordPush { # Constructor to allow casting or explicit import from a PSObject Representing the result of an API call PasswordPush([PSCustomObject]$APIresponseObject) { - throw NotImplementedException - } - - # Allow casting or explicit import from the raw Content of an API call - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Scope = 'Function', Justification = 'Global variables are used for module session helpers.')] - PasswordPush([string]$JsonResponse) { - Write-Debug 'New PasswordPush object instantiated from JsonResponse string' - Initialize-PassPushPosh # Initialize the module if not yet done. - - $_j = $JsonResponse | ConvertFrom-Json + $_j = $APIresponseObject $this.Note = $_j.note $this.Payload = $_j.payload $this.IsExpired = $_j.expired @@ -51,35 +41,18 @@ class PasswordPush { $this.DateUpdated = $_j.updated_at $this.DateExpired = if ($_j.expired_on) { $_j.expired_on } else { [DateTime]0 } $this.RetrievalStep = $_j.retrieval_step - - - $this | Add-Member -Name 'UrlToken' -MemberType ScriptProperty -Value { - return $this.__UrlToken - } -SecondValue { - $this.__UrlToken = $_ - $this.__LinkBase = $_j.html_url ?? "$Script:PPPBaseUrl/p/$($this.__UrlToken)" - } - $this.__UrlToken = $_j.url_token - $this.__LinkBase = $_j.html_url ?? "$Script:PPPBaseUrl/p/$($this.__UrlToken)" - $this | Add-Member -Name 'LinkDirect' -MemberType ScriptProperty -Value { return $this.__LinkBase } -SecondValue { - Write-Warning 'LinkDirect is a read-only calculated member.' - Write-Debug 'Link* members are calculated based on the Global BaseUrl and Push Retrieval Step values' - } - $this | Add-Member -Name 'LinkRetrievalStep' -MemberType ScriptProperty -Value { return "$($this.__LinkBase)/r" } -SecondValue { - Write-Warning 'LinkRetrievalStep is a read-only calculated member.' - Write-Debug 'Link* members are calculated based on the Global BaseUrl and Push Retrieval Step values' - } - $this | Add-Member -Name 'Link' -MemberType ScriptProperty -Value { - $_Link = if ($this.RetrievalStep) { $this.LinkRetrievalStep } else { $this.LinkDirect } - Write-Debug "Presented Link: $_link" - $_Link - } -SecondValue { - Write-Warning 'Link is a read-only calculated member.' - Write-Debug 'Link* members are calculated based on the Global BaseUrl and Push Retrieval Step values' + $this.AccountId = $_j.account_id + $this.UrlToken = $_j.url_token + $this.LinkDirect = $_j.json_url ? $_j.json_url.Replace('.json','') : "$Script:PPPBaseUrl/p/$($this.UrlToken)" + $this.LinkRetrievalStep = $this.LinkDirect, '/r' -join '' + $this.Link = $_j.html_url ?? $this.RetrievalStep -eq $true ? $this.LinkRetrievalStep : $this.LinkDirect + + if ($_j.Files) { + $this | Add-Member -MemberType NoteProperty -Name Files -Value $_j.files } } } -#EndRegion '.\Classes\PasswordPush.ps1' 80 +#EndRegion '.\Classes\PasswordPush.ps1' 53 #Region '.\Classes\TypeAccelerators.ps1' -1 # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_classes?view=powershell-7.4#exporting-classes-with-type-accelerators @@ -91,6 +64,7 @@ $ExportableTypes =@( $TypeAcceleratorsClass = [psobject].Assembly.GetType( 'System.Management.Automation.TypeAccelerators' ) +<# # Ensure none of the types would clobber an existing type accelerator. # If a type accelerator with the same name exists, throw an exception. $ExistingTypeAccelerators = $TypeAcceleratorsClass::Get @@ -108,10 +82,12 @@ foreach ($Type in $ExportableTypes) { $Type.FullName ) } -} +}#> # Add type accelerators for every exportable type. foreach ($Type in $ExportableTypes) { + try { $TypeAcceleratorsClass::Add($Type.FullName, $Type) + } catch {} } # Remove type accelerators when the module is removed. ($MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { @@ -189,13 +165,12 @@ function ConvertTo-PasswordPush { param( [parameter(Mandatory, ValueFromPipeline)] [ValidateNotNullOrEmpty()] - $JsonResponse + [PSCustomObject]$JsonResponse ) process { try { - $jsonObject = if ($JsonResponse -is [string]) { $JsonResponse | ConvertFrom-Json } else { $JsonResponse } - foreach ($o in $jsonObject) { - [PasswordPush]($o | ConvertTo-Json) # TODO fix this mess + foreach ($o in $JsonResponse) { + [PasswordPush]::New($o) } } catch { @@ -205,7 +180,7 @@ function ConvertTo-PasswordPush { } } } -#EndRegion '.\Private\ConvertTo-PasswordPush.ps1' 84 +#EndRegion '.\Private\ConvertTo-PasswordPush.ps1' 83 #Region '.\Private\Format-PasswordPusherSecret.ps1' -1 function Format-PasswordPusherSecret { @@ -238,13 +213,18 @@ function Format-PasswordPusherSecret { #Region '.\Private\Invoke-PasswordPusherAPI.ps1' -1 function Invoke-PasswordPusherAPI { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'Body')] [OutputType([PSCustomObject])] param( [string]$Endpoint, [Microsoft.PowerShell.Commands.WebRequestMethod]$Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get, + + [Parameter(ParameterSetName = 'Body')] [object]$Body, + [Parameter(ParameterSetName = 'Form')] + [object]$Form, + [Switch]$ReturnErrors ) process { @@ -253,18 +233,22 @@ function Invoke-PasswordPusherAPI { $iwrSplat = @{ 'Method' = $Method - 'ContentType' = 'application/json' - 'Body' = ($body | ConvertTo-Json) 'Uri' = $_uri 'UserAgent' = $Script:PPPUserAgent } + if ($PSCmdlet.ParameterSetName -eq 'Form') { + $iwrSplat.Form = $Form + } else { + $iwrSplat.Body = ($body | ConvertTo-Json) + $iwrSplat.ContentType = 'application/json' + } if ($Script:PPPHeaders.'X-User-Token') { $iwrSplat['Headers'] = $Script:PPPHeaders - Write-Debug "Authenticated with API token $(Format-PasswordPusherSecret -Secret $Script:PPPHeaders.'X-User-Token' -ShowSample)" + Write-Debug "Authenticated with X-User-Token $(Format-PasswordPusherSecret -Secret $Script:PPPHeaders.'X-User-Token' -ShowSample)" } if ($Script:PPPHeaders.'Authorization') { $iwrSplat['Headers'] = $Script:PPPHeaders - Write-Debug "Authenticated with API token $(Format-PasswordPusherSecret -Secret $Script:PPPHeaders.'Authorization' -ShowSample)" + Write-Debug "Authenticated with Bearer token $(Format-PasswordPusherSecret -Secret $Script:PPPHeaders.'Authorization' -ShowSample)" } $callInfo = "$Method $_uri" Write-Verbose "Sending HTTP request: $callInfo" @@ -283,7 +267,23 @@ function Invoke-PasswordPusherAPI { } } } -#EndRegion '.\Private\Invoke-PasswordPusherAPI.ps1' 47 +#EndRegion '.\Private\Invoke-PasswordPusherAPI.ps1' 56 +#Region '.\Private\New-PasswordPusherUserAgent.ps1' -1 + +function New-PasswordPusherUserAgent { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Function does not change state.')] + [CmdletBinding()] + [OutputType([string])] + param() + $osVersion = [System.Environment]::OSVersion + $userAtDomain = '{0}@{1}' -f [System.Environment]::UserName, [System.Environment]::UserDomainName + $uAD64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($userAtDomain)) + Write-Debug "$userAtDomain transformed to $uAD64. First 20 characters $($uAD64.Substring(0,20))" + + # Version tag is replaced by the semantic version number at build time. See PassPushPosh/issues/11 for context + "PassPushPosh/1.3.2 $osVersion/$($uAD64.Substring(0,20))" +} +#EndRegion '.\Private\New-PasswordPusherUserAgent.ps1' 14 #Region '.\Public\Get-Dashboard.ps1' -1 <# @@ -354,6 +354,14 @@ function Get-Dashboard { .PARAMETER Passhrase An additional phrase required to view the secret. Required if the Push was created with a Passphrase. + .PARAMETER OutFolder + For File pushes, a folder path to save files. If the folder path does not exist + it will be created. Files are saved with their original names. + + .PARAMETER IncludePushObject + When saving files from a file push, also save the push data itself. This will + create a JSON object in the same path as the files with the + .INPUTS [string] @@ -369,19 +377,13 @@ function Get-Dashboard { .LINK https://github.com/adamburley/PassPushPosh/blob/main/Docs/Get-Push.md - .LINK - https://pwpush.com/api/1.0/passwords.en.html - - .LINK - https://github.com/pglombardo/PasswordPusher/blob/c2909b2d5f1315f9b66939c9fbc7fd47b0cfeb03/app/controllers/passwords_controller.rb#L89 - .LINK New-Push #> function Get-Push { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "Passphrase", Justification = "DE0001: SecureString shouldn't be used")] - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'Text')] [OutputType([PasswordPush])] param( [Parameter(Mandatory, ValueFromPipeline)] @@ -390,20 +392,50 @@ function Get-Push { $URLToken, [Parameter()] - [String]$Passphrase + [String]$Passphrase, + + [Parameter(ParameterSetName = 'Out File')] + [Alias('OutFile')] + [System.IO.DirectoryInfo]$OutFolder, + + [Parameter(ParameterSetName = 'Out File')] + [switch]$IncludePushObject ) begin { Initialize-PassPushPosh -Verbose:$VerbosePreference -Debug:$DebugPreference } process { $endpoint = $Passphrase ? "p/$URLToken.json?passphrase=$Passphrase" : "p/$URLToken.json" $result = Invoke-PasswordPusherAPI -Endpoint $endpoint -ReturnErrors - switch ($result.error){ - 'not-found' { Write-Error -Message "Push not found. Check the token you provided. Tokens are case-sensitive." } - 'This push has a passphrase that was incorrect or not provided.' { if ($Passphrase) { Write-Error -Message "Incorrect passphrase provided." } else { Write-Error -Message "Passphrase required. Specify with the -Passphrase parameter." } } - default { $result | ConvertTo-PasswordPush } + if ($result.error){ + if ($result.error -eq 'not-found') { Write-Error -Message "Push not found. Check the token you provided. Tokens are case-sensitive." } + if ($result.error -eq 'This push has a passphrase that was incorrect or not provided.') { if ($Passphrase) { Write-Error -Message "Incorrect passphrase provided." } else { Write-Error -Message "Passphrase required. Specify with the -Passphrase parameter." } } + } + $pushObject = $result | ConvertTo-PasswordPush + if ($OutFolder) { + if ($pushObject.Files.Count -gt 0) { + if (-not (Test-Path -Path $OutFolder -PathType Container)) { + New-Item -Path $OutFolder -ItemType Directory | Out-Null + Write-Verbose "$OutFolder does not exist and was created." + } else { + Write-Verbose "Saving files to $OutFolder" + } + foreach ($f in $pushObject.Files){ + Write-Verbose "Saving $($f.filename) [$($f.content_type)]" + Invoke-WebRequest -Uri $f.url -OutFile (Join-Path -Path $OutFolder -ChildPath $f.filename) + } + if ($IncludePushObject) { + $pushObject | ConvertTo-Json -Depth 10 | Out-File (Join-Path $OutFolder -ChildPath "Push_$($pushObject.UrlToken).json") + } + } else { + Write-Warning "No files were included in this push. Nothing was saved." + } + $pushObject + } + else { + $pushObject } } } -#EndRegion '.\Public\Get-Push.ps1' 65 +#EndRegion '.\Public\Get-Push.ps1' 97 #Region '.\Public\Get-PushAccount.ps1' -1 <# @@ -428,6 +460,16 @@ function Get-PushAccount { } } #EndRegion '.\Public\Get-PushAccount.ps1' 22 +#Region '.\Public\Get-PushApiVersion.ps1' -1 + +function Get-PushApiVersion { + [CmdletBinding()] + [OutputType([PSCustomObject])] + param() + Initialize-PassPushPosh -Verbose:$VerbosePreference -Debug:$DebugPreference + Invoke-PasswordPusherAPI -Endpoint 'api/v1/version.json' +} +#EndRegion '.\Public\Get-PushApiVersion.ps1' 8 #Region '.\Public\Get-PushAuditLog.ps1' -1 <# @@ -585,17 +627,27 @@ function Get-SecretLink { This function is called automatically if needed, defaulting to the public pwpush.com service. - .PARAMETER AccountType - For paid users, specify the account type as Premium or Pro. Not required for free accounts and self-hosted. + .PARAMETER Bearer + API key for authenticated calls. Supported on hosted instance and OSS v1.51.0 and newer. + + .PARAMETER ApiKey + API key for authenticated calls. Supports older OSS installs. + Also supports Bearer autodetection. This will be removed in a future version. .PARAMETER EmailAddress Email address for authenticated calls. + NOTE: This is only required for legacy X-User-Token authentication. If using hosted pwpush.com + services or OSS v1.51.0 or newer use -Bearer - .PARAMETER ApiKey - API key for authenticated calls. + .PARAMETER UseLegacyAuth + Use legacy X-User-Token. Supportsversions of Password Pusher OSS older than v1.51.0. + If this is not set, but -ApiKey and -EmailAddress are specified the module will attempt to + auto-detect the correct connection. .PARAMETER BaseUrl - Base URL for API calls. Allows use of module with private instances of Password Pusher + Base URL for API calls. Allows use of custom domains with hosted Password Pusher as well as specifying + a private instance. + Default: https://pwpush.com .PARAMETER UserAgent @@ -608,23 +660,23 @@ function Get-SecretLink { .PARAMETER Force Force setting new information. If module is already initialized you can use this to - Re-initialize with default settings. Implied if either ApiKey or BaseUrl is provided. + re-initialize the module. If not specified and there is an existing session the request is ignored. .EXAMPLE - # Initialize with default settings + # Default settings PS > Initialize-PassPushPosh .EXAMPLE - # Initialize with authentication - PS > Initialize-PassPushPosh -EmailAddress 'youremail@example.com' -ApiKey '239jf0jsdflskdjf' -Verbose - - VERBOSE: Initializing PassPushPosh. ApiKey: [x-kdjf], BaseUrl: https://pwpush.com + # Authentication + PS > Initialize-PassPushPosh -Bearer 'myreallylongapikey' .EXAMPLE - # Initialize with another server with authentication - PS > Initialize-PassPushPosh -BaseUrl https://myprivatepwpushinstance.com -EmailAddress 'youremail@example.com' -ApiKey '239jf0jsdflskdjf' -Verbose + # Initialize with another domain - may be a private instance or a hosted instance with custom domain + PS > Initialize-PassPushPosh -BaseUrl https://myprivatepwpushinstance.example.com -Bearer 'myreallylongapikey' - VERBOSE: Initializing PassPushPosh. ApiKey: [x-kdjf], BaseUrl: https://myprivatepwpushinstance.com + .EXAMPLE + # Legacy authentication support + PS > Initialize-PassPushPosh -ApiKey 'myreallylongapikey' -EmailAddress 'myregisteredemail@example.com' -UseLegacyAuthentication -BaseUrl https://myprivatepwpushinstance.example.com .EXAMPLE # Set a custom User Agent @@ -634,29 +686,30 @@ function Get-SecretLink { https://github.com/adamburley/PassPushPosh/blob/main/Docs/Initialize-PassPushPosh.md .NOTES - -WhatIf setting for Set-Variable -Script is disabled, otherwise -WhatIf - calls for other functions would return incorrect data in the case this - function has not yet run. + The use of X-USER-TOKEN for authentication is depreciated and will be removed in a future release of the API. + This module will support it via legacy mode, initially by attempting to auto-detect if Bearer is supported. + New code using this module should use -Bearer (most cases) or -UseLegacyAuthentication (self-hosted older versions). + In a future release the module will default to Bearer unless the -UseLegacyAuthentication switch is set. + #> function Initialize-PassPushPosh { [CmdletBinding(DefaultParameterSetName = 'Anonymous')] param ( - [Parameter(ParameterSetName = 'Pro')] - [ValidateSet('Premium', 'Pro')] - [string]$AccountType = 'Pro', + [Parameter(ParameterSetName = 'Authenticated')] + [string]$Bearer, + + [Parameter(Mandatory, Position = 0, ParameterSetName = 'Legacy Auth')] + [ValidateLength(5, 256)] + [string]$ApiKey, - [Parameter(Mandatory, Position = 0, ParameterSetName = 'Authenticated')] + [Parameter(Mandatory, Position = 1, ParameterSetName = 'Legacy Auth')] [ValidatePattern('.+\@.+\..+', ErrorMessage = 'Please specify a valid email address')] [string]$EmailAddress, - [Parameter(Mandatory, ParameterSetName = 'Pro')] - [Parameter(Mandatory, Position = 1, ParameterSetName = 'Authenticated')] - [ValidateLength(5, 256)] - [string]$ApiKey, + [Parameter(ParameterSetName = 'Legacy Auth')] + [switch]$UseLegacyAuthentication, - [Parameter(Position = 0, ParameterSetName = 'Anonymous')] - [Parameter(Position = 2, ParameterSetName = 'Authenticated')] - [Parameter(ParameterSetName = 'Pro')] + [Parameter()] [ValidatePattern('^https?:\/\/[a-zA-Z0-9-_]+.[a-zA-Z0-9]+')] [string]$BaseUrl, @@ -665,60 +718,65 @@ function Initialize-PassPushPosh { [string] $UserAgent, - [Parameter()][switch]$Force + [Parameter()] + [switch]$Force ) - if ($Script:PPPBaseURL -and $true -inotin $Force, [bool]$ApiKey, [bool]$BaseUrl, [bool]$UserAgent) { Write-Debug -Message 'PassPushPosh is already initialized.' } + if ($Script:PPPBaseURL -and -not $Force) { Write-Debug -Message 'PassPushPosh is already initialized.' } else { - $defaultBaseUrl = 'https://pwpush.com' - $apiKeyOutput = $ApiKey ? (Format-PasswordPusherSecret -Secret $ApiKey -ShowSample) : 'None' + $_baseUrl = $PSBoundParameters.ContainsKey('BaseUrl') ? $BaseUrl : 'https://pwpush.com' + $_apiKey = $PSBoundParameters.ContainsKey('Bearer') ? $Bearer : $ApiKey - if (-not $Script:PPPBaseURL) { - # Not initialized - if (-not $BaseUrl) { $BaseUrl = $defaultBaseUrl } - Write-Verbose "Initializing PassPushPosh. ApiKey: [$apiKeyOutput], BaseUrl: $BaseUrl" - } - elseif ($Force -or $ApiKey -or $BaseURL) { - if (-not $BaseUrl) { $BaseUrl = $defaultBaseUrl } - $oldApiKeyOutput = if ($Script:PPPApiKey) { Format-PasswordPusherSecret -Secret $Script:PPPApiKey -ShowSample } else { 'None' } - Write-Verbose "Re-initializing PassPushPosh. Old ApiKey: [$oldApiKeyOutput] New ApiKey: [$apiKeyOutput], Old BaseUrl: $Script:PPPBaseUrl New BaseUrl: $BaseUrl" - } - if ($PSCmdlet.ParameterSetName -eq 'Authenticated') { + $apiKeySample = $_apiKey ? (Format-PasswordPusherSecret -Secret $_apiKey -ShowSample) : 'None' - Set-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -Value @{ - 'X-User-Email' = $EmailAddress - 'X-User-Token' = $ApiKey + $_AuthType = $PSCmdlet.ParameterSetName -iin 'Anonymous', 'Authenticated' ? $PSCmdlet.ParameterSetName : $UseLegacyAuthentication ? 'Legacy' : 'Automatic' + + switch ($_AuthType) { + 'Anonymous' { + # module is reinitialized from an authenticated to an anonymous session + Remove-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -ErrorAction SilentlyContinue } - } - elseif ($PSCmdlet.ParameterSetName -eq 'Pro') { - Write-Debug "Initializing for paid tier $($AccountType)" - Set-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -Value @{ - 'Authorization' = "Bearer $ApiKey" + 'Authenticated' { + Write-Debug 'Bearer auth specified.' + Set-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -Value @{ + 'Authorization' = "Bearer $_apiKey" + } + } + 'Legacy' { + Write-Debug 'Legacy auth specified.' + Set-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -Value @{ + 'X-User-Email' = $EmailAddress + 'X-User-Token' = $_apiKey + } + } + 'Automatic' { + Write-Debug 'Legacy auth status not specified Checking for /version' + if ((Invoke-RestMethod "$_baseUrl/api/v1/version.json" -SkipHttpErrorCheck).Api_Version -gt 1.0) { + Write-Debug "Current version detected via /version" + Set-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -Value @{ + 'Authorization' = "Bearer $_apiKey" + } + } else { + Write-Warning 'Instance does not appear to support modern Bearer authentication.' + Write-Warning 'The module will fall back to using legacy authentication.' + Write-Warning 'If you are connecting to a self-hosted instance, verify it is up to date.' + Write-Warning 'If you know you need legacy (X-User-Token) authentication include Invoke-PassPushPosh -UseLegacyAuth $true' + Write-Warning 'To skip the step check and this warning.' + Set-Variable -Scope Script -Name PPPHeaders -WhatIf:$false -Force -Value @{ + 'X-User-Email' = $EmailAddress + 'X-User-Token' = $_apiKey + } + } } - } - elseif ($Script:PPPHeaders) { - # Remove if present - covers case where module is reinitialized from an authenticated to an anonymous session - Remove-Variable -Scope Script -Name PPPHeaders -WhatIf:$false } - if (-not $UserAgent) { - $osVersion = [System.Environment]::OSVersion - $userAtDomain = '{0}@{1}' -f [System.Environment]::UserName, [System.Environment]::UserDomainName - $uAD64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($userAtDomain)) - Write-Debug "$userAtDomain transformed to $uAD64. First 20 characters $($uAD64.Substring(0,20))" - # Version tag is replaced by the semantic version number at build time. See PassPushPosh/issues/11 for context - $UserAgent = "PassPushPosh/1.2.1 $osVersion/$($uAD64.Substring(0,20))" - # $UserAgent = "PassPushPosh/$((Get-Module -Name PassPushPosh).Version.ToString()) $osVersion/$($uAD64.Substring(0,20))" - Write-Verbose "Generated user agent: $UserAgent" - } - else { - Write-Verbose "Using specified user agent: $UserAgent" - } + Set-Variable -WhatIf:$false -Scope Script -Name PPPUserAgent -Value ($PSBoundParameters.ContainsKey('UserAgent') ? $UserAgent : (New-PasswordPusherUserAgent)) + Set-Variable -WhatIf:$false -Scope Script -Name PPPBaseURL -Value $_baseUrl.TrimEnd('/') - Set-Variable -WhatIf:$false -Scope Script -Name PPPBaseURL -Value $BaseUrl.TrimEnd('/') - Set-Variable -WhatIf:$false -Scope Script -Name PPPUserAgent -Value $UserAgent + Write-Verbose -Message "PassPushPosh Initialized with these settings: Account type: [$_AuthType] API Key: $apiKeySample Base URL: [$_baseUrl]" + Write-Verbose -Message "User Agent: $Script:PPPUserAgent" } } -#EndRegion '.\Public\Initialize-PassPushPosh.ps1' 146 +#EndRegion '.\Public\Initialize-PassPushPosh.ps1' 162 #Region '.\Public\New-Push.ps1' -1 <# @@ -733,13 +791,31 @@ function Initialize-PassPushPosh { are always provided at LinkRetrievalStep and LinkDirect properties. .PARAMETER Payload - The URL password or secret text to share. + Generic text value to share. Use with -Kind to create arbitrary push types. + Payload is required for all types except File. For QR and URL pushes you + may directly specify those types by using the -QR and -URL parameters. + + .PARAMETER QR + Create a QR-type secret with this text value. May be a link or other text. + + .PARAMETER URL + Create a URL-type secret redirecting to this link. A fully-qualified URL is + required + + .PARAMETER File + Attach files to a push. Up to 10 files in all referenced folders and paths + may be specified by passing a file or folder path or array of paths or a + DirectoryInfo or FileInfo object. + + File pushes can be files only, files with text, or files with a QR code. + To add text, simply use -Payload. To specify a QR code, use -QR or use + -Payload 'your value' -Type QR .PARAMETER Passphrase Require recipients to enter this passphrase to view the created push. .PARAMETER Note - The note for this push. Visible only to the push creator. Requires authentication. + The note for this push. Visible only to the push creator. Requires authentication. .PARAMETER ExpireAfterDays Expire secret link and delete after this many days. @@ -759,6 +835,15 @@ function Initialize-PassPushPosh { .PARAMETER AccountId Account ID to associate with this push. Requires authentication. + If you have multiple accounts and you do not specify an account ID + Password Pusher will use the first account available, UNLESS you have a custom domain. + In that case it will default to the custom domain account IF you're connecting + to the custom domain for the API session. If you're connecting to pwpush.com, + it will use the unbranded / non-domain account. + + .PARAMETER Kind + The kind of Push to send. Defaults to text. If using -QR, -URL, or -File parameters + the correct kind is automatically selected and this parameter is ignored. .INPUTS [string] @@ -784,14 +869,30 @@ function Initialize-PassPushPosh { # "Burn after reading" style Push PS > New-Push -Payload "Still secret text!" -ExpireAfterViews 1 -RetrievalStep - .LINK - https://github.com/adamburley/PassPushPosh/blob/main/Docs/New-Push.md + .EXAMPLE + Create a URL push + PS > New-Push -URL 'https://example.com/coolplacetoforwardmyrecipientto' + + .EXAMPLE + Create a QR push + PS > New-Push -QR 'thing i want to show up when someone reads the QR code' + + .EXAMPLE + Create a file push + PS > New-Push -File 'C:\mytwofiles\mycoolfile.txt', 'C:\mytwofiles\mycoolfile2.txt' + or + PS > New-Push -File 'C:\mytwofiles' + or + PS > $myFolder = Get-ChildItem C:\mytwofiles + PS > New-Push -File $myFolder + + .EXAMPLE + Create a QR push using -Payload + PS > New-Push -Payload 'this is my qr code value' -Kind QR - .LINK - https://pwpush.com/api/1.0/passwords/create.en.html .LINK - https://github.com/pglombardo/PasswordPusher/blob/c2909b2d5f1315f9b66939c9fbc7fd47b0cfeb03/app/controllers/passwords_controller.rb#L120 + https://github.com/adamburley/PassPushPosh/blob/main/Docs/New-Push.md .LINK Get-Push @@ -799,23 +900,35 @@ function Initialize-PassPushPosh { .NOTES Maximum for -ExpireAfterDays and -ExpireAfterViews is based on the default values for Password Pusher and what's used on the public instance - (pwpush.com). If you're using this with a private instance and want to - override that value you'll need to fork this module. + (pwpush.com). #> function New-Push { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', 'Passphrase', Justification = "DE0001: SecureString shouldn't be used")] - [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low', DefaultParameterSetName = 'Anonymous')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low', DefaultParameterSetName = 'Text')] [OutputType([PasswordPush])] param( - [Parameter(Mandatory = $true, ValueFromPipeline, Position = 0)] + [Parameter(ParameterSetName = 'Text', ValueFromPipeline, Position = 0)] [Alias('Password')] [ValidateNotNullOrEmpty()] [string]$Payload, + [Parameter(ParameterSetName = 'QR', Mandatory)] + [string]$QR, + + [Parameter(ParameterSetName = 'URL', Mandatory)] + [ValidatePattern('^https?:\/\/[a-zA-Z0-9-_]+.[a-zA-Z0-9]+')] + [string]$URL, + + [Parameter(ParameterSetName = 'Text')] + [Parameter(ParameterSetName = 'QR')] + [ValidateCount(1, 10)] + [ValidateScript({ $null -ne $Script:PPPHeaders.'X-User-Token' -or $null -ne $Script:PPPHeaders.Authorization }, ErrorMessage = 'Adding files requires authentication.')] + [object[]]$File, + [Parameter()] [string]$Passphrase, - [Parameter(ParameterSetName = 'Authenticated')] + [Parameter()] [ValidateScript({ $null -ne $Script:PPPHeaders.'X-User-Token' -or $null -ne $Script:PPPHeaders.Authorization }, ErrorMessage = 'Adding a note requires authentication.')] [ValidateNotNullOrEmpty()] [string]$Note, @@ -840,60 +953,100 @@ function New-Push { [Parameter()] [ValidateScript({ $null -ne $Script:PPPHeaders.Authorization }, ErrorMessage = 'Adding an account id requires authentication.')] - $AccountId + $AccountId, + + [Parameter(ParameterSetName = 'Text')] + [ValidateSet('Text', 'File', 'QR', 'URL')] + [string]$Kind = 'Text' ) begin { Initialize-PassPushPosh -Verbose:$VerbosePreference -Debug:$DebugPreference } process { - $body = @{ - 'password' = @{ - 'payload' = $Payload + $_Kind = switch ($PSCmdlet.ParameterSetName) { + 'QR' { 'qr' } + 'URL' { 'url' } + default { + $File ? 'file' : $Kind.ToLower() } } - $shouldString = 'Submit {0} push with Payload of length {1}' -f $PSCmdlet.ParameterSetName, $Payload.Length + Write-Debug "Parameter Set: $($PSCmdlet.ParameterSetName)" + Write-Debug "Kind: $_Kind" + + $passVals = @{ 'kind' = $_Kind } + $shouldString = "Submit $_Kind push" + + if ($_Payload = $Payload ? $Payload : $QR ? $QR : $URL ? $URL : $Null) { + $shouldString += ", with payload of length $($_Payload.Length)" + $passVals.payload = $_Payload + } + elseif ($_Kind -ine 'File') { + Write-Error "A payload is required for all Push types except File." -ErrorAction Stop + } if ($Passphrase) { - $body.password.passphrase = $Passphrase + $passVals.passphrase = $Passphrase $shouldString += ", with passphrase of length $($Passphrase.Length)" } if ($Note) { - $body.password.note = $note + $passVals.note = $note $shouldString += ", with note $note" } if ($ExpireAfterDays) { - $body.password.expire_after_days = $ExpireAfterDays - $shouldString += ', expire after {0} days' -f $ExpireAfterDays + $passVals.expire_after_days = $ExpireAfterDays + $shouldString += ", expire after $ExpireAfterDays days" } if ($ExpireAfterViews) { - $body.password.expire_after_views = $ExpireAfterViews - $shouldString += ', expire after {0} views' -f $ExpireAfterViews + $passVals.expire_after_views = $ExpireAfterViews + $shouldString += ", expire after $ExpireAfterViews views" } - if ($AccountId) { - $body.account_id = $AccountId - $shouldString += ', with account ID {0}' -f $AccountId + if ($PSBoundParameters.ContainsKey('DeletableByViewer')) { + $passVals.deletable_by_viewer = [bool]$DeletableByViewer + $shouldString += $DeletableByViewer ? ', deletable by viewer' : ', not deletable by viewer' } - $body.password.deletable_by_viewer = if ($DeletableByViewer) { - $shouldString += ', deletable by viewer' - $true - } else { - $shouldString += ', NOT deletable by viewer' - $false + if ($PSBoundParameters.ContainsKey('RetrievalStep')) { + $passVals.retrieval_step = [bool]$RetrievalStep + $shouldString += $RetrievalStep ? ', with a 1-click retrieval step' : ', without a retrieval step' } - $body.password.retrieval_step = if ($RetrievalStep) { - $shouldString += ', with a 1-click retrieval step' - $true + + if ($File) { + $_Files = Get-ChildItem -Path $File + Write-Debug "Attaching $($_Files.Name -join '; ')" + if ($_Files.Count -gt 10) { + Write-Error "The total number of files is greater than allowed. Only 10 files may be attached to each Push." -ErrorAction Stop + } + else { + $shouldString += ", attaching $($_Files.count) files" + } + $Form = @{ } + $passVals.GetEnumerator() | ForEach-Object { $Form.Add("password[$($_.Name)]", $_.Value) } + $Form.'password[files][]' = $_Files + if ($AccountId) { + $Form.account_id = $AccountId + $shouldString += ', with account ID {0}' -f $AccountId + } + Write-Debug "Form looks like $($Form | Out-String)" + $invokeSplat = @{ + Form = $Form + } } else { - $shouldString += ', with a direct link' - $false + $Body = @{ 'password' = $passVals } + if ($AccountId) { + $Body.account_id = $AccountId + $shouldString += ', with account ID {0}' -f $AccountId + } + Write-Debug "Body looks like $($Body | ConvertTo-Json -Depth 5)" + $invokeSplat = @{ + Body = $Body + } } - if ($PSCmdlet.ShouldProcess($shouldString, $iwrSplat.Uri, 'Submit new Push')) { - $response = Invoke-PasswordPusherAPI -Endpoint 'p.json' -Method Post -Body $body + if ($PSCmdlet.ShouldProcess($shouldString, $Script:PPPBaseUrl, 'Submit new Push')) { + $response = Invoke-PasswordPusherAPI -Endpoint 'p.json' -Method Post @invokeSplat $response | ConvertTo-PasswordPush } } } -#EndRegion '.\Public\New-Push.ps1' 173 +#EndRegion '.\Public\New-Push.ps1' 268 #Region '.\Public\Remove-Push.ps1' -1 <# diff --git a/Tools/Update-LicenseSKUFiles.ps1 b/Tools/Update-LicenseSKUFiles.ps1 index 5d8e49a766d9..e3f41a4df698 100644 --- a/Tools/Update-LicenseSKUFiles.ps1 +++ b/Tools/Update-LicenseSKUFiles.ps1 @@ -27,14 +27,16 @@ $licenseCsvURL = 'https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-49 $TempLicenseDataFile = "$ENV:TEMP\LicenseSKUs.csv" Invoke-WebRequest -Uri $licenseCsvURL -OutFile $TempLicenseDataFile $LicenseDataFile = Get-Item -Path $TempLicenseDataFile -$LicenseData = Import-Csv -Path $LicenseDataFile.FullName -Encoding utf8BOM +$LicenseData = Import-Csv -Path $LicenseDataFile.FullName -Encoding utf8BOM -Delimiter ',' # Update ConversionTable.csv with the latest license SKU data Set-Location $PSScriptRoot Set-Location .. $ConversionTableFiles = Get-ChildItem -Path *ConversionTable.csv -Recurse -File +Write-Host "Updating $($ConversionTableFiles.Count) ConversionTable.csv files with the latest license SKU data..." -ForegroundColor Yellow foreach ($File in $ConversionTableFiles) { - $LicenseData | Export-Csv -Path $File.FullName -NoTypeInformation -Force -Encoding utf8 -UseQuotes Never + $LicenseData | Export-Csv -Path $File.FullName -NoTypeInformation -Force -Encoding utf8 -UseQuotes AsNeeded + Write-Host "Updated $($File.FullName) with new license SKU data." -ForegroundColor Green } @@ -45,8 +47,11 @@ Set-Location .. Set-Location CIPP\src\data $LicenseJSONFiles = Get-ChildItem -Path *M365Licenses.json -File +Write-Host "Updating $($LicenseJSONFiles.Count) M365 license JSON files with the latest license SKU data..." -ForegroundColor Yellow + foreach ($File in $LicenseJSONFiles) { ConvertTo-Json -InputObject $LicenseData -Depth 100 | Set-Content -Path $File.FullName -Encoding utf8 + Write-Host "Updated $($File.FullName) with new license SKU data." -ForegroundColor Green } # Clean up the temporary license SKU CSV file diff --git a/Tools/Update-StandardsComments.ps1 b/Tools/Update-StandardsComments.ps1 index c3d7c9cc30f1..e804aefe0998 100644 --- a/Tools/Update-StandardsComments.ps1 +++ b/Tools/Update-StandardsComments.ps1 @@ -1,152 +1,152 @@ -<# -.SYNOPSIS - This script updates the comment block in the CIPP standard files. - -.DESCRIPTION - The script reads the standards.json file and updates the comment block in the corresponding CIPP standard files. - It adds or modifies the comment block based on the properties defined in the standards.json file. - This is made to be able to generate the help documentation for the CIPP standards automatically. - -.INPUTS - None. You cannot pipe objects to this script. - -.OUTPUTS - None. The script modifies the CIPP standard files directly. - -.NOTES - .FUNCTIONALITY Internal needs to be present in the comment block for the script, otherwise it will not be updated. - This is done as a safety measure to avoid updating the wrong files. - -.EXAMPLE - Update-StandardsComments.ps1 - - This example runs the script to update the comment block in the CIPP standard files. - -#> -param ( - [switch]$WhatIf -) - - -function EscapeMarkdown([object]$InputObject) { - # https://github.com/microsoft/FormatPowerShellToMarkdownTable/blob/master/src/FormatMarkdownTable/FormatMarkdownTable.psm1 - $Temp = '' - - if ($null -eq $InputObject) { - return '' - } elseif ($InputObject.GetType().BaseType -eq [System.Array]) { - $Temp = '{' + [System.String]::Join(', ', $InputObject) + '}' - } elseif ($InputObject.GetType() -eq [System.Collections.ArrayList] -or $InputObject.GetType().ToString().StartsWith('System.Collections.Generic.List')) { - $Temp = '{' + [System.String]::Join(', ', $InputObject.ToArray()) + '}' - } elseif (Get-Member -InputObject $InputObject -Name ToString -MemberType Method) { - $Temp = $InputObject.ToString() - } else { - $Temp = '' - } - - return $Temp.Replace('\', '\\').Replace('*', '\*').Replace('_', '\_').Replace("``", "\``").Replace('$', '\$').Replace('|', '\|').Replace('<', '\<').Replace('>', '\>').Replace([System.Environment]::NewLine, '
    ') -} - - -# Find the paths to the standards.json file based on the current script path -$StandardsJSONPath = Split-Path (Split-Path $PSScriptRoot) -$StandardsJSONPath = Resolve-Path "$StandardsJSONPath\*\src\data\standards.json" -$StandardsInfo = Get-Content -Path $StandardsJSONPath | ConvertFrom-Json -Depth 10 - -foreach ($Standard in $StandardsInfo) { - - # Calculate the standards file name and path - $StandardFileName = $Standard.name -replace 'standards.', 'Invoke-CIPPStandard' - $StandardsFilePath = Resolve-Path "$(Split-Path $PSScriptRoot)\Modules\CIPPCore\Public\Standards\$StandardFileName.ps1" - if (-not (Test-Path $StandardsFilePath)) { - Write-Host "No file found for standard $($Standard.name)" -ForegroundColor Yellow - continue - } - $Content = (Get-Content -Path $StandardsFilePath -Raw).TrimEnd() + "`r`n" - - # Remove random newlines before the param block - $regexPattern = '#>\s*\r?\n\s*\r?\n\s*param' - $Content = $Content -replace $regexPattern, "#>`r`n`r`n param" - - # Regex to match the existing comment block - $Regex = '<#(.|\n)*?\.FUNCTIONALITY\s*Internal(.|\n)*?#>' - - if ($Content -match $Regex) { - $NewComment = [System.Collections.Generic.List[string]]::new() - # Add the initial scatic comments - $NewComment.Add("<#`r`n") - $NewComment.Add(" .FUNCTIONALITY`r`n") - $NewComment.Add(" Internal`r`n") - $NewComment.Add(" .COMPONENT`r`n") - $NewComment.Add(" (APIName) $($Standard.name -replace 'standards.', '')`r`n") - $NewComment.Add(" .SYNOPSIS`r`n") - $NewComment.Add(" (Label) $($Standard.label.ToString())`r`n") - $NewComment.Add(" .DESCRIPTION`r`n") - if ([string]::IsNullOrWhiteSpace($Standard.docsDescription)) { - $NewComment.Add(" (Helptext) $($Standard.helpText.ToString())`r`n") - $NewComment.Add(" (DocsDescription) $(EscapeMarkdown($Standard.helpText.ToString()))`r`n") - } else { - $NewComment.Add(" (Helptext) $($Standard.helpText.ToString())`r`n") - $NewComment.Add(" (DocsDescription) $(EscapeMarkdown($Standard.docsDescription.ToString()))`r`n") - } - $NewComment.Add(" .NOTES`r`n") - - # Loop through the rest of the properties of the standard and add them to the NOTES field - foreach ($Property in $Standard.PSObject.Properties) { - switch ($Property.Name) { - 'name' { continue } - 'impactColour' { continue } - 'docsDescription' { continue } - 'helpText' { continue } - 'label' { continue } - Default { - $NewComment.Add(" $($Property.Name.ToUpper())`r`n") - if ($Property.Value -is [System.Object[]]) { - foreach ($Value in $Property.Value) { - $NewComment.Add(" $(ConvertTo-Json -InputObject $Value -Depth 5 -Compress)`r`n") - } - continue - } - $NewComment.Add(" $(EscapeMarkdown($Property.Value.ToString()))`r`n") - } - } - - } - - # Add header about how to update the comment block with this script - $NewComment.Add(" UPDATECOMMENTBLOCK`r`n") - $NewComment.Add(" Run the Tools\Update-StandardsComments.ps1 script to update this comment block`r`n") - # -Online help link - $NewComment.Add(" .LINK`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 - if ($WhatIf.IsPresent) { - Write-Host "Would update $StandardsFilePath with the following comment block:" - $NewComment - } else { - $Content -replace $Regex, $NewComment | Set-Content -Path $StandardsFilePath -Encoding utf8 -NoNewline - } - } else { - Write-Host "No comment block found in $StandardsFilePath" -ForegroundColor Yellow - } -} +<# +.SYNOPSIS + This script updates the comment block in the CIPP standard files. + +.DESCRIPTION + The script reads the standards.json file and updates the comment block in the corresponding CIPP standard files. + It adds or modifies the comment block based on the properties defined in the standards.json file. + This is made to be able to generate the help documentation for the CIPP standards automatically. + +.INPUTS + None. You cannot pipe objects to this script. + +.OUTPUTS + None. The script modifies the CIPP standard files directly. + +.NOTES + .FUNCTIONALITY Internal needs to be present in the comment block for the script, otherwise it will not be updated. + This is done as a safety measure to avoid updating the wrong files. + +.EXAMPLE + Update-StandardsComments.ps1 + + This example runs the script to update the comment block in the CIPP standard files. + +#> +param ( + [switch]$WhatIf +) + + +function EscapeMarkdown([object]$InputObject) { + # https://github.com/microsoft/FormatPowerShellToMarkdownTable/blob/master/src/FormatMarkdownTable/FormatMarkdownTable.psm1 + $Temp = '' + + if ($null -eq $InputObject) { + return '' + } elseif ($InputObject.GetType().BaseType -eq [System.Array]) { + $Temp = '{' + [System.String]::Join(', ', $InputObject) + '}' + } elseif ($InputObject.GetType() -eq [System.Collections.ArrayList] -or $InputObject.GetType().ToString().StartsWith('System.Collections.Generic.List')) { + $Temp = '{' + [System.String]::Join(', ', $InputObject.ToArray()) + '}' + } elseif (Get-Member -InputObject $InputObject -Name ToString -MemberType Method) { + $Temp = $InputObject.ToString() + } else { + $Temp = '' + } + + return $Temp.Replace('\', '\\').Replace('*', '\*').Replace('_', '\_').Replace("``", "\``").Replace('$', '\$').Replace('|', '\|').Replace('<', '\<').Replace('>', '\>').Replace([System.Environment]::NewLine, '
    ') +} + + +# Find the paths to the standards.json file based on the current script path +$StandardsJSONPath = Split-Path (Split-Path $PSScriptRoot) +$StandardsJSONPath = Resolve-Path "$StandardsJSONPath\*\src\data\standards.json" +$StandardsInfo = Get-Content -Path $StandardsJSONPath | ConvertFrom-Json -Depth 10 + +foreach ($Standard in $StandardsInfo) { + + # Calculate the standards file name and path + $StandardFileName = $Standard.name -replace 'standards.', 'Invoke-CIPPStandard' + $StandardsFilePath = Resolve-Path "$(Split-Path $PSScriptRoot)\Modules\CIPPCore\Public\Standards\$StandardFileName.ps1" + if (-not (Test-Path $StandardsFilePath)) { + Write-Host "No file found for standard $($Standard.name)" -ForegroundColor Yellow + continue + } + $Content = (Get-Content -Path $StandardsFilePath -Raw).TrimEnd() + "`n" + + # Remove random newlines before the param block + $regexPattern = '#>\s*\r?\n\s*\r?\n\s*param' + $Content = $Content -replace $regexPattern, "#>`n`n param" + + # Regex to match the existing comment block + $Regex = '<#(.|\n)*?\.FUNCTIONALITY\s*Internal(.|\n)*?#>' + + if ($Content -match $Regex) { + $NewComment = [System.Collections.Generic.List[string]]::new() + # Add the initial static comments + $NewComment.Add("<#`n") + $NewComment.Add(" .FUNCTIONALITY`n") + $NewComment.Add(" Internal`n") + $NewComment.Add(" .COMPONENT`n") + $NewComment.Add(" (APIName) $($Standard.name -replace 'standards.', '')`n") + $NewComment.Add(" .SYNOPSIS`n") + $NewComment.Add(" (Label) $($Standard.label.ToString())`n") + $NewComment.Add(" .DESCRIPTION`n") + if ([string]::IsNullOrWhiteSpace($Standard.docsDescription)) { + $NewComment.Add(" (Helptext) $($Standard.helpText.ToString())`n") + $NewComment.Add(" (DocsDescription) $(EscapeMarkdown($Standard.helpText.ToString()))`n") + } else { + $NewComment.Add(" (Helptext) $($Standard.helpText.ToString())`n") + $NewComment.Add(" (DocsDescription) $(EscapeMarkdown($Standard.docsDescription.ToString()))`n") + } + $NewComment.Add(" .NOTES`n") + + # Loop through the rest of the properties of the standard and add them to the NOTES field + foreach ($Property in $Standard.PSObject.Properties) { + switch ($Property.Name) { + 'name' { continue } + 'impactColour' { continue } + 'docsDescription' { continue } + 'helpText' { continue } + 'label' { continue } + Default { + $NewComment.Add(" $($Property.Name.ToUpper())`n") + if ($Property.Value -is [System.Object[]]) { + foreach ($Value in $Property.Value) { + $NewComment.Add(" $(ConvertTo-Json -InputObject $Value -Depth 5 -Compress)`n") + } + continue + } + $NewComment.Add(" $(EscapeMarkdown($Property.Value.ToString()))`n") + } + } + + } + + # Add header about how to update the comment block with this script + $NewComment.Add(" UPDATECOMMENTBLOCK`n") + $NewComment.Add(" Run the Tools\Update-StandardsComments.ps1 script to update this comment block`n") + # -Online help link + $NewComment.Add(" .LINK`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`n") + $NewComment.Add(' #>') + + # Write the new comment block to the file + if ($WhatIf.IsPresent) { + Write-Host "Would update $StandardsFilePath with the following comment block:" + $NewComment + } else { + $Content -replace $Regex, $NewComment | Set-Content -Path $StandardsFilePath -Encoding utf8 -NoNewline + } + } else { + Write-Host "No comment block found in $StandardsFilePath" -ForegroundColor Yellow + } +} diff --git a/version_latest.txt b/version_latest.txt index 429dc57af3a3..1502020768a7 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -7.2.3 +7.3.0