From b40e4fe163f310c0d24b1f5306cec44fb8241a31 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Wed, 20 Mar 2024 11:52:09 +0000 Subject: [PATCH 01/56] Use Update-DeviceConfigurationPolicyAssignment instead --- ...IntuneDeviceCompliancePolicyWindows10.psm1 | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 index ca8a3c3d06..fce2d3177b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 @@ -506,16 +506,10 @@ function Set-TargetResource -AdditionalProperties $AdditionalProperties ` -ScheduledActionsForRule $scheduledActionsForRule - $assignmentsHash = @() - foreach ($assignment in $Assignments) - { - $assignmentsHash += Get-M365DSCAssignmentsAsHashtable -CIMAssignment $Assignment - - } - Update-M365DSCDeviceManagementPolicyAssignments -DeviceManagementPolicyId $policy.id ` + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $policy.id ` -Targets $assignmentsHash ` - -Repository deviceCompliancePolicies - + -Repository 'deviceManagement/deviceCompliancePolicies' } elseif ($Ensure -eq 'Present' -and $currentDeviceWindows10Policy.Ensure -eq 'Present') { @@ -534,15 +528,10 @@ function Set-TargetResource -Description $Description ` -DeviceCompliancePolicyId $configDevicePolicy.Id - $assignmentsHash = @() - foreach ($assignment in $Assignments) - { - $assignmentsHash += Get-M365DSCAssignmentsAsHashtable -CIMAssignment $Assignment - - } - Update-M365DSCDeviceManagementPolicyAssignments -DeviceManagementPolicyId $configDevicePolicy.id ` + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $configDevicePolicy.id ` -Targets $assignmentsHash ` - -Repository deviceCompliancePolicies + -Repository 'deviceManagement/deviceCompliancePolicies' } elseif ($Ensure -eq 'Absent' -and $currentDeviceWindows10Policy.Ensure -eq 'Present') { From f82912e447b0ad90aaea1246c27eb0cb4d0dfbfa Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Wed, 20 Mar 2024 11:52:56 +0000 Subject: [PATCH 02/56] These functions are not required anymore --- ...IntuneDeviceCompliancePolicyWindows10.psm1 | 124 ------------------ 1 file changed, 124 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 index fce2d3177b..c9808a27ec 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 @@ -1028,127 +1028,3 @@ function Get-M365DSCAssignmentsAsHashtable } return $CIMAssignmentAsHash } -function Get-M365DSCDeviceManagementPolicyAssignments -{ - [CmdletBinding()] - param ( - [Parameter(Mandatory = 'true')] - [System.String] - $DeviceManagementPolicyId, - - [Parameter()] - [ValidateSet('deviceCompliancePolicies', 'intents', 'configurationPolicies')] - [System.String] - $Repository = 'configurationPolicies' - ) - try - { - $deviceManagementPolicyAssignments = @() - - $Uri = "https://graph.microsoft.com/beta/deviceManagement/$Repository/$DeviceManagementPolicyId/assignments" - $results = Invoke-MgGraphRequest -Method GET -Uri $Uri -ErrorAction Stop - foreach ($result in $results.value.target) - { - $deviceManagementPolicyAssignments += @{ - dataType = $result.'@odata.type' - groupId = $result.groupId - collectionId = $result.collectionId - deviceAndAppManagementAssignmentFilterType = $result.deviceAndAppManagementAssignmentFilterType - deviceAndAppManagementAssignmentFilterId = $result.deviceAndAppManagementAssignmentFilterId - } - } - - while ($results.'@odata.nextLink') - { - $Uri = $results.'@odata.nextLink' - $results = Invoke-MgGraphRequest -Method GET -Uri $Uri -ErrorAction Stop - foreach ($result in $results.value.target) - { - $deviceManagementPolicyAssignments += @{ - dataType = $result.'@odata.type' - groupId = $result.groupId - collectionId = $result.collectionId - deviceAndAppManagementAssignmentFilterType = $result.deviceAndAppManagementAssignmentFilterType - deviceAndAppManagementAssignmentFilterId = $result.deviceAndAppManagementAssignmentFilterId - } - } - } - return $deviceManagementPolicyAssignments - } - catch - { - New-M365DSCLogEntry -Message 'Error retrieving data:' ` - -Exception $_ ` - -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $TenantId ` - -Credential $Credential - - return $null - } -} - -function Update-M365DSCDeviceManagementPolicyAssignments -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [Parameter(Mandatory = 'true')] - [System.String] - $DeviceManagementPolicyId, - - [Parameter()] - [Array] - $Targets, - - [Parameter()] - [ValidateSet('deviceCompliancePolicies', 'intents', 'configurationPolicies')] - [System.String] - $Repository = 'configurationPolicies' - ) - - try - { - $deviceManagementPolicyAssignments = @() - - $Uri = "https://graph.microsoft.com/beta/deviceManagement/$Repository/$DeviceManagementPolicyId/assign" - - foreach ($target in $targets) - { - $formattedTarget = @{'@odata.type' = $target.dataType } - if ($target.groupId) - { - $formattedTarget.Add('groupId', $target.groupId) - } - if ($target.collectionId) - { - $formattedTarget.Add('collectionId', $target.collectionId) - } - if ($target.deviceAndAppManagementAssignmentFilterType) - { - $formattedTarget.Add('deviceAndAppManagementAssignmentFilterType', $target.deviceAndAppManagementAssignmentFilterType) - } - if ($target.deviceAndAppManagementAssignmentFilterId) - { - $formattedTarget.Add('deviceAndAppManagementAssignmentFilterId', $target.deviceAndAppManagementAssignmentFilterId) - } - $deviceManagementPolicyAssignments += @{'target' = $formattedTarget } - } - $body = @{'assignments' = $deviceManagementPolicyAssignments } | ConvertTo-Json -Depth 20 - #write-verbose -Message $body - Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $body -ErrorAction Stop - - } - catch - { - New-M365DSCLogEntry -Message 'Error updating data:' ` - -Exception $_ ` - -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $TenantId ` - -Credential $Credential - - return $null - } -} - -Export-ModuleMember -Function *-TargetResource, * From 2c0facc311a1c740704c34d57f0c58d51d2d8105 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Fri, 10 May 2024 09:59:16 +0100 Subject: [PATCH 03/56] Change permission to cope with getOmaSettingPlainTextValue --- .../settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationCustomPolicyWindows10/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationCustomPolicyWindows10/settings.json index 4f57251847..59369d197b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationCustomPolicyWindows10/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceConfigurationCustomPolicyWindows10/settings.json @@ -9,7 +9,7 @@ "name": "Group.Read.All" }, { - "name": "DeviceManagementConfiguration.Read.All" + "name": "DeviceManagementConfiguration.ReadWrite.All" } ], "update": [ @@ -24,7 +24,7 @@ "name": "Group.Read.All" }, { - "name": "DeviceManagementConfiguration.Read.All" + "name": "DeviceManagementConfiguration.ReadWrite.All" } ], "update": [ From ddf5d53590108e2fdcae8ce3820e5d92ce66e3e9 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Fri, 10 May 2024 10:37:49 +0100 Subject: [PATCH 04/56] Update CHANGELOG.md --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9088b8b25e..184e94586f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,15 @@ FIXES [#4283](https://github.com/microsoft/Microsoft365DSC/issues/4283) * IntuneDeviceConfigurationCustomPolicyWindows10 * Fixed an issue where the payload of xml files was not encoded as base64. + * Change app and delegated permissions for reading to + DeviceManagementConfiguration.ReadWrite.All to cope with + getOmaSettingPlainTextValue which is only working if RW is granted + FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) * IntuneDeviceConfigurationDefenderForEndpointOnboardingPolicyWindows10 - * Fixed a creation and update issue when the exported policy contains a + * Fixed a creation and update issue when the exported policy contains a onboarding blob and the tenant is connected to Defender for Endpoint Service. * M365DSCUtil - * Fixed an issue where one could not pass empty arrays to the + * Fixed an issue where one could not pass empty arrays to the `Compare-PSCustomObjectArrays` function. * DEPENDENCIES * Updated Microsoft.Graph to version 2.18.0. @@ -36,7 +40,7 @@ * Fixed an issue where the update policy setting was not handled properly. * IntuneDeviceConfigurationWiredNetworkPolicyWindows10 * Added functionality for specifying the certificates with a display name since their - ids in the blueprint might be from a different source tenant. + ids in the blueprint might be from a different source tenant. FIXES [#4582](https://github.com/microsoft/Microsoft365DSC/issues/4582) * MISC * Added support for AccessTokens in EXO resources. From 56638473e80e70ab6641becceba23ccf39b3fc69 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Fri, 10 May 2024 12:57:56 +0100 Subject: [PATCH 05/56] Fix QA tests --- Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 b/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 index 7a21fd4b45..0dcca6a880 100644 --- a/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 +++ b/Tests/QA/Microsoft365DSC.SettingsJson.Tests.ps1 @@ -84,6 +84,13 @@ Describe -Name 'Successfully validate all used permissions in Settings.json file ) } + if ($settings.ResourceName -eq 'IntuneDeviceConfigurationCustomPolicyWindows10') + { + $allowedPermissions = @( + 'DeviceManagementConfiguration.ReadWrite.All' + ) + } + foreach ($permission in $settings.permissions.graph.application.read) { $ObjectGuid = [System.Guid]::empty From 4e3428a3fad89962ff8dfd136e0f21556a4b193b Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Fri, 10 May 2024 13:11:51 +0100 Subject: [PATCH 06/56] Fix --- ...IntuneDeviceCompliancePolicyWindows10.psm1 | 136 +----------------- 1 file changed, 6 insertions(+), 130 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 index 8fc780fe8b..5add8ab630 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 @@ -540,15 +540,13 @@ function Set-TargetResource -Description $Description ` -DeviceCompliancePolicyId $configDevicePolicy.Id - $assignmentsHash = @() - foreach ($assignment in $Assignments) + if ($Assignments.Count -gt 0) { - $assignmentsHash += Get-M365DSCAssignmentsAsHashtable -CIMAssignment $Assignment - + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $configDevicePolicy.id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/deviceCompliancePolicies' } - Update-M365DSCDeviceManagementPolicyAssignments -DeviceManagementPolicyId $configDevicePolicy.id ` - -Targets $assignmentsHash ` - -Repository deviceCompliancePolicies } elseif ($Ensure -eq 'Absent' -and $currentDeviceWindows10Policy.Ensure -eq 'Present') { @@ -1048,127 +1046,5 @@ function Get-M365DSCAssignmentsAsHashtable } return $CIMAssignmentAsHash } -function Get-M365DSCDeviceManagementPolicyAssignments -{ - [CmdletBinding()] - param ( - [Parameter(Mandatory = 'true')] - [System.String] - $DeviceManagementPolicyId, - - [Parameter()] - [ValidateSet('deviceCompliancePolicies', 'intents', 'configurationPolicies')] - [System.String] - $Repository = 'configurationPolicies' - ) - try - { - $deviceManagementPolicyAssignments = @() - - $Uri = "https://graph.microsoft.com/beta/deviceManagement/$Repository/$DeviceManagementPolicyId/assignments" - $results = Invoke-MgGraphRequest -Method GET -Uri $Uri -ErrorAction Stop - foreach ($result in $results.value.target) - { - $deviceManagementPolicyAssignments += @{ - dataType = $result.'@odata.type' - groupId = $result.groupId - collectionId = $result.collectionId - deviceAndAppManagementAssignmentFilterType = $result.deviceAndAppManagementAssignmentFilterType - deviceAndAppManagementAssignmentFilterId = $result.deviceAndAppManagementAssignmentFilterId - } - } - - while ($results.'@odata.nextLink') - { - $Uri = $results.'@odata.nextLink' - $results = Invoke-MgGraphRequest -Method GET -Uri $Uri -ErrorAction Stop - foreach ($result in $results.value.target) - { - $deviceManagementPolicyAssignments += @{ - dataType = $result.'@odata.type' - groupId = $result.groupId - collectionId = $result.collectionId - deviceAndAppManagementAssignmentFilterType = $result.deviceAndAppManagementAssignmentFilterType - deviceAndAppManagementAssignmentFilterId = $result.deviceAndAppManagementAssignmentFilterId - } - } - } - return $deviceManagementPolicyAssignments - } - catch - { - New-M365DSCLogEntry -Message 'Error retrieving data:' ` - -Exception $_ ` - -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $TenantId ` - -Credential $Credential - - return $null - } -} - -function Update-M365DSCDeviceManagementPolicyAssignments -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [Parameter(Mandatory = 'true')] - [System.String] - $DeviceManagementPolicyId, - - [Parameter()] - [Array] - $Targets, - - [Parameter()] - [ValidateSet('deviceCompliancePolicies', 'intents', 'configurationPolicies')] - [System.String] - $Repository = 'configurationPolicies' - ) - - try - { - $deviceManagementPolicyAssignments = @() - - $Uri = "https://graph.microsoft.com/beta/deviceManagement/$Repository/$DeviceManagementPolicyId/assign" - - foreach ($target in $targets) - { - $formattedTarget = @{'@odata.type' = $target.dataType } - if ($target.groupId) - { - $formattedTarget.Add('groupId', $target.groupId) - } - if ($target.collectionId) - { - $formattedTarget.Add('collectionId', $target.collectionId) - } - if ($target.deviceAndAppManagementAssignmentFilterType) - { - $formattedTarget.Add('deviceAndAppManagementAssignmentFilterType', $target.deviceAndAppManagementAssignmentFilterType) - } - if ($target.deviceAndAppManagementAssignmentFilterId) - { - $formattedTarget.Add('deviceAndAppManagementAssignmentFilterId', $target.deviceAndAppManagementAssignmentFilterId) - } - $deviceManagementPolicyAssignments += @{'target' = $formattedTarget } - } - $body = @{'assignments' = $deviceManagementPolicyAssignments } | ConvertTo-Json -Depth 20 - #write-verbose -Message $body - Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $body -ErrorAction Stop - - } - catch - { - New-M365DSCLogEntry -Message 'Error updating data:' ` - -Exception $_ ` - -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $TenantId ` - -Credential $Credential - - return $null - } -} -Export-ModuleMember -Function *-TargetResource, * +Export-ModuleMember -Function *-TargetResource From a72d054befd49c52cd04aecf2dac53bf79ed7445 Mon Sep 17 00:00:00 2001 From: Bart Vermeersch Date: Wed, 15 May 2024 16:25:34 +0200 Subject: [PATCH 07/56] Some Administrative Unit properties have moved out of AdditionalProperties --- .../MSFT_AADAdministrativeUnit.psm1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdministrativeUnit/MSFT_AADAdministrativeUnit.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdministrativeUnit/MSFT_AADAdministrativeUnit.psm1 index 8632ff07c0..bdd072fed5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdministrativeUnit/MSFT_AADAdministrativeUnit.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAdministrativeUnit/MSFT_AADAdministrativeUnit.psm1 @@ -159,17 +159,17 @@ function Get-TargetResource #endregion } - if (-not [string]::IsNullOrEmpty($getValue.AdditionalProperties.membershipType)) + if (-not [string]::IsNullOrEmpty($getValue.membershipType)) { - $results.Add('MembershipType', $getValue.AdditionalProperties.membershipType) + $results.Add('MembershipType', $getValue.membershipType) } - if (-not [string]::IsNullOrEmpty($getValue.AdditionalProperties.membershipRule)) + if (-not [string]::IsNullOrEmpty($getValue.membershipRule)) { - $results.Add('MembershipRule', $getValue.AdditionalProperties.membershipRule) + $results.Add('MembershipRule', $getValue.membershipRule) } - if (-not [string]::IsNullOrEmpty($getValue.AdditionalProperties.membershipRuleProcessingState)) + if (-not [string]::IsNullOrEmpty($getValue.membershipRuleProcessingState)) { - $results.Add('MembershipRuleProcessingState', $getValue.AdditionalProperties.membershipRuleProcessingState) + $results.Add('MembershipRuleProcessingState', $getValue.membershipRuleProcessingState) } Write-Verbose -Message "AU {$DisplayName} MembershipType {$($results.MembershipType)}" From 360f2021b4b4fece9e0a70a6a7fdedbc7ef6c285 Mon Sep 17 00:00:00 2001 From: Bart Vermeersch Date: Wed, 15 May 2024 16:29:52 +0200 Subject: [PATCH 08/56] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 537c3a5134..142980f1b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change log for Microsoft365DSC +# UNRELEASED +* AADAdministrativeUnit + * Fix Properties for Dynamic Administrative Units in Graph have moved + # 1.24.515.2 * EXOManagementRoleEntry From bf515b6b9ccc24dac71aee90d7d65b886169032d Mon Sep 17 00:00:00 2001 From: Alex Floca Date: Fri, 7 Jun 2024 09:27:36 +0200 Subject: [PATCH 09/56] fix #4741 --- .../MSFT_O365OrgSettings.psm1 | 71 ++++++++++++------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_O365OrgSettings/MSFT_O365OrgSettings.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_O365OrgSettings/MSFT_O365OrgSettings.psm1 index 0cee92ef1d..74a75e4c15 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_O365OrgSettings/MSFT_O365OrgSettings.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_O365OrgSettings/MSFT_O365OrgSettings.psm1 @@ -591,7 +591,8 @@ function Set-TargetResource -InboundParameters $PSBoundParameters $currentValues = Get-TargetResource @PSBoundParameters - if ($M365WebEnableUsersToOpenFilesFrom3PStorage -ne $currentValues.M365WebEnableUsersToOpenFilesFrom3PStorage) + if ($PSBoundParameters.ContainsKey('M365WebEnableUsersToOpenFilesFrom3PStorage') -and ` + ($M365WebEnableUsersToOpenFilesFrom3PStorage -ne $currentValues.M365WebEnableUsersToOpenFilesFrom3PStorage)) { Write-Verbose -Message "Updating the Microsoft 365 On the Web setting to {$M365WebEnableUsersToOpenFilesFrom3PStorage}" $OfficeOnlineId = 'c1f33bc0-bdb4-4248-ba9b-096807ddb43e' @@ -599,18 +600,20 @@ function Set-TargetResource Update-MgservicePrincipal -ServicePrincipalId $($M365WebEnableUsersToOpenFilesFrom3PStorageValue.Id) ` -AccountEnabled:$M365WebEnableUsersToOpenFilesFrom3PStorage } - if ($PlannerAllowCalendarSharing -ne $currentValues.PlannerAllowCalendarSharing) + if ($PSBoundParameters.ContainsKey('PlannerAllowCalendarSharing') -and ` + ($PlannerAllowCalendarSharing -ne $currentValues.PlannerAllowCalendarSharing)) { Write-Verbose -Message "Updating the Planner Allow Calendar Sharing setting to {$PlannerAllowCalendarSharing}" Set-M365DSCO365OrgSettingsPlannerConfig -AllowCalendarSharing $PlannerAllowCalendarSharing } - if ($currentValues.CortanaEnabled -and $CortanaEnabled -ne $currentValues.CortanaEnabled) + if ($PSBoundParameters.ContainsKey('CortanaEnabled') -and ` + ($CortanaEnabled -ne $currentValues.CortanaEnabled)) { $CortanaId = '0a0a29f9-0a25-49c7-94bf-c53c3f8fa69d' $CortanaEnabledValue = Get-MgServicePrincipal -Filter "appId eq '$CortanaId'" -Property 'AccountEnabled, Id' - if ($null -ne $CortanaEnabledValue.Id -and $CortanaEnabledValue.AccountEnabled) + if ($null -ne $CortanaEnabledValue.Id) { Write-Verbose -Message "Updating the Cortana setting to {$CortanaEnabled}" Update-MgServicePrincipal -ServicePrincipalId $($CortanaEnabledValue.Id) ` @@ -633,25 +636,29 @@ function Set-TargetResource }#> # Viva Insights - if ($currentValues.VivaInsightsWebExperience -ne $VivaInsightsWebExperience) + if ($PSBoundParameters.ContainsKey('VivaInsightsWebExperience') -and ` + ($currentValues.VivaInsightsWebExperience -ne $VivaInsightsWebExperience)) { Write-Verbose -Message "Updating Viva Insights settings for Web Experience" Set-DefaultTenantMyAnalyticsFeatureConfig -Feature "Dashboard" -IsEnabled $VivaInsightsWebExperience -Verbose:$false | Out-Null } - if ($currentValues.VivaInsightsDigestEmail -ne $VivaInsightsDigestEmail) + if ($PSBoundParameters.ContainsKey('VivaInsightsDigestEmail') -and ` + ($currentValues.VivaInsightsDigestEmail -ne $VivaInsightsDigestEmail)) { Write-Verbose -Message "Updating Viva Insights settings for Digest Email" Set-DefaultTenantMyAnalyticsFeatureConfig -Feature "Digest-email" -IsEnabled $VivaInsightsDigestEmail -Verbose:$false | Out-Null } - if ($currentValues.VivaInsightsOutlookAddInAndInlineSuggestions -ne $VivaInsightsOutlookAddInAndInlineSuggestions) + if ($PSBoundParameters.ContainsKey('VivaInsightsOutlookAddInAndInlineSuggestions') -and ` + ($currentValues.VivaInsightsOutlookAddInAndInlineSuggestions -ne $VivaInsightsOutlookAddInAndInlineSuggestions)) { Write-Verbose -Message "Updating Viva Insights settings for Addin and Inline Suggestions" Set-DefaultTenantMyAnalyticsFeatureConfig -Feature "Add-In" -IsEnabled $VivaInsightsOutlookAddInAndInlineSuggestions -Verbose:$false | Out-Null } - if ($currentValues.VivaInsightsScheduleSendSuggestions -ne $VivaInsightsScheduleSendSuggestions) + if ($PSBoundParameters.ContainsKey('VivaInsightsScheduleSendSuggestions') -and ` + ($currentValues.VivaInsightsScheduleSendSuggestions -ne $VivaInsightsScheduleSendSuggestions)) { Write-Verbose -Message "Updating Viva Insights settings for ScheduleSendSuggestions" Set-DefaultTenantMyAnalyticsFeatureConfig -Feature "Scheduled-send" -IsEnabled $VivaInsightsScheduleSendSuggestions -Verbose:$false | Out-Null @@ -659,7 +666,8 @@ function Set-TargetResource # Reports Display Names $AdminCenterReportDisplayConcealedNamesEnabled = Get-M365DSCOrgSettingsAdminCenterReport - if ($AdminCenterReportDisplayConcealedNames -ne $AdminCenterReportDisplayConcealedNamesEnabled.displayConcealedNames) + if ($PSBoundParameters.ContainsKey('AdminCenterReportDisplayConcealedNames') -and ` + ($AdminCenterReportDisplayConcealedNames -ne $AdminCenterReportDisplayConcealedNamesEnabled.displayConcealedNames)) { Write-Verbose -Message "Updating the Admin Center Report Display Concealed Names setting to {$AdminCenterReportDisplayConcealedNames}" Update-M365DSCOrgSettingsAdminCenterReport -DisplayConcealedNames $AdminCenterReportDisplayConcealedNames @@ -732,31 +740,38 @@ function Set-TargetResource # Forms $FormsParametersToUpdate = @{} - if ($FormsIsExternalSendFormEnabled -ne $currentValues.FormsIsExternalSendFormEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsExternalSendFormEnabled') -and ` + ($FormsIsExternalSendFormEnabled -ne $currentValues.FormsIsExternalSendFormEnabled)) { $FormsParametersToUpdate.Add('isExternalSendFormEnabled', $FormsIsExternalSendFormEnabled) } - if ($FormsIsExternalShareCollaborationEnabled -ne $currentValues.FormsIsExternalShareCollaborationEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsExternalShareCollaborationEnabled') -and ` + ($FormsIsExternalShareCollaborationEnabled -ne $currentValues.FormsIsExternalShareCollaborationEnabled)) { $FormsParametersToUpdate.Add('isExternalShareCollaborationEnabled', $FormsIsExternalShareCollaborationEnabled) } - if ($FormsIsExternalShareResultEnabled -ne $currentValues.FormsIsExternalShareResultEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsExternalShareResultEnabled') -and ` + ($FormsIsExternalShareResultEnabled -ne $currentValues.FormsIsExternalShareResultEnabled)) { $FormsParametersToUpdate.Add('isExternalShareResultEnabled', $FormsIsExternalShareResultEnabled) } - if ($FormsIsExternalShareTemplateEnabled -ne $currentValues.FormsIsExternalShareTemplateEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsExternalShareTemplateEnabled') -and ` + ($FormsIsExternalShareTemplateEnabled -ne $currentValues.FormsIsExternalShareTemplateEnabled)) { $FormsParametersToUpdate.Add('isExternalShareTemplateEnabled', $FormsIsExternalShareTemplateEnabled) } - if ($FormsIsRecordIdentityByDefaultEnabled -ne $currentValues.FormsIsRecordIdentityByDefaultEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsRecordIdentityByDefaultEnabled') -and ` + ($FormsIsRecordIdentityByDefaultEnabled -ne $currentValues.FormsIsRecordIdentityByDefaultEnabled)) { $FormsParametersToUpdate.Add('isRecordIdentityByDefaultEnabled', $FormsIsRecordIdentityByDefaultEnabled) } - if ($FormsIsBingImageSearchEnabled -ne $currentValues.FormsIsBingImageSearchEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsBingImageSearchEnabled') -and ` + ($FormsIsBingImageSearchEnabled -ne $currentValues.FormsIsBingImageSearchEnabled)) { $FormsParametersToUpdate.Add('isBingImageSearchEnabled', $FormsIsBingImageSearchEnabled) } - if ($FormsIsInOrgFormsPhishingScanEnabled -ne $currentValues.FormsIsInOrgFormsPhishingScanEnabled) + if ($PSBoundParameters.ContainsKey('FormsIsInOrgFormsPhishingScanEnabled') -and ` + ($FormsIsInOrgFormsPhishingScanEnabled -ne $currentValues.FormsIsInOrgFormsPhishingScanEnabled)) { $FormsParametersToUpdate.Add('isInOrgFormsPhishingScanEnabled', $FormsIsInOrgFormsPhishingScanEnabled) } @@ -768,15 +783,18 @@ function Set-TargetResource # Dynamics Customer Voice Settings $DynamicsCustomerVoiceParametersToUpdate = @{} - if ($DynamicsCustomerVoiceIsRestrictedSurveyAccessEnabled -ne $currentValues.DynamicsCustomerVoiceIsRestrictedSurveyAccessEnabled) + if ($PSBoundParameters.ContainsKey('DynamicsCustomerVoiceIsRestrictedSurveyAccessEnabled') -and ` + ($DynamicsCustomerVoiceIsRestrictedSurveyAccessEnabled -ne $currentValues.DynamicsCustomerVoiceIsRestrictedSurveyAccessEnabled)) { $DynamicsCustomerVoiceParametersToUpdate.Add('isRestrictedSurveyAccessEnabled', $DynamicsCustomerVoiceIsRestrictedSurveyAccessEnabled) } - if ($DynamicsCustomerVoiceIsRecordIdentityByDefaultEnabled -ne $currentValues.DynamicsCustomerVoiceIsRecordIdentityByDefaultEnabled) + if ($PSBoundParameters.ContainsKey('DynamicsCustomerVoiceIsRecordIdentityByDefaultEnabled') -and ` + ($DynamicsCustomerVoiceIsRecordIdentityByDefaultEnabled -ne $currentValues.DynamicsCustomerVoiceIsRecordIdentityByDefaultEnabled)) { $DynamicsCustomerVoiceParametersToUpdate.Add('isRecordIdentityByDefaultEnabled', $DynamicsCustomerVoiceIsRecordIdentityByDefaultEnabled) } - if ($DynamicsCustomerVoiceIsInOrgFormsPhishingScanEnabled -ne $currentValues.DynamicsCustomerVoiceIsInOrgFormsPhishingScanEnabled) + if ($PSBoundParameters.ContainsKey('DynamicsCustomerVoiceIsInOrgFormsPhishingScanEnabled') -and ` + ($DynamicsCustomerVoiceIsInOrgFormsPhishingScanEnabled -ne $currentValues.DynamicsCustomerVoiceIsInOrgFormsPhishingScanEnabled)) { $DynamicsCustomerVoiceParametersToUpdate.Add('isInOrgFormsPhishingScanEnabled', $DynamicsCustomerVoiceIsInOrgFormsPhishingScanEnabled) } @@ -788,11 +806,13 @@ function Set-TargetResource # Apps And Services $AppsAndServicesParametersToUpdate = @{} - if ($AppsAndServicesIsOfficeStoreEnabled -ne $currentValues.AppsAndServicesIsOfficeStoreEnabled) + if ($PSBoundParameters.ContainsKey('AppsAndServicesIsOfficeStoreEnabled') -and ` + ($AppsAndServicesIsOfficeStoreEnabled -ne $currentValues.AppsAndServicesIsOfficeStoreEnabled)) { $AppsAndServicesParametersToUpdate.Add('isOfficeStoreEnabled', $AppsAndServicesIsOfficeStoreEnabled) } - if ($AppsAndServicesIsAppAndServicesTrialEnabled -ne $currentValues.AppsAndServicesIsAppAndServicesTrialEnabled) + if ($PSBoundParameters.ContainsKey('AppsAndServicesIsAppAndServicesTrialEnabled') -and ` + ($AppsAndServicesIsAppAndServicesTrialEnabled -ne $currentValues.AppsAndServicesIsAppAndServicesTrialEnabled)) { $AppsAndServicesParametersToUpdate.Add('isAppAndServicesTrialEnabled', $AppsAndServicesIsAppAndServicesTrialEnabled) } @@ -804,15 +824,18 @@ function Set-TargetResource # To Do $ToDoParametersToUpdate = @{} - if ($ToDoIsPushNotificationEnabled -ne $currentValues.ToDoIsPushNotificationEnabled) + if ($PSBoundParameters.ContainsKey('ToDoIsPushNotificationEnabled') -and ` + ($ToDoIsPushNotificationEnabled -ne $currentValues.ToDoIsPushNotificationEnabled)) { $ToDoParametersToUpdate.Add('isPushNotificationEnabled', $ToDoIsPushNotificationEnabled) } - if ($ToDoIsExternalJoinEnabled -ne $currentValues.ToDoIsExternalJoinEnabled) + if ($PSBoundParameters.ContainsKey('ToDoIsExternalJoinEnabled') -and ` + ($ToDoIsExternalJoinEnabled -ne $currentValues.ToDoIsExternalJoinEnabled)) { $ToDoParametersToUpdate.Add('isExternalJoinEnabled', $ToDoIsExternalJoinEnabled) } - if ($ToDoIsExternalShareEnabled -ne $currentValues.ToDoIsExternalShareEnabled) + if ($PSBoundParameters.ContainsKey('ToDoIsExternalShareEnabled') -and ` + ($ToDoIsExternalShareEnabled -ne $currentValues.ToDoIsExternalShareEnabled)) { $ToDoParametersToUpdate.Add('isExternalShareEnabled', $ToDoIsExternalShareEnabled) } From 927f4cf5a908ad015bd84d78a37b4edca8df9c04 Mon Sep 17 00:00:00 2001 From: Alex Floca Date: Fri, 7 Jun 2024 09:30:34 +0200 Subject: [PATCH 10/56] add changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14ecbab2c8..bff0ca0b0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* O365OrgSettings + * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) + # 1.24.605.1 * AADAuthenticationFlowPolicy From feea33ba7dab8b762fc4e8155f6cbba3963666dd Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Wed, 24 Jul 2024 23:43:04 +0200 Subject: [PATCH 11/56] Update Intune Settings Catalog handling --- .../Modules/M365DSCDRGUtil.psm1 | 10 + .../M365DSCResourceGenerator.psm1 | 179 +++++++++++++----- 2 files changed, 139 insertions(+), 50 deletions(-) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 6f84482e14..d46f9616e9 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -1511,6 +1511,16 @@ function Get-IntuneSettingCatalogPolicySetting $DSCParams.Remove('DisplayName') | Out-Null $DSCParams.Remove('Description') | Out-Null + $DSCParams = Rename-M365DSCCimInstanceParameter -Properties $DSCParams + $keys = (([Hashtable]$DSCParams).Clone()).Keys + foreach ($key in $keys) + { + if ($null -ne $DSCParams.$key -and $DSCParams.$key.GetType().Name -like '*CimInstance*') + { + $DSCParams.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.$key + } + } + # Prepare setting definitions mapping $settingTemplates = Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate ` -DeviceManagementConfigurationPolicyTemplateId $TemplateId ` diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index 1cc3f8df17..ebb7b0ffbe 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -188,7 +188,7 @@ function New-M365DSCResource -CimClasses $cimClasses ` -Workload $Workload $typeProperties = $typeProperties | Where-Object -FilterScript { - $_.Name -notin @('createdDateTime', 'isAssigned', 'lastModifiedDateTime', 'priorityMetaData', 'retryCount', 'settingCount', 'templateReference') + $_.Name -notin @('createdDateTime', 'isAssigned', 'lastModifiedDateTime', 'priorityMetaData', 'retryCount', 'settingCount', 'templateReference', 'creationSource') } $global:ComplexList = $null $global:searchedEntity = $null @@ -236,12 +236,6 @@ function New-M365DSCResource $Global:AlreadyFoundInstances = $null $parameterString = Get-ParameterBlockStringForModule -ParameterBlockInformation $parameterInformation - $hashtableResults = New-M365HashTableMapping -Properties $parameterInformation ` - -DefaultParameterSetProperties $defaultParameterSetProperties ` - -GraphNoun $CmdLetNoun ` - -Workload $Workload ` - -DateFormat $DateFormat - $hashTableMapping = $hashtableResults.StringContent if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") { @@ -267,8 +261,31 @@ function New-M365DSCResource $parameterString += $definitionSettings.PowerShell -join ",`r`n`r`n" $parameterString += ",`r`n`r`n" + + $complexParameters = @($definitionSettings.PowerShell | Where-Object -FilterScript { $_ -like "*CimInstance*" }) + foreach ($parameter in $complexParameters) + { + $parameter -match '\$.*$' + $parameterName = $Matches[0].Replace('$', '') + $parameterInformation += @{ + Name = $parameterName + IsComplexType = $true + IsMandatory = $false + IsArray = $true + Type = 'IntuneSettingsCatalog' + $parameterName + } + + Write-Warning "Do not forget to replace the value `$getValue.$parameterName with `$policySettings.$parameterName in Get-TargetResource and update the description in the MOF template." + } } + $hashtableResults = New-M365HashTableMapping -Properties $parameterInformation ` + -DefaultParameterSetProperties $defaultParameterSetProperties ` + -GraphNoun $CmdLetNoun ` + -Workload $Workload ` + -DateFormat $DateFormat + $hashTableMapping = $hashtableResults.StringContent + #region UnitTests $fakeValues = Get-M365DSCFakeValues ` -ParametersInformation $parameterInformation ` @@ -477,11 +494,11 @@ function New-M365DSCResource $newDefaultParameterSet = $newCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Create' } [Array]$newKeyIdentifier = ($newDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name $defaultCreateParameters = @" - `$createParameters = ([Hashtable]`$BoundParameters).clone() + `$createParameters = ([Hashtable]`$BoundParameters).Clone() `$createParameters = Rename-M365DSCCimInstanceParameter -Properties `$createParameters `$createParameters.Remove('Id') | Out-Null - `$keys = (([Hashtable]`$createParameters).clone()).Keys + `$keys = (([Hashtable]`$createParameters).Clone()).Keys foreach (`$key in `$keys) { if (`$null -ne `$createParameters.`$key -and `$createParameters.`$key.GetType().Name -like '*CimInstance*') @@ -491,17 +508,17 @@ function New-M365DSCResource } "@ $defaultUpdateParameters = @" - `$UpdateParameters = ([Hashtable]`$BoundParameters).clone() - `$UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $`UpdateParameters + `$updateParameters = ([Hashtable]`$BoundParameters).Clone() + `$updateParameters = Rename-M365DSCCimInstanceParameter -Properties `$updateParameters - `$UpdateParameters.Remove('Id') | Out-Null + `$updateParameters.Remove('Id') | Out-Null - `$keys = (([Hashtable]`$UpdateParameters).clone()).Keys + `$keys = (([Hashtable]`$updateParameters).Clone()).Keys foreach (`$key in `$keys) { - if (`$null -ne `$UpdateParameters.`$key -and `$UpdateParameters.`$key.GetType().Name -like '*CimInstance*') + if (`$null -ne `$pdateParameters.`$key -and `$updateParameters.`$key.GetType().Name -like '*CimInstance*') { - `$UpdateParameters.`$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject `$UpdateParameters.$key + `$updateParameters.`$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject `$updateParameters.$key } } @@ -534,7 +551,6 @@ function New-M365DSCResource } $settingsCatalogProperties = "" - $defaultCreateParameters = "" if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") { $odataType = "" @@ -662,7 +678,6 @@ function New-M365DSCResource } $updateCmdletName = " $updateVerb-$CmdLetNoun" - $defaultUpdateParameters = "" if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") { $odataType = "" @@ -681,7 +696,7 @@ function New-M365DSCResource -Platforms `$platforms `` -Technologies `$technologies `` -Settings `$settings`r`n -"@ +"@ } Write-TokenReplacement -Token '<#DefaultUpdateParameters#>' -Value $defaultUpdateParameters -FilePath $moduleFilePath Write-TokenReplacement -Token '' -Value "$odataType" -FilePath $moduleFilePath @@ -731,7 +746,7 @@ function New-M365DSCResource $AssignmentsRemove += " `$BoundParameters.Remove(`"Assignments`") | Out-Null`r`n" - $AssignmentsNew += " " + $AssignmentsNew += "" $AssignmentsNew += "`r`n" $AssignmentsNew += " if (`$policy.Id)`r`n" $AssignmentsNew += " {`r`n" @@ -811,6 +826,9 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments } } "@ + Write-TokenReplacement -Token 'Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)' ` + -Value 'Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)' ` + -FilePath $moduleFilePath } Write-TokenReplacement -Token '<#DefaultTestValuesToCheck#>' -Value $defaultTestValuesToCheck -FilePath $moduleFilePath @@ -825,6 +843,7 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy") { + $CimInstancesSchemaContent += "`r`n" + ($definitionsettings.MOFInstance -join "`r`n`r`n") $schemaProperties += $definitionSettings.MOF -join "`r`n" } @@ -3643,9 +3662,19 @@ function Get-SettingsCatalogSettingDefinitionValueType { if ($type -eq 'Simple') { $type += $SettingDefinition.AdditionalProperties.defaultValue.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValue", "") } elseif ($type -eq 'SimpleCollection') { - $type = $type.Replace("Collection", $SettingDefinition.AdditionalProperties.defaultValue.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValue", "") + "Collection") + if ($null -ne $SettingDefinition.AdditionalProperties.defaultValue) { + $type = $type.Replace("Collection", $SettingDefinition.AdditionalProperties.defaultValue.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValue", "") + "Collection") + } else { + $type = $type.Replace("Collection", "StringCollection") + } + } elseif ($type -eq 'ChoiceCollection') { + $type = $type.Replace("Collection", "StringCollection") } else { # Type is GroupCollection and does not have a default value to narrow down the type + # but we can check the maximum count to determine if it is a collection or not + if ($SettingDefinition.AdditionalProperties.maximumCount -gt 1) { + $type += 'Collection' + } } return $type @@ -3669,7 +3698,13 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $RootSettingDefinitions, [Parameter(ParameterSetName = "Start")] - [switch] $FromRoot + [switch] $FromRoot, + + [Parameter(ParameterSetName = "ParseChild")] + [System.String]$ParentInstanceName, + + [Parameter(ParameterSetName = "ParseChild")] + [System.Int32]$Level = 0 ) $settingDefinitionOdataTypeBase = "#microsoft.graph.deviceManagementConfiguration" @@ -3678,7 +3713,7 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $_.Id -eq $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId -and ` ($_.AdditionalProperties.dependentOn.Count -eq 0 -and $_.AdditionalProperties.options.dependentOn.Count -eq 0) } - $settingDefinitionIdPrefix = $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId.Split("_")[0..-1] -join "_" + $settingDefinitionIdPrefix = $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId return New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` -SettingTemplate $SettingTemplate ` -RootSettingDefinitions $RootSettingDefinitions ` @@ -3691,7 +3726,9 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $settings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` -SettingTemplate $SettingTemplate ` -SettingDefinition $RootSettingDefinition ` - -SettingDefinitionIdPrefix $settingDefinitionIdPrefix + -SettingDefinitionIdPrefix $settingDefinitionIdPrefix ` + -Level 1 ` + -ParentInstanceName "MSFT_MicrosoftGraphIntuneSettingsCatalog" } return $settings } @@ -3702,8 +3739,6 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $valueRestriction = Get-SettingsCatalogSettingDefinitionValueDefinition -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase $settingName = $SettingDefinition.Name - $settingNameLowercase = "" - $settingNameLowercase = $SettingDefinition.Id.Replace($SettingDefinitionIdPrefix, "") if ($SettingDefinition.AdditionalProperties.dependentOn.Count -gt 0) { $possibleParentSettingId = $SettingDefinition.AdditionalProperties.dependentOn.parentSettingId.Replace($SettingDefinitionIdPrefix, "") @@ -3711,12 +3746,6 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $possibleParentSettingId = $SettingDefinition.AdditionalProperties.options.dependentOn.parentSettingId | Select-Object -Unique $possibleParentSettingId = $possibleParentSettingId.Replace($SettingDefinitionIdPrefix, "") } - $regex = [Regex]::new($possibleParentSettingId + "_") - $settingNameLowercase = $regex.Replace($settingNameLowercase, "", 1) - - if ($settingNameLowercase -match "_.*_.*") { - $settingNameLowercase = $settingNameLowercase.Split("_")[1..2] -join "_" - } $settingsWithSameName = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $settingName } if ($settingsWithSameName.Count -gt 1) { @@ -3757,21 +3786,37 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $childSettings = @() $childSettings += $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { $_.visibility -notlike "*none*" -and - (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) -or - ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($SettingDefinition.Id))) + (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId -contains $SettingDefinition.Id) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId -contains $SettingDefinition.Id)) + } + + $instanceName = "MSFT_MicrosoftGraphIntuneSettingsCatalog" + if ($Level -ge 2 -and $type -like "GroupCollection*" -and $childSettings.Count -gt 1) + { + $instanceName = $ParentInstanceName + $SettingDefinition.Name + } + + $innerChildSettings = @() + foreach ($childSetting in $childSettings) { + $innerChildSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate -SettingTemplate $SettingTemplate -SettingDefinition $childSetting -SettingDefinitionIdPrefix $SettingDefinitionIdPrefix -Level $($Level + 1) -ParentInstanceName $instanceName } $setting = [ordered]@{ - NameFromId = $settingNameLowercase - Name = $settingName - DisplayName = $SettingDefinition.DisplayName - Type = $type - DefaultValue = $defaultValue - Options = $options + Name = $settingName + DisplayName = $SettingDefinition.DisplayName + Type = $type + DefaultValue = $defaultValue + Options = $options ValueRestriction = $valueRestriction - ChildSettings = foreach ($childSetting in $childSettings) { - New-SettingsCatalogSettingDefinitionSettingsFromTemplate -SettingTemplate $SettingTemplate -SettingDefinition $childSetting -SettingDefinitionIdPrefix $SettingDefinitionIdPrefix - } + InstanceName = $instanceName + ChildSettings = $innerChildSettings + } + + if ($type -eq "GroupCollectionCollection" -and $childSettings.Count -eq 1) + { + # Reset type and make child setting a collection + $setting.Type = "GroupCollection" + $setting.ChildSettings[0].Type += "Collection" } $setting @@ -3785,6 +3830,7 @@ function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { $mofTypeMapping = @{ "Choice" = "String" + "ChoiceStringCollection" = "String" "SimpleString" = "String" "String" = "String" "SimpleInteger" = "SInt32" @@ -3795,17 +3841,26 @@ function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { } $powerShellTypeMapping = @{ "Choice" = "System.String" + "ChoiceStringCollection" = "System.String[]" "SimpleString" = "System.String" "String" = "System.String" "SimpleInteger" = "System.Int32" "Integer" = "System.Int32" "Boolean" = "System.Boolean" "DateTime" = "System.DateTime" + "GroupCollection" = "Microsoft.Management.Infrastructure.CimInstance" + "GroupCollectionCollection" = "Microsoft.Management.Infrastructure.CimInstance[]" "SimpleStringCollection" = "System.String[]" "SimpleIntegerCollection" = "System.Int32[]" } - $mofParameterTemplate = " [Write, Description("""")] ;" + $mofInstanceTemplate = @" +[ClassVersion("1.0.0.0")] +class +{ +}; +"@ + $mofParameterTemplate = " [Write, Description("""")] ;" $powerShellParameterTemplate = @" [Parameter()] [] @@ -3827,9 +3882,17 @@ function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { } $mofDefinition = $mofDefinition.Replace("", $optionsString) $mofDefinition = $mofDefinition.Replace("", $valueMapString) - $mofDefinition = $mofDefinition.Replace("", $mofTypeMapping[$TemplateSetting.Type]) + + if ($TemplateSetting.InstanceName -ne "MSFT_MicrosoftGraphIntuneSettingsCatalog") { + $mofDefinition = $mofDefinition.Replace("", """), EmbeddedInstance(""$($TemplateSetting.InstanceName)") + $mofDefinition = $mofDefinition.Replace("", "String") + } else { + $mofDefinition = $mofDefinition.Replace("", $mofTypeMapping[$TemplateSetting.Type]) + $mofDefinition = $mofDefinition.Replace("", "") + } + $mofDefinition = $mofDefinition.Replace("", $TemplateSetting.Name) - $isCollection = $TemplateSetting.Type -like "*Collection" + $isCollection = ($TemplateSetting.Type -like "*Collection" -and $TemplateSetting.Type -ne "GroupCollection") -or $TemplateSetting.Type -eq "GroupColletionCollection" $mofDefinition = $mofDefinition.Replace("", $( if ($isCollection) { "[]" } else { "" } )) $powerShellDefinition = $powerShellParameterTemplate.Replace("", $TemplateSetting.Name) @@ -3848,15 +3911,31 @@ function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { $powerShellDefinition = $powerShellDefinition.Replace("", $( if ($restriction) { "`n $restriction" } else { "" })) $definition = @{} - if ($TemplateSetting.Type -ne "GroupCollection") { + if ($TemplateSetting.Type -notlike "GroupCollection*" -or $TemplateSetting.InstanceName -ne "MSFT_MicrosoftGraphIntuneSettingsCatalog") { $definition.Add("MOF", @($mofDefinition)) $definition.Add("PowerShell", @($powerShellDefinition)) } - $TemplateSetting.ChildSettings | ForEach-Object { - $childDefinitions = New-ParameterDefinitionFromSettingsCatalogTemplateSetting -TemplateSetting $_ - $definition.MOF += $childDefinitions.MOF - $definition.PowerShell += $childDefinitions.PowerShell + $childDefinitions = @() + foreach ($childSetting in $TemplateSetting.ChildSettings) { + $childDefinitions += New-ParameterDefinitionFromSettingsCatalogTemplateSetting -TemplateSetting $childSetting + } + + if ($TemplateSetting.Type -like "GroupCollection*" -and $TemplateSetting.InstanceName -ne "MSFT_MicrosoftGraphIntuneSettingsCatalog") { + $mofInstanceDefinition = $mofInstanceTemplate.Replace("", $TemplateSetting.InstanceName) + $mofInstanceDefinition = $mofInstanceDefinition.Replace("", $($childDefinitions.MOF | Out-String)) + $definition.Add("MOFInstance", @($mofInstanceDefinition)) + $definition.MOFInstance += $childDefinitions.MOFInstance + } else { + if ($null -ne $childDefinitions.MOFInstance) { + $definition.MOFInstance += $childDefinitions.MOFInstance + } + if ($null -ne $childDefinitions.MOF) { + $definition.MOF += $childDefinitions.MOF + } + if ($null -ne $childDefinitions.PowerShell) { + $definition.PowerShell += $childDefinitions.PowerShell + } } $definition From e6dc717594f44cc91778f0e4d637e3c06a46fa97 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Fri, 2 Aug 2024 11:15:28 +0100 Subject: [PATCH 12/56] Don't check if associated policy is present while removing resource --- CHANGELOG.md | 6 +++ .../MSFT_EXOHostedContentFilterRule.psm1 | 42 ++++++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4146d32157..941971d976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* EXOHostedContentFilterRule + * Don't check if associated `EXOHostedContentFilterPolicy` is present + while removing resource since it's not required + # 1.24.731.1 * AADAuthenticationMethodPolicyFido2 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOHostedContentFilterRule/MSFT_EXOHostedContentFilterRule.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOHostedContentFilterRule/MSFT_EXOHostedContentFilterRule.psm1 index f8f39c8e1a..2adf454d92 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOHostedContentFilterRule/MSFT_EXOHostedContentFilterRule.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOHostedContentFilterRule/MSFT_EXOHostedContentFilterRule.psm1 @@ -297,26 +297,26 @@ function Set-TargetResource $ConnectionMode = New-M365DSCConnection -Workload 'ExchangeOnline' ` -InboundParameters $PSBoundParameters - # Make sure that the associated Policy exists; - $AssociatedPolicy = Get-HostedContentFilterPolicy -Identity $HostedContentFilterPolicy -ErrorAction 'SilentlyContinue' - if ($null -eq $AssociatedPolicy) - { - throw "Error attempting to create EXOHostedContentFilterRule {$Identity}. The specified HostedContentFilterPolicy " + ` - "{$HostedContentFilterPolicy} doesn't exist. Make sure you either create it first or specify a valid policy." - } - - # Make sure that the associated Policy is not Default; - if ($AssociatedPolicy.IsDefault -eq $true ) - { - throw "Policy $Identity is marked as the default. Creating a rule to apply the default policy is not allowed." - } - $CurrentValues = Get-TargetResource @PSBoundParameters $BoundParameters = ([System.Collections.Hashtable]$PSBoundParameters).Clone() $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters if ($Ensure -eq 'Present' -and $CurrentValues.Ensure -eq 'Absent') { + # Make sure that the associated Policy exists; + $AssociatedPolicy = Get-HostedContentFilterPolicy -Identity $HostedContentFilterPolicy -ErrorAction 'SilentlyContinue' + if ($null -eq $AssociatedPolicy) + { + throw "Error attempting to create EXOHostedContentFilterRule {$Identity}. The specified HostedContentFilterPolicy " + ` + "{$HostedContentFilterPolicy} doesn't exist. Make sure you either create it first or specify a valid policy." + } + + # Make sure that the associated Policy is not Default; + if ($AssociatedPolicy.IsDefault -eq $true ) + { + throw "Policy $Identity is marked as the default. Creating a rule to apply the default policy is not allowed." + } + if ($Enabled -and ('Disabled' -eq $CurrentValues.State)) { # New-HostedContentFilterRule has the Enabled parameter, Set-HostedContentFilterRule does not. @@ -332,6 +332,20 @@ function Set-TargetResource } elseif ($Ensure -eq 'Present' -and $CurrentValues.Ensure -eq 'Present') { + # Make sure that the associated Policy exists; + $AssociatedPolicy = Get-HostedContentFilterPolicy -Identity $HostedContentFilterPolicy -ErrorAction 'SilentlyContinue' + if ($null -eq $AssociatedPolicy) + { + throw "Error attempting to create EXOHostedContentFilterRule {$Identity}. The specified HostedContentFilterPolicy " + ` + "{$HostedContentFilterPolicy} doesn't exist. Make sure you either create it first or specify a valid policy." + } + + # Make sure that the associated Policy is not Default; + if ($AssociatedPolicy.IsDefault -eq $true ) + { + throw "Policy $Identity is marked as the default. Creating a rule to apply the default policy is not allowed." + } + $BoundParameters.Remove('Enabled') | Out-Null if ($CurrentValues.HostedContentFilterPolicy -eq $BoundParameters.HostedContentFilterPolicy) { From 564171ec01e988e584ebed5ec8e5dde3631892d5 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 2 Aug 2024 19:05:10 +0200 Subject: [PATCH 13/56] Improve PowerShell 7 support --- CHANGELOG.md | 7 ++ .../Dependencies/Manifest.psd1 | 12 +++ .../Modules/M365DSCReport.psm1 | 21 +++- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 98 +++++++++++++++++-- Tests/TestHarness.psm1 | 1 + .../get-started/powershell7-support.md | 6 +- 6 files changed, 133 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4146d32157..1387489d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* MISC + * Improve module updates and PowerShell Core support across the DSC + resources. + FIXES [#4941](https://github.com/microsoft/Microsoft365DSC/issues/4941) + # 1.24.731.1 * AADAuthenticationMethodPolicyFido2 diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index ffb61d0613..651a963737 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -96,6 +96,18 @@ ModuleName = 'PnP.PowerShell' RequiredVersion = '1.12.0' }, + @{ + ModuleName = 'PSDesiredStateConfiguration' + RequiredVersion = '1.1' + PowerShellCore = $false + }, + @{ + ModuleName = 'PSDesiredStateConfiguration' + RequiredVersion = '2.0.7' + PowerShellCore = $true + ExplicitLoading = $true + Prefix = 'Pwsh' + }, @{ ModuleName = 'ReverseDSC' RequiredVersion = '2.0.0.20' diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 index bf7ce34d56..104aa83797 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 @@ -419,12 +419,21 @@ function Get-Base64EncodedImage { $mimeType = "image/jpeg" } + if($icon.Extension.endsWith("png")) { $mimeType = "image/png" } - $base64EncodedImage = [System.Convert]::ToBase64String((Get-Content -Path $iconPath -Encoding Byte -ReadCount 0)) + if ($PSVersionTable.PSEdition -eq 'Core') + { + $base64EncodedImage = [System.Convert]::ToBase64String((Get-Content -Path $IconPath -AsByteStream -ReadCount 0)) + } + else + { + $base64EncodedImage = [System.Convert]::ToBase64String((Get-Content -Path $iconPath -Encoding Byte -ReadCount 0)) + } + return $("data:$($mimeType);base64,$($base64EncodedImage)") } else @@ -736,7 +745,15 @@ function Compare-M365DSCConfigurations [Array]$DestinationObject = $DestinationObject | Where-Object -FilterScript { $_.ResourceName -notin $ExcludedResources } } - $dscResourceInfo = Get-DSCResource -Module 'Microsoft365DSC' + $isPowerShellCore = $PSVersionTable.PSEdition -eq 'Core' + if ($isPowerShellCore) + { + $dscResourceInfo = Get-PwshDSCResource -Module 'Microsoft365DSC' + } + else + { + $dscResourceInfo = Get-DSCResource -Module 'Microsoft365DSC' + } # Loop through all items in the source array $i = 1 foreach ($sourceResource in $SourceObject) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index 1411a55cac..a94cb4a976 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -1451,6 +1451,7 @@ function Export-M365DSCConfiguration } $Script:M365DSCDependenciesValidated = $false +$Script:IsPowerShellCore = $PSVersionTable.PSEdition -eq 'Core' <# .Description @@ -1477,7 +1478,7 @@ function Confirm-M365DSCDependencies { $ErrorMessage += ' * ' + $invalidDependency.ModuleName + "`r`n" } - $ErrorMessage += 'Please run Update-M365DSCDependencies with scope "currentUser" or as Administrator.' + $ErrorMessage += 'Please run Update-M365DSCDependencies as Administrator.' $ErrorMessage += 'Please run Uninstall-M365DSCOutdatedDependencies.' $Script:M365DSCDependenciesValidated = $false Add-M365DSCEvent -Message $ErrorMessage -EntryType 'Error' ` @@ -1522,6 +1523,17 @@ function Import-M365DSCDependencies foreach ($dependency in $dependencies) { + if ($dependency.PowerShellCore -and -not $Script:IsPowerShellCore) + { + Write-Verbose -Message "Skipping module {$($dependency.ModuleName)} as it is not compatible with Windows PowerShell." + continue + } + elseif ($dependency.PowerShellCore -eq $false -and $Script:IsPowerShellCore) + { + Write-Verbose -Message "Skipping module {$($dependency.ModuleName)} as it is not compatible with PowerShell Core." + continue + } + Import-Module $dependency.ModuleName -RequiredVersion $dependency.RequiredVersion -Force -Global:$Global } } @@ -3096,6 +3108,16 @@ function Update-M365DSCDependencies { if (-not $Force) { + if ($dependency.PowerShellCore -and -not $Script:IsPowerShellCore) + { + Write-Verbose -Message "The dependency {$($dependency.ModuleName)} requires PowerShell Core. Skipping." + continue + } + elseif ($dependency.PowerShellCore -eq $false -and $Script:IsPowerShellCore) + { + Write-Verbose -Message "The dependency {$($dependency.ModuleName)} requires Windows PowerShell. Skipping." + continue + } $found = Get-Module $dependency.ModuleName -ListAvailable | Where-Object -FilterScript { $_.Version -eq $dependency.RequiredVersion } } @@ -3112,10 +3134,21 @@ function Update-M365DSCDependencies } catch { - Write-Verbose -Message "Couldn't retrieve Windows Principal. One possible cause is that the current environment is not Windows OS." + Write-Verbose -Message "Couldn't retrieve Windows Principal. One possible cause is that the current environment is not a Windows OS." } if (-not $errorFound) { + if (-not $dependency.PowerShellCore -and $Script:IsPowerShellCore) + { + Write-Warning "The dependency {$($dependency.ModuleName)} does not support PowerShell Core. Please run Update-M365DSCDependencies in Windows PowerShell." + continue + } + elseif ($dependency.PowerShellCore -and -not $Script:IsPowerShellCore) + { + Write-Warning "The dependency {$($dependency.ModuleName)} requires PowerShell Core. Please run Update-M365DSCDependencies in PowerShell Core." + continue + } + Write-Information -MessageData "Installing $($dependency.ModuleName) version {$($dependency.RequiredVersion)}" Remove-Module $dependency.ModuleName -Force -ErrorAction SilentlyContinue if ($dependency.ModuleName -like 'Microsoft.Graph*') @@ -3127,6 +3160,19 @@ function Update-M365DSCDependencies } } + if ($dependency.ExplicitLoading) + { + Remove-Module $dependency.ModuleName -Force -ErrorAction SilentlyContinue + if ($dependency.Prefix) + { + Import-Module $dependency.ModuleName -Global -Prefix $dependency.Prefix -Force + } + else + { + Import-Module $dependency.ModuleName -Global -Force + } + } + if (-not $found -and $validateOnly) { $returnValue += $dependency @@ -3209,6 +3255,16 @@ function Uninstall-M365DSCOutdatedDependencies Write-Progress -Activity 'Scanning Dependencies' -PercentComplete ($i / $allDependenciesExceptAuth.Count * 100) try { + if ($dependency.PowerShellCore -and -not $Script:IsPowerShellCore) + { + Write-Verbose -Message "Skipping module {$($dependency.ModuleName)} as it is managed by PowerShell Core." + continue + } + elseif ($dependency.PowerShellCore -eq $false -and $Script:IsPowerShellCore) + { + Write-Verbose -Message "Skipping module {$($dependency.ModuleName)} as it is managed by Windows PowerShell." + continue + } $found = Get-Module $dependency.ModuleName -ListAvailable | Where-Object -FilterScript { $_.Version -ne $dependency.RequiredVersion } foreach ($foundModule in $found) { @@ -3583,7 +3639,14 @@ function Get-M365DSCExportContentForResource { if ($Script:AllM365DscResources.Count -eq 0) { - $Script:AllM365DscResources = Get-DscResource -Module 'Microsoft365Dsc' + if ($Script:IsPowerShellCore) + { + $Script:AllM365DscResources = Get-PwshDscResource -Module 'Microsoft365Dsc' + } + else + { + $Script:AllM365DscResources = Get-DscResource -Module 'Microsoft365Dsc' + } } $Resource = $Script:AllM365DscResources.Where({ $_.Name -eq $ResourceName }) @@ -4328,7 +4391,14 @@ function Create-M365DSCResourceExample $ResourceName ) - $resource = Get-DscResource -Name $ResourceName + if ($Script:IsPowerShellCore) + { + $resource = Get-PwshDscResource -Name $ResourceName + } + else + { + $resource = Get-DscResource -Name $ResourceName + } $params = Get-DSCFakeParameters -ModulePath $resource.Path @@ -4413,7 +4483,14 @@ function New-M365DSCMissingResourcesExample { $location = $PSScriptRoot - $m365Resources = Get-DscResource -Module Microsoft365DSC | Select-Object -ExpandProperty Name + if ($Script:IsPowerShellCore) + { + $m365Resources = Get-PwshDscResource -Module Microsoft365DSC | Select-Object -ExpandProperty Name + } + else + { + $m365Resources = Get-DscResource -Module Microsoft365DSC | Select-Object -ExpandProperty Name + } $examplesPath = Join-Path $location -ChildPath '..\Examples\Resources' $examples = Get-ChildItem -Path $examplesPath | Where-Object { $_.PsIsContainer } | Select-Object -ExpandProperty Name @@ -4515,7 +4592,7 @@ function Update-M365DSCModule ) try { - Update-Module -Name 'Microsoft365DSC' -ErrorAction Stop -Scope $Scope + Update-Module -Name 'Microsoft365DSC' -ErrorAction Stop } catch { @@ -4769,7 +4846,14 @@ function Get-M365DSCConfigurationConflict $parsedContent = ConvertTo-DSCObject -Content $ConfigurationContent $resourcesPrimaryIdentities = @() - $resourcesInModule = Get-DSCResource -Module 'Microsoft365DSC' + if ($Script:IsPowerShellCore) + { + $resourcesInModule = Get-PwshDSCResource -Module 'Microsoft365DSC' + } + else + { + $resourcesInModule = Get-DSCResource -Module 'Microsoft365DSC' + } foreach ($component in $parsedContent) { $resourceDefinition = $resourcesInModule | Where-Object -FilterScript {$_.Name -eq $component.ResourceName} diff --git a/Tests/TestHarness.psm1 b/Tests/TestHarness.psm1 index ecc798f884..a1ccd89269 100644 --- a/Tests/TestHarness.psm1 +++ b/Tests/TestHarness.psm1 @@ -38,6 +38,7 @@ function Invoke-TestHarness } Import-Module -Name "$repoDir/Modules/Microsoft365DSC/Microsoft365DSC.psd1" + Import-Module -Name PSDesiredStateConfiguration -Global -Prefix 'Pwsh' -Force $testsToRun = @() # Run Unit Tests diff --git a/docs/docs/user-guide/get-started/powershell7-support.md b/docs/docs/user-guide/get-started/powershell7-support.md index cb869406b4..b12e6f1041 100644 --- a/docs/docs/user-guide/get-started/powershell7-support.md +++ b/docs/docs/user-guide/get-started/powershell7-support.md @@ -41,10 +41,10 @@ that location or use PowerShell 5.1 to install the modules using 'Install-Module Connect-PnPOnline: Could not load file or assembly 'System.IdentityModel.Tokens.Jwt, Version=6.12.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Could not find or load a specific file. (0x80131621) ``` -# PSDesiredStateConfiguration Needs to be Installed Separately +# PSDesiredStateConfiguration needs to be installed separately -Starting with PowerShell 7.2, the core Desired State Configuration module (PSdesiredStateConfiguration) has been decoupled from the core PowerShell build and now need to be installed separately. In a PowerShell 7+ console, you can install the module by running the command: +Starting with PowerShell 7.2, the core Desired State Configuration module (PSdesiredStateConfiguration) has been decoupled from the core PowerShell build and now needs to be installed separately. In an administrative PowerShell 7+ console, you can install the module by running the command: ```powershell -Install-Module PSDesiredStateConfiguration -Force +Update-M365DSCDependencies -Scope AllUsers ``` From eaed5ae9aab5674d84cdbebda82a992f779aae8d Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 2 Aug 2024 21:49:50 +0200 Subject: [PATCH 14/56] Replace some Write-Host with appropriate alternatives --- CHANGELOG.md | 7 ++++ .../Microsoft365DSC/Modules/M365DSCAgent.psm1 | 33 ++++++--------- .../Modules/M365DSCExoResourceUtils.psm1 | 6 +-- .../Modules/M365DSCLogEngine.psm1 | 5 +-- .../Modules/M365DSCPermissions.psm1 | 4 +- .../Modules/M365DSCReport.psm1 | 4 +- .../Modules/M365DSCReverse.psm1 | 16 ++++--- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 42 ++++++++----------- .../M365DSCResourceGenerator.psm1 | 7 +--- 9 files changed, 54 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4146d32157..91e08db211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* MISC + * Replace some `Write-Host` occurrences in core engine with + appropriate alternatives. + FIXES [#4943](https://github.com/microsoft/Microsoft365DSC/issues/4943) + # 1.24.731.1 * AADAuthenticationMethodPolicyFido2 diff --git a/Modules/Microsoft365DSC/Modules/M365DSCAgent.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCAgent.psm1 index 125f753259..8c2274b0e9 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCAgent.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCAgent.psm1 @@ -14,9 +14,6 @@ function Test-M365DSCAgent param( ) - #Ensure the proper dependencies are installed in the current environment. - Confirm-M365DSCDependencies - #region Telemetry $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() $data.Add('Event', 'TestAgent') @@ -68,21 +65,13 @@ function Test-M365DSCAgent #region Modules Dependencies Write-Progress -Activity 'Scanning Dependencies...' -PercentComplete (3 / $TotalSteps * 100) - $M365DSC = Get-Module Microsoft365DSC - $ManifestPath = Join-Path -Path $M365DSC.ModuleBase -ChildPath 'Microsoft365DSC.psd1' - $manifest = Import-PowerShellDataFile $ManifestPath - $dependencies = $manifest.RequiredModules + $dependencies = Update-M365DSCDependencies -ValidateOnly foreach ($dependency in $dependencies) { - $module = Get-Module $dependency.ModuleName -ListAvailable | ` - Where-Object -FilterScript { $_.Version -eq $dependency.RequiredVersion } - if ($null -eq $module) - { - $Issues += @{ - ID = 'I2' - Message = "M365DSC has a dependency on module $($dependency.ModuleName) which was not found. You need to install " + ` - "this module by running: Install-Module $($dependency.ModuleName) -RequiredVersion $($dependency.RequiredVersion) -Force" - } + $Issues += @{ + ID = 'I2' + Message = "M365DSC has a dependency on module $($dependency.ModuleName) which was not found. You need to install " + ` + "this module by running: Install-Module $($dependency.ModuleName) -RequiredVersion $($dependency.RequiredVersion) -Force" } } #endregion @@ -90,23 +79,25 @@ function Test-M365DSCAgent Write-Progress -Completed -Activity 'Completed Analysis' if ($Issues.Count -gt 0) { - Write-Host "The following issues were detected with the current agent's configuration. Please take " + ` - 'proper action to remediate.' + $errorMessage = "The following issues were detected with the current agent's configuration. Please take " + ` + "proper action to remediate. `r`n" $i = 1 foreach ($issue in $Issues) { - Write-Error -Message " [$i/$($Issues.Count)] $($issue.Message)" + $errorMessage += " [$i/$($Issues.Count)] $($issue.Message)`r`n" } + Write-Error -Message $errorMessage -ErrorAction Continue } if ($Recommendations.Count -gt 0) { - Write-Host 'The following recommendations were issued. We strongly recommend adressing those: ' + $warningMessage = 'The following recommendations were issued. We strongly recommend adressing those: ' $i = 1 foreach ($recommendation in $Recommendations) { - Write-Warning " [$i/$($Recommendations.Count)] $($recommendation.Message)" + $warningMessage += " [$i/$($Recommendations.Count)] $($recommendation.Message)`r`n" } + Write-Warning -Message $warningMessage } if ($Recommendations.Count -eq 0 -and $Issues.Count -eq 0) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCExoResourceUtils.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCExoResourceUtils.psm1 index 9f393d6bf5..35f962b2f4 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCExoResourceUtils.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCExoResourceUtils.psm1 @@ -226,8 +226,7 @@ function New-ExoUnitTest } catch { - Write-Host "DSC resource $ResourceName not found!" - break; + throw "DSC resource $ResourceName not found!" } # Copy unit test template @@ -238,8 +237,7 @@ function New-ExoUnitTest } catch { - Write-Host 'Cannot create unit test file!' - break; + throw 'Failed to create unit test file!' } $parameterInformation = @() diff --git a/Modules/Microsoft365DSC/Modules/M365DSCLogEngine.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCLogEngine.psm1 index 15ed9d16ac..85eae9c25c 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCLogEngine.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCLogEngine.psm1 @@ -138,7 +138,7 @@ function New-M365DSCLogEntry } else { - Write-Host " Error Log created at {file://$LogFileName}" -ForegroundColor Red + Write-Host "Error Log created at {file://$LogFileName}" -ForegroundColor Red } #endregion } @@ -332,8 +332,7 @@ function Export-M365DSCDiagnosticData if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator') -eq $false) { - Write-Host -Object '[ERROR] You need to run this cmdlet with Administrator privileges!' -ForegroundColor Red - return + throw 'You need to run this cmdlet with Administrator privileges!' } $afterDate = (Get-Date).AddDays(($NumberOfDays * -1)) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCPermissions.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCPermissions.psm1 index feea85d6f4..ca1d20dd85 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCPermissions.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCPermissions.psm1 @@ -103,7 +103,7 @@ function Get-M365DSCCompiledPermissionList } catch { - Write-Host "File settings.json was not found for resource {$resourceName}" -ForegroundColor Red + Write-Warning -Message "File settings.json was not found for resource {$resourceName}" } if ($null -ne $settingsFilePath) @@ -1747,7 +1747,7 @@ function Update-M365DSCAzureAdApplication { if ($_.Exception.Message -match 'Key credential end date is invalid') { - Write-Host "Caught error: $($_.Exception.Message)" + Write-Error $($_.Exception.Message) -ErrorAction Continue if ($retryCount -lt $maxRetries) { $retryCount++ diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 index bf7ce34d56..d46e9ccfb6 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 @@ -1086,7 +1086,7 @@ function Compare-M365DSCConfigurations } catch { - Write-Host "Error: $_" + Write-Error -Message $_ -ErrorAction Continue } $i++ } @@ -1140,7 +1140,7 @@ function Compare-M365DSCConfigurations } catch { - Write-Host "Error: $_" + Write-Error -Message $_ -ErrorAction Continue } Write-Progress -Activity 'Scanning Destination...' -Completed diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReverse.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReverse.psm1 index 97ec7abbc0..be090cf9a6 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReverse.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReverse.psm1 @@ -256,9 +256,9 @@ function Start-M365DSCConfigurationExtract $ComponentsToSkip += $resource.InputObject } - Write-Host '[WARNING]' -NoNewline -ForegroundColor Yellow - Write-Host ' Based on the provided Authentication parameters, the following resources cannot be extracted: ' -ForegroundColor Gray - Write-Host "$($resourcesNotSupported -join ',')" -ForegroundColor Gray + $warningMessage = 'Based on the provided Authentication parameters, the following resources cannot be extracted: ' + $warningMessage += $resourcesNotSupported -join ',' + Write-Warning -Message $warningMessage # If all selected resources are not valid based on the authentication method used, simply return. if ($ComponentsToSkip.Length -eq $selectedResources.Length) @@ -773,12 +773,12 @@ function Start-M365DSCConfigurationExtract Write-Host "Results:" if ($results.Count -gt 0) { + $errorMessage = '' foreach ($issue in $results) { - Write-Host " - [" -NoNewline - Write-Host "$($issue.Reason)" -ForegroundColor Red -NoNewline - Write-Host "]: $($issue.InstanceName)" + $errorMessage += " - [$($issue.Reason)]: $($issue.InstanceName)`r`n" } + Write-Error -Message $errorMessage -ErrorAction Continue } else { @@ -918,9 +918,7 @@ function Start-M365DSCConfigurationExtract } else { - Write-Host "$($Global:M365DSCEmojiYellowCircle) Warning {" -NoNewline - Write-Host "Cannot export Local Configuration Manager settings. This process isn't executed with Administrative Privileges!" -NoNewline -ForegroundColor DarkCyan - Write-Host '}' + Write-Warning -Message "Cannot export Local Configuration Manager settings. This process isn't executed with Administrative Privileges!" } } catch diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index 1411a55cac..ac50dfc5aa 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -1209,7 +1209,7 @@ function Export-M365DSCConfiguration } else { - Write-Host -Object "[WARNING] We recommend providing the TenantId property in the format of .onmicrosoft.*" -ForegroundColor Yellow + Write-Warning -Message "We recommend providing the TenantId property in the format of .onmicrosoft.*" } } return $true @@ -1276,30 +1276,27 @@ function Export-M365DSCConfiguration { if ($Credential.Username -notmatch ".onmicrosoft.") { - Write-Host -Object "[WARNING] We recommend providing the username in the format of .onmicrosoft.* for the Credential property." -ForegroundColor Yellow + Write-Warning -Message "We recommend providing the username in the format of .onmicrosoft.* for the Credential property." } } if ($PSBoundParameters.ContainsKey('CertificatePath') -eq $true -and ` $PSBoundParameters.ContainsKey('CertificatePassword') -eq $false) { - Write-Host -Object '[ERROR] You have to specify CertificatePassword when you specify CertificatePath' -ForegroundColor Red - return + throw 'You have to specify CertificatePassword when you specify CertificatePath' } if ($PSBoundParameters.ContainsKey('CertificatePassword') -eq $true -and ` $PSBoundParameters.ContainsKey('CertificatePath') -eq $false) { - Write-Host -Object '[ERROR] You have to specify CertificatePath when you specify CertificatePassword' -ForegroundColor Red - return + throw 'You have to specify CertificatePath when you specify CertificatePassword' } if ($PSBoundParameters.ContainsKey('ApplicationId') -eq $true -and ` $PSBoundParameters.ContainsKey('Credential') -eq $false -and ` $PSBoundParameters.ContainsKey('TenantId') -eq $false) { - Write-Host -Object '[ERROR] You have to specify TenantId when you specify ApplicationId' -ForegroundColor Red - return + throw 'You have to specify TenantId when you specify ApplicationId' } if ($PSBoundParameters.ContainsKey('ApplicationId') -eq $true -and ` @@ -1309,8 +1306,7 @@ function Export-M365DSCConfiguration $PSBoundParameters.ContainsKey('ApplicationSecret') -eq $false -and ` $PSBoundParameters.ContainsKey('CertificatePath') -eq $false)) { - Write-Host -Object '[ERROR] You have to specify ApplicationSecret, CertificateThumbprint or CertificatePath when you specify ApplicationId/TenantId' -ForegroundColor Red - return + throw 'You have to specify ApplicationSecret, CertificateThumbprint or CertificatePath when you specify ApplicationId/TenantId' } if (($PSBoundParameters.ContainsKey('ApplicationId') -eq $false -or ` @@ -1320,8 +1316,7 @@ function Export-M365DSCConfiguration $PSBoundParameters.ContainsKey('ApplicationSecret') -eq $true -or ` $PSBoundParameters.ContainsKey('CertificatePath') -eq $true)) { - Write-Host -Message '[ERROR] You have to specify ApplicationId and TenantId when you specify ApplicationSecret, CertificateThumbprint or CertificatePath' -ForegroundColor Red - return + throw 'You have to specify ApplicationId and TenantId when you specify ApplicationSecret, CertificateThumbprint or CertificatePath' } # Default to Credential if no authentication mechanism were provided @@ -3091,7 +3086,7 @@ function Update-M365DSCDependencies foreach ($dependency in $dependencies) { - Write-Progress -Activity 'Scanning Dependencies' -PercentComplete ($i / $dependencies.Count * 100) + Write-Progress -Activity 'Scanning dependencies' -PercentComplete ($i / $dependencies.Count * 100) try { if (-not $Force) @@ -3134,15 +3129,14 @@ function Update-M365DSCDependencies } catch { - Write-Host "Could not update or import {$($dependency.ModuleName)}" - Write-Host "Error-Mesage: $($_.Exception.Message)" + Write-Error -Message "Could not update or import {$($dependency.ModuleName)}: $($_.Exception.Message)" -ErrorAction Continue } $i++ } # The progress bar seems to hang sometimes. Make sure it is no longer displayed. - Write-Progress -Activity 'Scanning Dependencies' -Completed + Write-Progress -Activity 'Scanning dependencies' -Completed if ($ValidateOnly) { @@ -3152,10 +3146,10 @@ function Update-M365DSCDependencies } catch { - New-M365DSCLogEntry -Message 'Error Updating Dependencies:' ` + New-M365DSCLogEntry -Message 'Error updating dependencies:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) - Write-Error $_ + Write-Error $_ -ErrorAction Continue } } @@ -3194,7 +3188,7 @@ function Uninstall-M365DSCOutdatedDependencies New-M365DSCLogEntry -Message "Could not uninstall $($module.Name) Version $($module.Version)" ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) - Write-Host "Could not uninstall $($module.Name) Version $($module.Version)" + Write-Error -Message "Could not uninstall $($module.Name) Version $($module.Version)" -ErrorAction Continue } } @@ -3225,20 +3219,20 @@ function Uninstall-M365DSCOutdatedDependencies New-M365DSCLogEntry -Message "Could not uninstall $($foundModule.Name) Version $($foundModule.Version)" ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) - Write-Host "Could not uninstall $($foundModule.Name) Version $($foundModule.Version)" + Write-Error -Message "Could not uninstall $($foundModule.Name) Version $($foundModule.Version)" -ErrorAction Continue } } } catch { - Write-Host "Could not uninstall {$($dependency.ModuleName)}" + Write-Error -Message "Could not uninstall {$($dependency.ModuleName)}" -ErrorAction Continue } $i++ } } catch { - New-M365DSCLogEntry -Message 'Error Uninstalling Outdated Dependencies:' ` + New-M365DSCLogEntry -Message 'Error uninstalling outdated dependencies:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) Write-Error $_ @@ -3261,13 +3255,13 @@ function Uninstall-M365DSCOutdatedDependencies } catch { - Write-Host "Could not uninstall $($foundModule.Name) Version $($foundModule.Version) " + Write-Error -Message "Could not uninstall $($foundModule.Name) Version $($foundModule.Version)" -ErrorAction Continue } } } catch { - Write-Host "Could not uninstall {$($dependency.ModuleName)}" + Write-Error -Message "Could not uninstall {$($dependency.ModuleName)}" -ErrorAction Continue } } diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index 1cc3f8df17..89d425d38a 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -1181,14 +1181,12 @@ function Get-MgGraphModuleCmdLetDifference if ($modules.Count -eq 0) { - Write-Host '[ERROR] No module selected!' -ForegroundColor Red - return + throw 'No module selected!' } if (($modules.Name | Sort-Object | Select-Object -Unique).Count -ne 1 -or $modules.Count -ne 2) { - Write-Host '[ERROR] Please select two versions of the same module' -ForegroundColor Red - return + throw 'Please select two versions of the same module' } [array]$exportedKeysModule1 = $modules[0].ExportedCommands.Keys @@ -2568,7 +2566,6 @@ function Get-M365DSCFakeValues { $parameterName = Get-StringFirstCharacterToLower -Value $parameterName } - write-host -ForegroundColor Yellow $parameterName $result.Add($parameterName, $hashValue) } } From 47c1071fe24a3c844a0e47600eef7a1bff1d848b Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Tue, 6 Aug 2024 07:45:10 +0100 Subject: [PATCH 15/56] Allow empty arrays as input --- CHANGELOG.md | 6 ++++++ Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 | 2 ++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4146d32157..78c7af2d31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* M365DSCUtil + * Fix `Compare-PSCustomObjectArrays` by allowing empty arrays as input + FIXES [#4952](https://github.com/microsoft/Microsoft365DSC/issues/4952) + # 1.24.731.1 * AADAuthenticationMethodPolicyFido2 diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index 1411a55cac..822be4eaed 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -437,10 +437,12 @@ function Compare-PSCustomObjectArrays param ( [Parameter(Mandatory = $true)] + [AllowEmptyCollection()] [System.Object[]] $DesiredValues, [Parameter(Mandatory = $true)] + [AllowEmptyCollection()] [System.Object[]] $CurrentValues ) From 3a4a183393edb65a13c815078d2ae505811226ac Mon Sep 17 00:00:00 2001 From: Andrew Hodgson Date: Thu, 8 Aug 2024 10:30:50 +0100 Subject: [PATCH 16/56] ExoAuthenticationPolicyAssignment: Return all users when exporting --- CHANGELOG.md | 4 ++++ .../MSFT_EXOAuthenticationPolicyAssignment.psm1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941971d976..569bb062d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ # UNRELEASED +* EXOAuthenticationPolicyAssignment + * Removes the 1000 user limit when exporting authentication policy assignments + FIXES [#4956](https://github.com/microsoft/Microsoft365DSC/issues/4956) + * EXOHostedContentFilterRule * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAuthenticationPolicyAssignment/MSFT_EXOAuthenticationPolicyAssignment.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAuthenticationPolicyAssignment/MSFT_EXOAuthenticationPolicyAssignment.psm1 index 4148c8c09a..8206c166c9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAuthenticationPolicyAssignment/MSFT_EXOAuthenticationPolicyAssignment.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOAuthenticationPolicyAssignment/MSFT_EXOAuthenticationPolicyAssignment.psm1 @@ -356,7 +356,7 @@ function Export-TargetResource foreach ($AuthenticationPolicy in $AllAuthenticationPolicies) { Write-Host " |---[$i/$($AllAuthenticationPolicies.Count)] $($AuthenticationPolicy.Identity)" -NoNewline - $assignedUsers = Get-User -Filter "AuthenticationPolicy -eq '$($AuthenticationPolicy.DistinguishedName)'" + $assignedUsers = Get-User -Filter "AuthenticationPolicy -eq '$($AuthenticationPolicy.DistinguishedName)'" -ResultSize unlimited foreach ($user in $assignedUsers) { From 7c778c747812cb030382037e00890c9b148c40dc Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Tue, 13 Aug 2024 23:40:12 +0200 Subject: [PATCH 17/56] Finalize Intune Settings Catalog Handling and Resource Generation --- CHANGELOG.md | 7 + .../Modules/M365DSCDRGUtil.psm1 | 274 ++++++++++++++---- .../M365DSCResourceGenerator.psm1 | 73 +++-- 3 files changed, 271 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39b9e762df..81e1768306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* M365DSCDRGUtil + * Update Intune Settings Catalog Handling. +* M365DSCResourceGenerator + * Update Intune resource generation for the Settings Catalog. + # 1.24.724.1 * IntuneAntivirusPolicyWindows10SettingCatalog diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index d46f9616e9..ed50f9286b 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -285,7 +285,7 @@ function Get-M365DSCDRGComplexTypeToString { $indent += ' ' } - #If ComplexObject is an Array + #If ComplexObject is an Array if ($ComplexObject.GetType().FullName -like '*[[\]]') { $currentProperty = @() @@ -318,13 +318,13 @@ function Get-M365DSCDRGComplexTypeToString $currentProperty += $indent } - $CIMInstanceName = $CIMInstanceName.replace('MSFT_', '') + $CIMInstanceName = $CIMInstanceName.Replace('MSFT_', '') $currentProperty += "MSFT_$CIMInstanceName{`r`n" $IndentLevel++ $indent = ' ' * $IndentLevel $keyNotNull = 0 - if ($ComplexObject.Keys.count -eq 0) + if ($ComplexObject.Keys.Count -eq 0) { return $null } @@ -336,7 +336,7 @@ function Get-M365DSCDRGComplexTypeToString $keyNotNull++ if ($ComplexObject.$key.GetType().FullName -like 'Microsoft.Graph.PowerShell.Models.*' -or $key -in $ComplexTypeMapping.Name) { - $hashPropertyType = $ComplexObject[$key].GetType().Name.tolower() + $hashPropertyType = $ComplexObject[$key].GetType().Name.ToLower() $isArray = $false if ($ComplexObject[$key].GetType().FullName -like '*[[\]]') @@ -349,7 +349,6 @@ function Get-M365DSCDRGComplexTypeToString $hashPropertyType = ([Array]($ComplexTypeMapping | Where-Object -FilterScript { $_.Name -eq $key }).CimInstanceName)[0] $hashProperty = $ComplexObject[$key] $currentProperty += "`r`n" - } else { @@ -363,7 +362,7 @@ function Get-M365DSCDRGComplexTypeToString if ($isArray -and $key -in $ComplexTypeMapping.Name) { - if ($ComplexObject.$key.count -gt 0) + if ($ComplexObject.$key.Count -gt 0) { $currentProperty += $indent + $key + ' = ' $currentProperty += '@(' @@ -408,7 +407,7 @@ function Get-M365DSCDRGComplexTypeToString } if ($isArray) { - if ($ComplexObject.$key.count -gt 0) + if ($ComplexObject.$key.Count -gt 0) { $currentProperty += $indent $currentProperty += ')' @@ -464,7 +463,7 @@ function Get-M365DSCDRGComplexTypeToString $currentProperty += $indent } - $emptyCIM = $currentProperty.replace(' ', '').replace("`r`n", '') + $emptyCIM = $currentProperty.Replace(' ', '').Replace("`r`n", '') if ($emptyCIM -eq "MSFT_$CIMInstanceName{}") { $currentProperty = $null @@ -1511,16 +1510,6 @@ function Get-IntuneSettingCatalogPolicySetting $DSCParams.Remove('DisplayName') | Out-Null $DSCParams.Remove('Description') | Out-Null - $DSCParams = Rename-M365DSCCimInstanceParameter -Properties $DSCParams - $keys = (([Hashtable]$DSCParams).Clone()).Keys - foreach ($key in $keys) - { - if ($null -ne $DSCParams.$key -and $DSCParams.$key.GetType().Name -like '*CimInstance*') - { - $DSCParams.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.$key - } - } - # Prepare setting definitions mapping $settingTemplates = Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate ` -DeviceManagementConfigurationPolicyTemplateId $TemplateId ` @@ -1528,7 +1517,7 @@ function Get-IntuneSettingCatalogPolicySetting -All $settingInstances = @() - # Iterate over all setting instance templates + # Iterate over all setting instance templates in the setting template foreach ($settingInstanceTemplate in $settingTemplates.SettingInstanceTemplate) { $settingInstance = @{} @@ -1626,7 +1615,15 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue [Parameter()] [System.String] - $SettingValueTemplateId + $SettingValueTemplateId, + + [Parameter()] + [System.String] + $SettingInstanceName = 'MSFT_MicrosoftGraphIntuneSettingsCatalog', + + [Parameter()] + [System.Int32] + $Level = 1 ) $settingValuesToReturn = @{} @@ -1640,10 +1637,10 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue } # Depending on the setting type, there is other logic involved - switch ($settingType) + switch ($SettingType) { # GroupSettingCollections are a collection of settings without a value of their own - '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + { $_ -eq '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' -or $_ -eq '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' } { $groupSettingCollectionValue = @{} $groupSettingCollectionValueChildren = @() @@ -1653,40 +1650,94 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue $_.settingInstanceTemplate.settingDefinitionId -eq $SettingDefinition.RootDefinitionId } $groupSettingCollectionDefinitionChildren += $templates.SettingDefinitions | Where-Object { - ($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) -or - ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($SettingDefinition.Id)) + ($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId -contains $SettingDefinition.Id) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId -contains $SettingDefinition.Id) } - foreach ($childDefinition in $groupSettingCollectionDefinitionChildren) + + $instanceCount = 1 + if ($Level -ge 2 -and $groupSettingCollectionDefinitionChildren.Count -gt 1) { - $childSettingName = $childDefinition.Name - $childSettingType = $childDefinition.AdditionalProperties.'@odata.type'.Replace('Definition', 'Instance') - $childSettingValueName = $childSettingType.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') - $childSettingValueType = "#microsoft.graph.deviceManagementConfiguration$($childSettingValueName)" - $childSettingValueName = $childSettingValueName.Substring(0, 1).ToLower() + $childSettingValueName.Substring(1, $childSettingValueName.length - 1 ) - $childSettingInstanceTemplate = $SettingTemplates.SettingInstanceTemplate | Where-Object { $_.SettingDefinitionId -eq $childDefinition.Id } - $childSettingValueTemplateId = $childSettingInstanceTemplate.AdditionalProperties."$($childSettingValueName)Template".settingValueTemplateId - $childSettingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` - -DSCParams $DSCParams ` - -SettingDefinition $childDefinition ` - -SettingTemplates $SettingTemplates ` - -SettingName $childSettingName ` - -SettingType $childDefinition.AdditionalProperties.'@odata.type' ` - -SettingValueName $childSettingValueName ` - -SettingValueType $childSettingValueType ` - -SettingValueTemplateId $childSettingValueTemplateId + $SettingInstanceName += $SettingDefinition.Name + $cimDSCParams = @() + $cimDSCParamsName = "" + $DSCParams.GetEnumerator() | Where-Object -FilterScript { + $_.Value.CimClass.CimClassName -contains $SettingInstanceName + } | Foreach-Object -Process { + $cimDSCParams += $_.Value + $cimDSCParamsName = $_.Key + } + $newDSCParams = @{ + $cimDSCParamsName = @() + } + foreach ($instance in $cimDSCParams) { + $newInstanceDSCParams = @{} + # Preserve CIM instances when converting to hashtable + foreach ($property in $instance.CimInstanceProperties) { + $newInstanceDSCParams.Add($property.Name, $property.Value) + } + $newDSCParams.$cimDSCParamsName += $newInstanceDSCParams + } + $instanceCount = $newDSCParams.$cimDSCParamsName.Count + $DSCParams = @{ + $cimDSCParamsName = if ($instanceCount -eq 1) { $newDSCParams.$cimDSCParamsName[0] } else { $newDSCParams.$cimDSCParamsName } + } + } - if ($childSettingValue.Keys.Count -gt 0) - { - if ($childSettingValue.Keys -notcontains 'settingDefinitionId') - { - $childSettingValue.Add('settingDefinitionId', $childDefinition.Id) + for ($i = 0; $i -lt $instanceCount; $i++) + { + $currentDSCParams = if ($instanceCount -eq 1) { + if (-not [System.String]::IsNullOrEmpty($cimDSCParamsName)) { + $DSCParams.$cimDSCParamsName + } else { + $DSCParams } - if (-not [string]::IsNullOrEmpty($childSettingInstanceTemplate.settingInstanceTemplateId)) + } else { + if (-not [System.String]::IsNullOrEmpty($cimDSCParamsName)) { + $DSCParams.$cimDSCParamsName[$i] + } else { + $DSCParams[$i] + } + } + if ($null -eq $currentDSCParams) + { + # Should we continue? Let's try out + $currentDSCParams = @{} + } + + foreach ($childDefinition in $groupSettingCollectionDefinitionChildren) + { + $childSettingName = $childDefinition.Name + $childSettingType = $childDefinition.AdditionalProperties.'@odata.type'.Replace('Definition', 'Instance') + $childSettingValueName = $childSettingType.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') + $childSettingValueType = "#microsoft.graph.deviceManagementConfiguration$($childSettingValueName)" + $childSettingValueName = $childSettingValueName.Substring(0, 1).ToLower() + $childSettingValueName.Substring(1, $childSettingValueName.length - 1 ) + $childSettingInstanceTemplate = $SettingTemplates.SettingInstanceTemplate | Where-Object { $_.SettingDefinitionId -eq $childDefinition.Id } + $childSettingValueTemplateId = $childSettingInstanceTemplate.AdditionalProperties."$($childSettingValueName)Template".settingValueTemplateId + $childSettingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` + -DSCParams $currentDSCParams ` + -SettingDefinition $childDefinition ` + -SettingTemplates $SettingTemplates ` + -SettingName $childSettingName ` + -SettingType $childDefinition.AdditionalProperties.'@odata.type' ` + -SettingValueName $childSettingValueName ` + -SettingValueType $childSettingValueType ` + -SettingValueTemplateId $childSettingValueTemplateId ` + -SettingInstanceName $SettingInstanceName ` + -Level ($Level + 1) + + if ($childSettingValue.Keys.Count -gt 0) { - $childSettingValue.Add('settingInstanceTemplateReference', @{'settingInstanceTemplateId' = $childSettingInstanceTemplate.settingInstanceTemplateId }) + if ($childSettingValue.Keys -notcontains 'settingDefinitionId') + { + $childSettingValue.Add('settingDefinitionId', $childDefinition.Id) + } + if (-not [string]::IsNullOrEmpty($childSettingInstanceTemplate.settingInstanceTemplateId)) + { + $childSettingValue.Add('settingInstanceTemplateReference', @{'settingInstanceTemplateId' = $childSettingInstanceTemplate.settingInstanceTemplateId }) + } + $childSettingValue.Add('@odata.type', $childSettingType) + $groupSettingCollectionValueChildren += $childSettingValue } - $childSettingValue.Add('@odata.type', $childSettingType) - $groupSettingCollectionValueChildren += $childSettingValue } } @@ -1730,7 +1781,8 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue -SettingType $childDefinition.AdditionalProperties.'@odata.type' ` -SettingValueName $childSettingValueName ` -SettingValueType $childSettingValueType ` - -SettingValueTemplateId $childSettingValueTemplateId + -SettingValueTemplateId $childSettingValueTemplateId ` + -SettingInstanceName $SettingInstanceName if ($childSettingValue.Keys.Count -gt 0) { @@ -1782,6 +1834,31 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue $settingValuesToReturn.Add('choiceSettingValue', $choiceSettingValue) } } + # ChoiceSettingCollection is a collection of ChoiceSettings + { $_ -eq '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionInstance' -or $_ -eq '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionDefinition' } + { + $choiceSettingValueCollection = @() + $valueResult = Get-IntuneSettingCatalogPolicySettingDSCValue ` + -SettingName $SettingName ` + -SettingValueType $SettingValueType ` + -SettingTemplates $SettingTemplates ` + -SettingDefinition $SettingDefinition ` + -DSCParams $DSCParams + + $values = $valueResult.Value + + # We iterate over all the values in the DSC params and add them to the choice setting collection + foreach ($value in $values) + { + $choiceSettingValueCollection += @{ + value = $value + children = @() + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + } + } + + $settingValuesToReturn.Add('choiceSettingCollectionValue', $choiceSettingValueCollection) + } # SimpleSettingCollections are collections of simple settings, e.g. strings or integers { $_ -eq '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' -or $_ -eq '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionDefinition' } { @@ -1793,7 +1870,7 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue -DSCParams $DSCParams $values = $valuesResult.Value - $SettingValueType = $valuesResult.SettingValueType + $SettingValueType = $valuesResult.SettingDefinition.AdditionalProperties.valueDefinition.'@odata.type'.Replace('Definition', '') $settingValueCollection = @() foreach ($v in $values) @@ -1807,7 +1884,7 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue $settingValuesToReturn.Add($SettingValueName, $settingValueCollection) } } - # For all other types, e.g. Integer, String, Boolean, etc., we add the value directly + # For all other types, e.g. Integer or String, we add the value directly Default { $valueResult = Get-IntuneSettingCatalogPolicySettingDSCValue ` @@ -1875,7 +1952,7 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue $matchesId = $false $settingDefinitions = $SettingTemplates.SettingDefinitions ` | Where-Object -FilterScript { $_.Name -eq $key } - + # Edge case where the same setting is defined twice in the template, with the same name and id if ($settingDefinitions.Count -eq 2) { @@ -1894,10 +1971,10 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue { $parentSettingName = $key.Split('_')[0] $parentDefinition = $SettingTemplates.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $parentSettingName } - $childDefinition = $SettingTemplates.SettingDefinitions | Where-Object -FilterScript { + $childDefinition = $SettingTemplates.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $SettingName -and - (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($parentDefinition.Id)) -or - ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($parentDefinition.Id)) + (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId -contains $parentDefinition.Id) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId -contains $parentDefinition.Id) ) } if ($null -ne $parentDefinition -and $null -ne $childDefinition -and $childDefinition.Id -eq $SettingDefinition.Id) @@ -1926,7 +2003,7 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue } } - # If there is exactly one setting with the name, the setting is combined or the id matches, we get the DSC value update the real setting value type + # If there is exactly one setting with the name, the setting is combined or the id matches, we get the DSC value and update the real setting value type if (($name.Count -eq 1 -and $SettingName -eq $key) -or $matchCombined -or $matchesId) { $isArray = $false @@ -1951,6 +2028,7 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue $isArray = $true } } + if ($SettingValueType -like "*Simple*" -or $SettingValueType -in @("#microsoft.graph.deviceManagementConfigurationIntegerSettingValue", "#microsoft.graph.deviceManagementConfigurationStringSettingValue")) { return @{ @@ -1959,6 +2037,18 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue Value = if ($isArray) { ,$DSCParams[$key] } else { $DSCParams[$key] } } } + elseif ($SettingValueType -like "*ChoiceSettingCollection*") + { + $values = @() + foreach ($value in $DSCParams[$key]) + { + $values += "$($SettingDefinition.Id)_$value" + } + + return @{ + Value = $values + } + } else { return @{ @@ -2070,15 +2160,65 @@ function Export-IntuneSettingCatalogPolicySettings Export-IntuneSettingCatalogPolicySettings -SettingInstance $childSetting -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable } } - '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionInstance' { $values = @() - $childSettings = if ($IsRoot) { $SettingInstance.AdditionalProperties.groupSettingCollectionValue.children } else { $SettingInstance.groupSettingCollectionValue.children } - foreach ($value in $childSettings) + $childValues = if ($IsRoot) { $SettingInstance.AdditionalProperties.choiceSettingCollectionValue.value } else { $SettingInstance.choiceSettingCollectionValue.value } + foreach ($value in $childValues) + { + $values += $value.Split('_') | Select-Object -Last 1 + } + $settingValue = $values + } + '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + { + $groupSettingCollectionValue = if ($IsRoot) { $SettingInstance.AdditionalProperties.groupSettingCollectionValue } else { $SettingInstance.groupSettingCollectionValue } + $childSettingDefinitions = $SettingDefinitions | Where-Object -FilterScript { + $settingDefinition.AdditionalProperties.childIds -contains $_.Id + } + + if ($settingDefinition.AdditionalProperties.maximumCount -gt 1 -and $childSettingDefinitions.Count -eq 1) { - Export-IntuneSettingCatalogPolicySettings -SettingInstance $value -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable + # Skip GroupSettingCollection with only one child, go straight to the child property + foreach ($child in $groupSettingCollectionValue) + { + $childInstances = $child.children + foreach ($childInstance in $childInstances) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $childInstance -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable + } + } $addToParameters = $false } + elseif (-not $IsRoot -and $childSettingDefinitions.Count -gt 1) + { + $childValue = $null + $parentSettingDefinition = $SettingDefinitions | Where-Object -FilterScript { $_.Id -eq $settingDefinition.AdditionalProperties.dependentOn.parentSettingId } + if ($settingDefinition.AdditionalProperties.maximumCount -gt 1 -or + $parentSettingDefinition.AdditionalProperties.maximumCount -gt 1) + { + $childValue = @() + } + foreach ($child in $groupSettingCollectionValue) + { + $childHashtable = @{} + foreach ($childInstance in $child.children) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $childInstance -SettingDefinitions $SettingDefinitions -ReturnHashtable $childHashtable + } + $childValue += $childHashtable + } + $settingValue = if ($null -eq $childValue) { $childHashtable } else { ,$childValue } + } + else + { + $childSettings = $childSettingsOrInstances + foreach ($value in $childSettings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $value -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable + $addToParameters = $false + } + } } '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' { @@ -2098,7 +2238,15 @@ function Export-IntuneSettingCatalogPolicySettings if ($addToParameters) { - $ReturnHashtable.Add($settingName, $settingValue) + if (-not $ReturnHashtable.ContainsKey($settingName)) + { + $ReturnHashtable.Add($settingName, $settingValue) + } + else + { + # Only happens when it's a GroupCollection(Collection) with multiple entries + $ReturnHashtable[$settingName] = @($ReturnHashtable[$settingName]) + $settingValue + } } } diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index ebb7b0ffbe..cb050397f8 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -267,16 +267,46 @@ function New-M365DSCResource { $parameter -match '\$.*$' $parameterName = $Matches[0].Replace('$', '') + $parameterType = 'IntuneSettingsCatalog' + $parameterName + $cimInstance = $definitionSettings.MOFInstance | Where-Object -FilterScript { $_ -like "*$parameterType`n*" } + $rowFilter = '\[.*;' + $cimRows = [regex]::Matches($cimInstance, $rowFilter) | Foreach-Object { + $_.Value + } + $cimPropertyNamequery = '[a-zA-Z_]+[\[\]]*;' + $cimProperties = @() + foreach ($row in $cimRows) + { + $cimProperties += [regex]::Matches($row, $cimPropertyNamequery) | Foreach-Object { + $props = @{ + Name = $_.Value.Replace('[', '').Replace(']', '').Replace(';', '') + IsArray = $_.Value.Contains('[]') + IsComplexType = $row.Contains('EmbeddedInstance') + } + if ($props.IsComplexType) + { + Write-Warning -Message "Attention: No automatic complex type conversion is available for the property $($props.Name) in $parameterName. Please implement the conversion manually." + $props.Type = $row.Split(' ')[2].Replace('EmbeddedInstance("', '').Replace('")]', '') + } + $props + } + } $parameterInformation += @{ Name = $parameterName IsComplexType = $true IsMandatory = $false IsArray = $true - Type = 'IntuneSettingsCatalog' + $parameterName + Type = $parameterType + Properties = $cimProperties } - Write-Warning "Do not forget to replace the value `$getValue.$parameterName with `$policySettings.$parameterName in Get-TargetResource and update the description in the MOF template." + Write-Warning -Message "* Do not forget to replace the value `$getValue.$parameterName with `$policySettings.$parameterName in Get-TargetResource, remove it using `$policySettings.Remove('$parameterName')` and update the description in the MOF template. " + Write-Warning -Message "* Make sure to remove the duplicate entry of '$parameterName' in the MOF template." + Write-Warning -Message "* Check all CimInstanceNames in the `$complexTypeMapping in Export-TargetResource because they are not generated correctly." } + + Write-Warning -Message "* Update all occurences of 'Name' from parameters to 'DisplayName', since security and settings catalog policies use 'Name' internally, but the DSC resource uses 'DisplayName' for clarity." + Write-Warning -Message "* Replace the technology, platform and template reference placeholders with the actual values." } $hashtableResults = New-M365HashTableMapping -Properties $parameterInformation ` @@ -696,7 +726,7 @@ function New-M365DSCResource -Platforms `$platforms `` -Technologies `$technologies `` -Settings `$settings`r`n -"@ +"@ } Write-TokenReplacement -Token '<#DefaultUpdateParameters#>' -Value $defaultUpdateParameters -FilePath $moduleFilePath Write-TokenReplacement -Token '' -Value "$odataType" -FilePath $moduleFilePath @@ -3634,7 +3664,9 @@ function Get-SettingsCatalogSettingDefinitionDefaultValue { switch ($type) { "String" { if (-not $nullOrEmpty) { $value } else { "" } } "Integer" { if (-not $nullOrEmpty) { [System.Int32]::Parse($value) } else { 0 } } - "Boolean" { if (-not $nullOrEmpty) { [System.Boolean]::Parse($value) } else { $false } } + # Does not exist + # "Boolean" { if (-not $nullOrEmpty) { [System.Boolean]::Parse($value) } else { $false } } + "Secret" { if (-not $nullOrEmpty) { $value } else { "" } } default { $value } } } else { @@ -3668,7 +3700,8 @@ function Get-SettingsCatalogSettingDefinitionValueType { $type = $type.Replace("Collection", "StringCollection") } } elseif ($type -eq 'ChoiceCollection') { - $type = $type.Replace("Collection", "StringCollection") + $valueType = $SettingDefinition.AdditionalProperties.options[0].optionValue.'@odata.type'.Replace("#microsoft.graph.deviceManagementConfiguration", "").Replace("SettingValue", "") + $type = $type.Replace("Collection", $valueType + "Collection") } else { # Type is GroupCollection and does not have a default value to narrow down the type # but we can check the maximum count to determine if it is a collection or not @@ -3740,16 +3773,9 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { $settingName = $SettingDefinition.Name - if ($SettingDefinition.AdditionalProperties.dependentOn.Count -gt 0) { - $possibleParentSettingId = $SettingDefinition.AdditionalProperties.dependentOn.parentSettingId.Replace($SettingDefinitionIdPrefix, "") - } elseif ($SettingDefinition.AdditionalProperties.options.dependentOn.Count -gt 0) { - $possibleParentSettingId = $SettingDefinition.AdditionalProperties.options.dependentOn.parentSettingId | Select-Object -Unique - $possibleParentSettingId = $possibleParentSettingId.Replace($SettingDefinitionIdPrefix, "") - } - $settingsWithSameName = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $settingName } if ($settingsWithSameName.Count -gt 1) { - # Add parent setting name to the child setting name + # Get the parent setting of the current setting if ($SettingDefinition.AdditionalProperties.dependentOn.parentSettingId.Count -gt 0) { $parentSetting = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { @@ -3764,22 +3790,22 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { } $combinationMatches = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript { - $_.Name -eq $settingName -and ` - (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($parentSetting.Id)) -or ` - ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($parentSetting.Id))) + $_.Name -eq $settingName -and + (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId -contains $parentSetting.Id) -or + ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId -contains $parentSetting.Id)) } # If the combination of parent setting and setting name is unique, add the parent setting name to the setting name if ($combinationMatches.Count -eq 1) { $settingName = $parentSetting.Name + "_" + $settingName } - # If the combination of parent setting and setting name is still not unique, grab the last part of the setting id + # If the combination of parent setting and setting name is still not unique, get the last part of the setting id as the name else { $parentSettingIdProperty = $parentSetting.Id.Split('_')[-1] $parentSettingIdWithoutProperty = $parentSetting.Id.Replace("_$parentSettingIdProperty", "") # We can't use the entire setting here, because the child setting id does not have to come after the parent setting id - $settingName = $settingDefinition.Id.Replace($parentSettingIdWithoutProperty + "_", "").Replace($parentSettingIdProperty + "_", "") + $settingName = $SettingDefinition.Id.Replace($parentSettingIdWithoutProperty + "_", "").Replace($parentSettingIdProperty + "_", "") } } @@ -3791,14 +3817,19 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { } $instanceName = "MSFT_MicrosoftGraphIntuneSettingsCatalog" - if ($Level -ge 2 -and $type -like "GroupCollection*" -and $childSettings.Count -gt 1) + if ($Level -gt 1 -and $type -like "GroupCollection*" -and $childSettings.Count -gt 1) { $instanceName = $ParentInstanceName + $SettingDefinition.Name } $innerChildSettings = @() foreach ($childSetting in $childSettings) { - $innerChildSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate -SettingTemplate $SettingTemplate -SettingDefinition $childSetting -SettingDefinitionIdPrefix $SettingDefinitionIdPrefix -Level $($Level + 1) -ParentInstanceName $instanceName + $innerChildSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` + -SettingTemplate $SettingTemplate ` + -SettingDefinition $childSetting ` + -SettingDefinitionIdPrefix $SettingDefinitionIdPrefix ` + -Level $($Level + 1) ` + -ParentInstanceName $instanceName } $setting = [ordered]@{ @@ -3830,6 +3861,7 @@ function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { $mofTypeMapping = @{ "Choice" = "String" + "ChoiceIntegerCollection" = "SInt32" "ChoiceStringCollection" = "String" "SimpleString" = "String" "String" = "String" @@ -3841,6 +3873,7 @@ function New-ParameterDefinitionFromSettingsCatalogTemplateSetting { } $powerShellTypeMapping = @{ "Choice" = "System.String" + "ChoiceIntegerCollection" = "System.Int32[]" "ChoiceStringCollection" = "System.String[]" "SimpleString" = "System.String" "String" = "System.String" From b39165a5d13fb4374c9d308406566977c2b777e5 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Wed, 14 Aug 2024 23:36:54 +0200 Subject: [PATCH 18/56] Add note for secret value --- ResourceGenerator/M365DSCResourceGenerator.psm1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index cb050397f8..ef185157b9 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -3664,8 +3664,7 @@ function Get-SettingsCatalogSettingDefinitionDefaultValue { switch ($type) { "String" { if (-not $nullOrEmpty) { $value } else { "" } } "Integer" { if (-not $nullOrEmpty) { [System.Int32]::Parse($value) } else { 0 } } - # Does not exist - # "Boolean" { if (-not $nullOrEmpty) { [System.Boolean]::Parse($value) } else { $false } } + # The secret value will require an update at a later date. Currently no use case found for this. "Secret" { if (-not $nullOrEmpty) { $value } else { "" } } default { $value } } From 2f893ce719444a7656cedaf2b40a01e7fb4387b2 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Thu, 15 Aug 2024 12:47:56 +0100 Subject: [PATCH 19/56] Allow PasswordComplexity to be set to 5 --- CHANGELOG.md | 3 +++ ...tProtectionLocalAdministratorPasswordSolutionPolicy.psm1 | 6 +++--- ...ctionLocalAdministratorPasswordSolutionPolicy.schema.mof | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941971d976..e51ede3e32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * EXOHostedContentFilterRule * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required +* IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy + * Fixed issue if `PasswordComplexity` was set to 5 by allowing that value + FIXES [#4963](https://github.com/microsoft/Microsoft365DSC/issues/4963) # 1.24.731.1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 index e6cdb33d58..9a6140387a 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 @@ -54,7 +54,7 @@ function Get-TargetResource [Parameter()] [System.Int32] - [ValidateRange(1, 4)] + [ValidateRange(1, 5)] $PasswordComplexity, [Parameter()] @@ -267,7 +267,7 @@ function Set-TargetResource [Parameter()] [System.Int32] - [ValidateRange(1, 4)] + [ValidateRange(1, 5)] $PasswordComplexity, [Parameter()] @@ -463,7 +463,7 @@ function Test-TargetResource [Parameter()] [System.Int32] - [ValidateRange(1, 4)] + [ValidateRange(1, 5)] $PasswordComplexity, [Parameter()] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof index 4a8235bf89..33aeb469d7 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof @@ -24,7 +24,7 @@ class MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy : OMI [Write, Description("Configures whether the password is encrypted before being stored in Active Directory.")] Boolean AdPasswordEncryptionEnabled; [Write, Description("Configures the name or SID of a user or group that can decrypt the password stored in Active Directory.")] String AdPasswordEncryptionPrincipal; [Write, Description("Configures the name of the managed local administrator account.")] String AdministratorAccountName; - [Write, Description("Configures the password complexity of the managed local administrator account. 1 - Large letters, 2 - Large + small letters, 3 - Large + small letters + numbers, 4 - Large + small letters + numbers + special characters"), ValueMap{"1", "2", "3", "4"}, Values{"1", "2", "3", "4"}] UInt32 PasswordComplexity; + [Write, Description("Configures the password complexity of the managed local administrator account. 1 - Large letters, 2 - Large + small letters, 3 - Large + small letters + numbers, 4 - Large + small letters + numbers + special characters, 5 - Large letters + small letters + numbers + special characters (improved readability)"), ValueMap{"1", "2", "3", "4", "5"}, Values{"1", "2", "3", "4", "5"}] UInt32 PasswordComplexity; [Write, Description("Configures the length of the password of the managed local administrator account. Minimum - 8, Maximum - 64")] UInt32 PasswordLength; [Write, Description("Specifies the actions to take upon expiration of the configured grace period. 1 - Reset password, 3 - Reset password and log off, 5 - Reset password and restart"), ValueMap{"1", "3", "5"}, Values{"1", "3", "5"}] UInt32 PostAuthenticationActions; [Write, Description("Specifies the amount of time (in hours) to wait after an authentication before executing the specified post-authentication actions. Minimum - 0, Maximum - 24")] UInt32 PostAuthenticationResetDelay; From f546f2a64181df778f703310ac5a69ac4921e011 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 15 Aug 2024 19:01:47 +0200 Subject: [PATCH 20/56] Fix test cases and invalid variable declaration --- .../Modules/M365DSCDRGUtil.psm1 | 2 +- ...ulesPolicyWindows10ConfigManager.Tests.ps1 | 12 + ...tDetectionAndResponsePolicyLinux.Tests.ps1 | 6 + ...tDetectionAndResponsePolicyMacOS.Tests.ps1 | 6 + ...ngCatalogASRRulesPolicyWindows10.Tests.ps1 | 449 ++++-------------- 5 files changed, 126 insertions(+), 349 deletions(-) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index ed50f9286b..8adbc514a5 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -2212,7 +2212,7 @@ function Export-IntuneSettingCatalogPolicySettings } else { - $childSettings = $childSettingsOrInstances + $childSettings = $groupSettingCollectionValue.children foreach ($value in $childSettings) { Export-IntuneSettingCatalogPolicySettings -SettingInstance $value -SettingDefinitions $SettingDefinitions -ReturnHashtable $ReturnHashtable diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAttackSurfaceReductionRulesPolicyWindows10ConfigManager.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAttackSurfaceReductionRulesPolicyWindows10ConfigManager.Tests.ps1 index 7f5ca15155..dccfff73ef 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAttackSurfaceReductionRulesPolicyWindows10ConfigManager.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAttackSurfaceReductionRulesPolicyWindows10ConfigManager.Tests.ps1 @@ -63,6 +63,18 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' } + }, + @{ + Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' + Name = 'AttackSurfaceReductionRules' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + 'childIds' = @( + 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_useadvancedprotectionagainstransomware' + ) + minimumCount = 0 + maximumCount = 1 + } } ) SettingInstance = @{ diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyLinux.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyLinux.Tests.ps1 index 02453092ee..2a2d99ef56 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyLinux.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyLinux.Tests.ps1 @@ -57,6 +57,12 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Name = 'tags' AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + childIds = @( + 'linux_mdatp_managed_edr_tags_item_key', + 'linux_mdatp_managed_edr_tags_item_value' + ) + minimumCount = 0 + maximumCount = 1 } }, @{ diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyMacOS.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyMacOS.Tests.ps1 index 344ee94756..9b51196991 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyMacOS.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneEndpointDetectionAndResponsePolicyMacOS.Tests.ps1 @@ -57,6 +57,12 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Name = 'tags' AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + childIds = @( + 'com.apple.managedclient.preferences_tags_item_value', + 'com.apple.managedclient.preferences_tags_item_key' + ) + minimumCount = 1 + maximumCount = 1 } }, @{ diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneSettingCatalogASRRulesPolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneSettingCatalogASRRulesPolicyWindows10.Tests.ps1 index 246ab91305..d4af8433c9 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneSettingCatalogASRRulesPolicyWindows10.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneSettingCatalogASRRulesPolicyWindows10.Tests.ps1 @@ -55,11 +55,108 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-IntuneSettingCatalogPolicySetting -MockWith { } - Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { - return ,@() + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { } - Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = '0' + SettingDefinitions = @( + @{ + Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' + Name = 'AttackSurfaceReductionRules' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + childIds = @( + 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses', + 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros', + 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem', + 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' + ) + maximumCount = 1 + minimumCount = 0 + } + }, + @{ + Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' + Name = 'BlockAdobeReaderFromCreatingChildProcesses' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + } + }, + @{ + Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' + Name = 'BlockWin32APICallsFromOfficeMacros' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + } + }, + @{ + Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' + Name = 'BlockCredentialStealingFromWindowsLocalSecurityAuthoritySubsystem' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + } + }, + @{ + Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' + Name = 'BlockAllOfficeApplicationsFromCreatingChildProcesses' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' + } + } + ) + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' + } + AdditionalProperties = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' + choiceSettingValue = @{ + children = @() + value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_audit' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' + choiceSettingValue = @{ + children = @() + value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros_block' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' + choiceSettingValue = @{ + children = @() + value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_warn' + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' + choiceSettingValue = @{ + children = @() + value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_warn' + } + } + ) + } + ) + } + ) + } + AdditionalProperties = @{} + } } Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyAssignment -MockWith { @@ -140,7 +237,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { BlockAdobeReaderFromCreatingChildProcesses = 'audit' BlockAllOfficeApplicationsFromCreatingChildProcesses = 'warn' BlockCredentialStealingFromWindowsLocalSecurityAuthoritySubsystem = 'warn' - BlockWin32APICallsFromOfficeMacros = 'block' + BlockWin32APICallsFromOfficeMacros = 'block' #drift Credential = $Credential Description = 'test' DisplayName = 'asdfads' @@ -155,92 +252,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Name = 'asdfads' } } - - Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { - return @{ - Id = '0' - SettingDefinitions = @( - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - Name = 'BlockAdobeReaderFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - Name = 'BlockWin32APICallsFromOfficeMacros' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - Name = 'BlockCredentialStealingFromWindowsLocalSecurityAuthoritySubsystem' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - Name = 'BlockAllOfficeApplicationsFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - } - ) - SettingInstance = @{ - SettingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' - SettingInstanceTemplateReference = @{ - SettingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' - } - AdditionalProperties = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' - groupSettingCollectionValue = @( - @{ - children = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_audit' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros_block' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_block' #drift - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_warn' - } - } - ) - } - ) - } - ) - } - AdditionalProperties = @{} - } - } } It 'Should return Present from the Get method' { @@ -285,92 +296,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Name = 'asdfads' } } - - Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { - return @{ - Id = '0' - SettingDefinitions = @( - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - Name = 'BlockAdobeReaderFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - Name = 'BlockWin32APICallsFromOfficeMacros' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - Name = 'BlockCredentialStealingFromWindowsLocalSecurityAuthoritySubsystem' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - Name = 'BlockAllOfficeApplicationsFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - } - ) - SettingInstance = @{ - SettingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' - SettingInstanceTemplateReference = @{ - SettingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' - } - AdditionalProperties = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' - groupSettingCollectionValue = @( - @{ - children = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_audit' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros_block' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_warn' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_warn' - } - } - ) - } - ) - } - ) - } - AdditionalProperties = @{} - } - } } It 'Should return true from the Test method' { @@ -406,92 +331,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Name = 'asdfads' } } - - Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { - return @{ - Id = '0' - SettingDefinitions = @( - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - Name = 'BlockAdobeReaderFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - Name = 'BlockWin32APICallsFromOfficeMacros' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - Name = 'BlockCredentialStealingFromWindowsLocalSecurityAuthoritySubsystem' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - Name = 'BlockAllOfficeApplicationsFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - } - ) - SettingInstance = @{ - SettingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' - SettingInstanceTemplateReference = @{ - SettingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' - } - AdditionalProperties = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' - groupSettingCollectionValue = @( - @{ - children = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_audit' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros_block' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_warn' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_warn' - } - } - ) - } - ) - } - ) - } - AdditionalProperties = @{} - } - } } It 'Should return Present from the Get method' { @@ -526,92 +365,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } } - - Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { - return @{ - Id = '0' - SettingDefinitions = @( - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - Name = 'BlockAdobeReaderFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - Name = 'BlockWin32APICallsFromOfficeMacros' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - Name = 'BlockCredentialStealingFromWindowsLocalSecurityAuthoritySubsystem' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - }, - @{ - Id = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - Name = 'BlockAllOfficeApplicationsFromCreatingChildProcesses' - AdditionalProperties = @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingDefinition' - } - } - ) - SettingInstance = @{ - SettingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules' - SettingInstanceTemplateReference = @{ - SettingInstanceTemplateId = '19600663-e264-4c02-8f55-f2983216d6d7' - } - AdditionalProperties = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' - groupSettingCollectionValue = @( - @{ - children = @( - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockadobereaderfromcreatingchildprocesses_audit' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockwin32apicallsfromofficemacros_block' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem_warn' - } - }, - @{ - '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' - settingDefinitionId = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses' - choiceSettingValue = @{ - children = @() - value = 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules_blockallofficeapplicationsfromcreatingchildprocesses_warn' - } - } - ) - } - ) - } - ) - } - AdditionalProperties = @{} - } - } } It 'Should Reverse Engineer resource from the Export method' { From babe36f3be558fa50f9790b36b3365a2e8f2164c Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Mon, 19 Aug 2024 23:14:54 +0200 Subject: [PATCH 21/56] Fix AuthenticationFlows in Conditional Access Policy --- CHANGELOG.md | 7 ++++ .../MSFT_AADConditionalAccessPolicy.psm1 | 42 +++++++++++++++---- ...MSFT_AADConditionalAccessPolicy.schema.mof | 2 +- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941971d976..a84327386b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ # UNRELEASED +* AADConditionalAccessPolicy + * Fixes an issue where the `AuthenticationFlows` property changed in Graph + and updates on the documentation for the possible values of `TransferMethods`. + FIXES [#4961](https://github.com/microsoft/Microsoft365DSC/issues/4961) + FIXES [#4960](https://github.com/microsoft/Microsoft365DSC/issues/4960) + FIXES [#4734](https://github.com/microsoft/Microsoft365DSC/issues/4734) + FIXES [#4725](https://github.com/microsoft/Microsoft365DSC/issues/4725) * EXOHostedContentFilterRule * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index c64c6aba13..07d70529ae 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -1519,15 +1519,23 @@ function Set-TargetResource if ($currentParameters.ContainsKey('TransferMethods')) { #create and provision TransferMethods condition object if used + $authenticationFlows = if ([System.String]::IsNullOrEmpty($TransferMethods)) + { + $null + } + else + { + @{ + transferMethods = $TransferMethods + } + } if (-not $conditions.Contains('authenticationFlows')) { - $conditions.Add('authenticationFlows', @{ - transferMethods = $TransferMethods - }) + $conditions.Add('authenticationFlows', $authenticationFlows) } else { - $conditions.authenticationFlows.Add('transferMethods', $TransferMethods) + $conditions.authenticationFlows = $authenticationFlows } } @@ -1972,10 +1980,28 @@ function Test-TargetResource $ValuesToCheck = $PSBoundParameters $ValuesToCheck.Remove('Id') | Out-Null - $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` - -Source $($MyInvocation.MyCommand.Source) ` - -DesiredValues $PSBoundParameters ` - -ValuesToCheck $ValuesToCheck.Keys + # If no TransferMethod is specified, ignore it + # If a TransferMethod is specified, check if it is equal to the current value + # while ignoring the order of the values + if (-not $PSBoundParameters.ContainsKey('TransferMethods') -or + $null -eq (Compare-Object -ReferenceObject $TransferMethods.Split(',') -DifferenceObject $CurrentValues.TransferMethods.Split(','))) + { + $ValuesToCheck.Remove('TransferMethods') | Out-Null + $TestResult = $true + } + else + { + Write-Verbose -Message "TransferMethods are not equal: [$TransferMethods] - [$($CurrentValues.TransferMethods)]" + $TestResult = $false + } + + if ($TestResult) + { + $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + } Write-Verbose -Message "Test-TargetResource returned $TestResult" diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof index e31287c13f..c1f6d5283f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof @@ -44,7 +44,7 @@ class MSFT_AADConditionalAccessPolicy : OMI_BaseResource [Write, Description("Specifies, whether Browser Persistence is controlled by the Policy.")] Boolean PersistentBrowserIsEnabled; [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never",""}, Values{"Always","Never",""}] String PersistentBrowserMode; [Write, Description("Name of the associated authentication strength policy.")] String AuthenticationStrength; - [Write, Description("Names of the associated authentication flow transfer methods")] String TransferMethods; + [Write, Description("Names of the associated authentication flow transfer methods. Possible values are '', 'deviceCodeFlow', 'authenticationTransfer', or 'deviceCodeFlow,authenticationTransfer'.")] String TransferMethods; [Write, Description("Authentication context class references.")] String AuthenticationContexts[]; [Write, Description("Specify if the Azure AD CA Policy should exist or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Write, Description("Credentials for the Microsoft Graph delegated permissions."), EmbeddedInstance("MSFT_Credential")] string Credential; From c91bc222047ed2bf9a5a0345cb7aa781a55b8d23 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 21 Aug 2024 09:50:57 +0200 Subject: [PATCH 22/56] Fixing error handling in AADConditionalAccessPolicy --- CHANGELOG.md | 3 +++ .../MSFT_AADConditionalAccessPolicy.psm1 | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941971d976..cff53b3f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # UNRELEASED +* AADConditionalAccessPolicy + * Fixing issue where the resource crashed when trying to retrieve groups + and users from Entra ID which no longer existed * EXOHostedContentFilterRule * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index c64c6aba13..9271de9bbe 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -372,7 +372,7 @@ function Get-TargetResource $IncludeGroup = $null try { - $IncludeGroup = (Get-MgGroup -GroupId $IncludeGroupGUID).displayname + $IncludeGroup = (Get-MgGroup -GroupId $IncludeGroupGUID -ErrorAction Stop).displayname } catch { @@ -382,6 +382,7 @@ function Get-TargetResource -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential + continue } if ($IncludeGroup) { @@ -400,7 +401,7 @@ function Get-TargetResource $ExcludeGroup = $null try { - $ExcludeGroup = (Get-MgGroup -GroupId $ExcludeGroupGUID).displayname + $ExcludeGroup = (Get-MgGroup -GroupId $ExcludeGroupGUID -ErrorAction Stop).displayname } catch { @@ -410,6 +411,7 @@ function Get-TargetResource -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential + continue } if ($ExcludeGroup) { @@ -1026,7 +1028,7 @@ function Set-TargetResource $userguid = $null try { - $userguid = (Get-MgUser -UserId $includeuser).Id + $userguid = (Get-MgUser -UserId $includeuser -ErrorAction Stop).Id } catch { @@ -1073,7 +1075,7 @@ function Set-TargetResource $userguid = $null try { - $userguid = (Get-MgUser -UserId $excludeuser).Id + $userguid = (Get-MgUser -UserId $excludeuser -ErrorAction Stop).Id } catch { @@ -1118,7 +1120,7 @@ function Set-TargetResource $GroupLookup = $null try { - $GroupLookup = Get-MgGroup -Filter "DisplayName eq '$includegroup'" + $GroupLookup = Get-MgGroup -Filter "DisplayName eq '$includegroup'" -ErrorAction Stop } catch { @@ -1168,7 +1170,7 @@ function Set-TargetResource $GroupLookup = $null try { - $GroupLookup = Get-MgGroup -Filter "DisplayName eq '$ExcludeGroup'" + $GroupLookup = Get-MgGroup -Filter "DisplayName eq '$ExcludeGroup'" -ErrorAction Stop } catch { From 27422ed4baafe127ed4cb63b249d237d5cc591d1 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 21 Aug 2024 09:53:52 +0200 Subject: [PATCH 23/56] Added continue keyword to go the next item in the loop --- .../MSFT_AADConditionalAccessPolicy.psm1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index 9271de9bbe..dac87d769f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -314,6 +314,7 @@ function Get-TargetResource -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential + continue } if ($IncludeUser) { @@ -349,6 +350,7 @@ function Get-TargetResource -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential + continue } if ($ExcludeUser) { From a2f9e0a8fa1c91b7f5e307db736d101eeae4464a Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 21 Aug 2024 09:02:13 +0000 Subject: [PATCH 24/56] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md b/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md index 6c9999834d..760138f056 100644 --- a/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md +++ b/docs/docs/resources/azure-ad/AADConditionalAccessPolicy.md @@ -47,7 +47,7 @@ | **PersistentBrowserIsEnabled** | Write | Boolean | Specifies, whether Browser Persistence is controlled by the Policy. | | | **PersistentBrowserMode** | Write | String | Specifies, what Browser Persistence control is enforced by the Policy. | `Always`, `Never`, `` | | **AuthenticationStrength** | Write | String | Name of the associated authentication strength policy. | | -| **TransferMethods** | Write | String | Names of the associated authentication flow transfer methods | | +| **TransferMethods** | Write | String | Names of the associated authentication flow transfer methods. Possible values are '', 'deviceCodeFlow', 'authenticationTransfer', or 'deviceCodeFlow,authenticationTransfer'. | | | **AuthenticationContexts** | Write | StringArray[] | Authentication context class references. | | | **Ensure** | Write | String | Specify if the Azure AD CA Policy should exist or not. | `Present`, `Absent` | | **Credential** | Write | PSCredential | Credentials for the Microsoft Graph delegated permissions. | | From e0a63c541aa86986a6c24a66c99317b386429004 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 21 Aug 2024 09:13:46 +0000 Subject: [PATCH 25/56] Updated Resources and Cmdlet documentation pages --- ...AccountProtectionLocalAdministratorPasswordSolutionPolicy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md b/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md index e19cc33b08..9736f856f2 100644 --- a/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md +++ b/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md @@ -16,7 +16,7 @@ | **AdPasswordEncryptionEnabled** | Write | Boolean | Configures whether the password is encrypted before being stored in Active Directory. | | | **AdPasswordEncryptionPrincipal** | Write | String | Configures the name or SID of a user or group that can decrypt the password stored in Active Directory. | | | **AdministratorAccountName** | Write | String | Configures the name of the managed local administrator account. | | -| **PasswordComplexity** | Write | UInt32 | Configures the password complexity of the managed local administrator account. 1 - Large letters, 2 - Large + small letters, 3 - Large + small letters + numbers, 4 - Large + small letters + numbers + special characters | `1`, `2`, `3`, `4` | +| **PasswordComplexity** | Write | UInt32 | Configures the password complexity of the managed local administrator account. 1 - Large letters, 2 - Large + small letters, 3 - Large + small letters + numbers, 4 - Large + small letters + numbers + special characters, 5 - Large letters + small letters + numbers + special characters (improved readability) | `1`, `2`, `3`, `4`, `5` | | **PasswordLength** | Write | UInt32 | Configures the length of the password of the managed local administrator account. Minimum - 8, Maximum - 64 | | | **PostAuthenticationActions** | Write | UInt32 | Specifies the actions to take upon expiration of the configured grace period. 1 - Reset password, 3 - Reset password and log off, 5 - Reset password and restart | `1`, `3`, `5` | | **PostAuthenticationResetDelay** | Write | UInt32 | Specifies the amount of time (in hours) to wait after an authentication before executing the specified post-authentication actions. Minimum - 0, Maximum - 24 | | From f8846701619240251b23e35339f406571da18fe9 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Wed, 21 Aug 2024 10:46:59 +0100 Subject: [PATCH 26/56] Fix extraction of property TpmRequired --- CHANGELOG.md | 3 ++- .../MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 | 8 ++++---- .../MSFT_IntuneDeviceCompliancePolicyWindows10.schema.mof | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 569bb062d2..a60c43ed4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,11 @@ * EXOAuthenticationPolicyAssignment * Removes the 1000 user limit when exporting authentication policy assignments FIXES [#4956](https://github.com/microsoft/Microsoft365DSC/issues/4956) - * EXOHostedContentFilterRule * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required +* IntuneDeviceCompliancePolicyWindows10 + * Fix extraction of property TpmRequired # 1.24.731.1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 index 419e4ac295..81f4c3aa3b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.psm1 @@ -132,7 +132,7 @@ function Get-TargetResource [Parameter()] [System.Boolean] - $TPMRequired, + $TpmRequired, [Parameter()] [System.String] @@ -247,7 +247,7 @@ function Get-TargetResource DeviceThreatProtectionEnabled = $devicePolicy.AdditionalProperties.deviceThreatProtectionEnabled DeviceThreatProtectionRequiredSecurityLevel = $devicePolicy.AdditionalProperties.deviceThreatProtectionRequiredSecurityLevel ConfigurationManagerComplianceRequired = $devicePolicy.AdditionalProperties.configurationManagerComplianceRequired - TPMRequired = $devicePolicy.AdditionalProperties.tPMRequired + TpmRequired = $devicePolicy.AdditionalProperties.tpmRequired DeviceCompliancePolicyScript = $devicePolicy.AdditionalProperties.deviceCompliancePolicyScript ValidOperatingSystemBuildRanges = $devicePolicy.AdditionalProperties.validOperatingSystemBuildRanges Ensure = 'Present' @@ -418,7 +418,7 @@ function Set-TargetResource [Parameter()] [System.Boolean] - $TPMRequired, + $TpmRequired, [Parameter()] [System.String] @@ -694,7 +694,7 @@ function Test-TargetResource [Parameter()] [System.Boolean] - $TPMRequired, + $TpmRequired, [Parameter()] [System.String] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.schema.mof index 5a2828ddac..3dd4d6a55b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyWindows10/MSFT_IntuneDeviceCompliancePolicyWindows10.schema.mof @@ -44,7 +44,7 @@ class MSFT_IntuneDeviceCompliancePolicyWindows10 : OMI_BaseResource [Write, Description("DeviceThreatProtectionEnabled of the Windows 10 device compliance policy.")] Boolean DeviceThreatProtectionEnabled; [Write, Description("DeviceThreatProtectionRequiredSecurityLevel of the Windows 10 device compliance policy."), ValueMap{"Unavailable","Secured","Low", "Medium","High","NotSet"}, Values{"Unavailable","Secured","Low", "Medium","High","NotSet"}] String DeviceThreatProtectionRequiredSecurityLevel; [Write, Description("ConfigurationManagerComplianceRequired of the Windows 10 device compliance policy.")] Boolean ConfigurationManagerComplianceRequired; - [Write, Description("TPMRequired of the Windows 10 device compliance policy.")] Boolean TPMRequired; + [Write, Description("TpmRequired of the Windows 10 device compliance policy.")] Boolean TpmRequired; [Write, Description("DeviceCompliancePolicyScript of the Windows 10 device compliance policy.")] String DeviceCompliancePolicyScript; [Write, Description("ValidOperatingSystemBuildRanges of the Windows 10 device compliance policy.")] String ValidOperatingSystemBuildRanges[]; [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; From 0ac497e671c3d101bd537bca4cad79a3a0160685 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Wed, 21 Aug 2024 10:47:35 +0100 Subject: [PATCH 27/56] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a60c43ed4d..3c6321b528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required * IntuneDeviceCompliancePolicyWindows10 - * Fix extraction of property TpmRequired + * Fix extraction of property `TpmRequired` # 1.24.731.1 From 3181224460e1e86357fdb16f255681ca8ea47962 Mon Sep 17 00:00:00 2001 From: Ricardo Mestre Date: Wed, 21 Aug 2024 11:25:07 +0100 Subject: [PATCH 28/56] Update CHANGELOG.md --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32e7e01aa2..e9e6fe51d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,11 @@ * IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy * Fixed issue if `PasswordComplexity` was set to 5 by allowing that value FIXES [#4963](https://github.com/microsoft/Microsoft365DSC/issues/4963) +* IntuneDeviceConfigurationCustomPolicyWindows10 + * Change app and delegated permissions for reading to + DeviceManagementConfiguration.ReadWrite.All to cope with + getOmaSettingPlainTextValue which is only working if RW is granted + FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) * M365DSCUtil * Fix `Compare-PSCustomObjectArrays` by allowing empty arrays as input FIXES [#4952](https://github.com/microsoft/Microsoft365DSC/issues/4952) @@ -344,10 +349,6 @@ * Update setting handling so that the value is reverted to default when unset * IntuneDeviceConfigurationCustomPolicyWindows10 * Fixed an issue where the payload of xml files was not encoded as base64. - * Change app and delegated permissions for reading to - DeviceManagementConfiguration.ReadWrite.All to cope with - getOmaSettingPlainTextValue which is only working if RW is granted - FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) * IntuneDeviceConfigurationDefenderForEndpointOnboardingPolicyWindows10 * Fixed a creation and update issue when the exported policy contains a onboarding blob and the tenant is connected to Defender for Endpoint Service. From c24165e09604af93e4e041835cb88b042a22eb77 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 21 Aug 2024 11:04:12 +0000 Subject: [PATCH 29/56] Updated Resources and Cmdlet documentation pages --- .../intune/IntuneDeviceConfigurationCustomPolicyWindows10.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/resources/intune/IntuneDeviceConfigurationCustomPolicyWindows10.md b/docs/docs/resources/intune/IntuneDeviceConfigurationCustomPolicyWindows10.md index 1cab65c261..37558493b4 100644 --- a/docs/docs/resources/intune/IntuneDeviceConfigurationCustomPolicyWindows10.md +++ b/docs/docs/resources/intune/IntuneDeviceConfigurationCustomPolicyWindows10.md @@ -63,7 +63,7 @@ To authenticate with the Microsoft Graph API, this resource required the followi - **Read** - - Group.Read.All, DeviceManagementConfiguration.Read.All + - Group.Read.All, DeviceManagementConfiguration.ReadWrite.All - **Update** @@ -73,7 +73,7 @@ To authenticate with the Microsoft Graph API, this resource required the followi - **Read** - - Group.Read.All, DeviceManagementConfiguration.Read.All + - Group.Read.All, DeviceManagementConfiguration.ReadWrite.All - **Update** From 2877c6c07ab7b9d81d035cd00852e550b7a7f7a4 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 21 Aug 2024 12:16:38 +0000 Subject: [PATCH 30/56] Updated Resources and Cmdlet documentation pages --- .../resources/intune/IntuneDeviceCompliancePolicyWindows10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/intune/IntuneDeviceCompliancePolicyWindows10.md b/docs/docs/resources/intune/IntuneDeviceCompliancePolicyWindows10.md index f9249a42a4..ee9498d7cd 100644 --- a/docs/docs/resources/intune/IntuneDeviceCompliancePolicyWindows10.md +++ b/docs/docs/resources/intune/IntuneDeviceCompliancePolicyWindows10.md @@ -36,7 +36,7 @@ | **DeviceThreatProtectionEnabled** | Write | Boolean | DeviceThreatProtectionEnabled of the Windows 10 device compliance policy. | | | **DeviceThreatProtectionRequiredSecurityLevel** | Write | String | DeviceThreatProtectionRequiredSecurityLevel of the Windows 10 device compliance policy. | `Unavailable`, `Secured`, `Low`, `Medium`, `High`, `NotSet` | | **ConfigurationManagerComplianceRequired** | Write | Boolean | ConfigurationManagerComplianceRequired of the Windows 10 device compliance policy. | | -| **TPMRequired** | Write | Boolean | TPMRequired of the Windows 10 device compliance policy. | | +| **TpmRequired** | Write | Boolean | TpmRequired of the Windows 10 device compliance policy. | | | **DeviceCompliancePolicyScript** | Write | String | DeviceCompliancePolicyScript of the Windows 10 device compliance policy. | | | **ValidOperatingSystemBuildRanges** | Write | StringArray[] | ValidOperatingSystemBuildRanges of the Windows 10 device compliance policy. | | | **Ensure** | Write | String | Present ensures the policy exists, absent ensures it is removed. | `Present`, `Absent` | From 6fa24f5b07bf37a461f8b7e2d12ebcea1c5c73ad Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 21 Aug 2024 12:19:01 +0000 Subject: [PATCH 31/56] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 25293aadb8..a5466b33ac 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -18639,7 +18639,7 @@ }, { "CIMType": "Boolean", - "Name": "TPMRequired", + "Name": "TpmRequired", "Option": "Write" }, { From b97ee2e556b5aec6c1a4743566fbf67055b3c284 Mon Sep 17 00:00:00 2001 From: tayhall <51701340+tayhall@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:21:38 +0100 Subject: [PATCH 32/56] Update MSFT_EXORoleGroup.psm1 Updated to handle $null on compare-object and also allows the adding of members to the Role with empty members --- .../MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 index 44f102c318..ddaf63e526 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 @@ -240,7 +240,14 @@ function Set-TargetResource Remove-RoleGroup -Identity $Name -Confirm:$false -Force } # CASE: Role Group exists and it should, but has different member values than the desired ones - elseif ($Ensure -eq 'Present' -and $currentRoleGroupConfig.Ensure -eq 'Present' -and $null -ne (Compare-Object -ReferenceObject $($currentRoleGroupConfig.Members) -DifferenceObject $Members)) + elseif ($Ensure -eq 'Present' -and $currentRoleGroupConfig.Ensure -eq 'Present' -and $null -ne (Compare-Object -ReferenceObject @($($currentRoleGroupConfig.Members) | Select-Object) -DifferenceObject @($Members | Select-Object))) + { + Write-Verbose -Message "Role Group '$($Name)' already exists, but members need updating." + Write-Verbose -Message "Updating Role Group $($Name) members with values: $(Convert-M365DscHashtableToString -Hashtable $NewRoleGroupParams)" + Update-RoleGroupMember -Identity $Name -Members $Members -Confirm:$false + } + # CASE: Role Assignment Policy exists and it should, but Role has no members as its never been set + elseif ($Ensure -eq 'Present' -and $currentRoleGroupConfig.Ensure -eq 'Present' -and $currentRoleGroupConfig.Members -eq '') { Write-Verbose -Message "Role Group '$($Name)' already exists, but members need updating." Write-Verbose -Message "Updating Role Group $($Name) members with values: $(Convert-M365DscHashtableToString -Hashtable $NewRoleGroupParams)" From be9a38a597be13805d42892f5e5443150937bd6c Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 22 Aug 2024 11:34:25 -0400 Subject: [PATCH 33/56] Updated Teams Dependencies --- CHANGELOG.md | 5 +++++ .../MSFT_TeamsOrgWideAppSettings.psm1 | 6 +++++- Modules/Microsoft365DSC/Dependencies/Manifest.psd1 | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4146d32157..2ac1f78a8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* DEPENDENCIES + * Updated MicrosoftTeams to version 6.5.0. + # 1.24.731.1 * AADAuthenticationMethodPolicyFido2 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsOrgWideAppSettings/MSFT_TeamsOrgWideAppSettings.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsOrgWideAppSettings/MSFT_TeamsOrgWideAppSettings.psm1 index 31b7f3cb62..500b04fb3d 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsOrgWideAppSettings/MSFT_TeamsOrgWideAppSettings.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsOrgWideAppSettings/MSFT_TeamsOrgWideAppSettings.psm1 @@ -15,7 +15,11 @@ function Get-TargetResource [Parameter()] [System.Management.Automation.PSCredential] - $Credential + $Credential, + + [Parameter()] + [System.String[]] + $AccessTokens ) Write-Verbose -Message 'Checking the Teams Upgrade Configuration' diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index ffb61d0613..de87416383 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -86,7 +86,7 @@ }, @{ ModuleName = 'MicrosoftTeams' - RequiredVersion = '6.4.0' + RequiredVersion = '6.5.0' }, @{ ModuleName = "MSCloudLoginAssistant" From 37a844e77e2708060c15d1a1d6fddb92f623d89b Mon Sep 17 00:00:00 2001 From: tayhall <51701340+tayhall@users.noreply.github.com> Date: Fri, 23 Aug 2024 11:53:56 +0100 Subject: [PATCH 34/56] Update CHANGELOG.md Added details of fix and related issue --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 116d97723f..189cf37dcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ # UNRELEASED +* EXORoleGroup + * Fix an issue where roles that have empty members cannot be compared + FIXES [#4977] (https://github.com/microsoft/Microsoft365DSC/issues/4977) * AADConditionalAccessPolicy * Fixing issue where the resource crashed when trying to retrieve groups and users from Entra ID which no longer existed From a9829fa5870183d15ac734ff7bbaef44cabf0554 Mon Sep 17 00:00:00 2001 From: tayhall <51701340+tayhall@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:02:03 +0100 Subject: [PATCH 35/56] Update CHANGELOG.md Alphabetical update --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 189cf37dcd..ba99742b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,7 @@ # UNRELEASED -* EXORoleGroup - * Fix an issue where roles that have empty members cannot be compared - FIXES [#4977] (https://github.com/microsoft/Microsoft365DSC/issues/4977) + * AADConditionalAccessPolicy * Fixing issue where the resource crashed when trying to retrieve groups and users from Entra ID which no longer existed @@ -20,6 +18,9 @@ * EXOHostedContentFilterRule * Don't check if associated `EXOHostedContentFilterPolicy` is present while removing resource since it's not required + * EXORoleGroup + * Fix an issue where roles that have empty members cannot be compared + FIXES [#4977] (https://github.com/microsoft/Microsoft365DSC/issues/4977) * IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy * Fixed issue if `PasswordComplexity` was set to 5 by allowing that value FIXES [#4963](https://github.com/microsoft/Microsoft365DSC/issues/4963) From 6ec0f5645ab9a53ba3d37f5cfaaeba92024a3251 Mon Sep 17 00:00:00 2001 From: Harleycox <68119890+Harleycox@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:09:08 +0100 Subject: [PATCH 36/56] Update to M365DSCReport.psm1 due to typo in script Correcting a typo for the name of the Security & compliance.png file the M365DSCReport.psm1 script when it tries to pull it. Essentially it was missing an 'i' in compliance which meant it errored out every time it tries to call the .png file --- Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 index d46e9ccfb6..9fe918a51b 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 @@ -368,7 +368,7 @@ function Get-IconPath } elseif ($ResourceName.StartsWith('SC')) { - return Get-Base64EncodedImage -IconName "SecurityAndComplance.png" + return Get-Base64EncodedImage -IconName "SecurityAndCompliance.png" } elseif ($ResourceName.StartsWith('SPO')) { From 7a15afc6a07d818cd79422ced65b44992426039b Mon Sep 17 00:00:00 2001 From: Bart Vermeersch Date: Mon, 26 Aug 2024 14:21:37 +0200 Subject: [PATCH 37/56] Update Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 Update mock data/code --- .../Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 index 5fb04e2487..b8ddffc9f1 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 @@ -236,11 +236,9 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DisplayName = 'DSCAU' Id = 'DSCAU' Visibility = 'Public' - AdditionalProperties = @{ - membershipType = 'Assigned' - membershipRule = 'Canada' - membershipRuleProcessingState = 'On' - } + MembershipType = 'Assigned' + MembershipRule = 'Canada' + MembershipRuleProcessingState = 'On' } } @@ -303,8 +301,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Description = 'DSCAU Old Description' DisplayName = 'DSCAU' Id = 'DSCAU' - AdditionalProperties = @{ - membershipType = 'Assigned' + MembershipType = 'Assigned' } } } From 3edd424be62a4f5ce251e18d7e5d33797ccdb61b Mon Sep 17 00:00:00 2001 From: Bart Vermeersch Date: Mon, 26 Aug 2024 14:39:23 +0200 Subject: [PATCH 38/56] Update Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 Forgot to remove a closing bracket --- .../Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 index b8ddffc9f1..2f72570e31 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADAdministrativeUnit.Tests.ps1 @@ -302,7 +302,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DisplayName = 'DSCAU' Id = 'DSCAU' MembershipType = 'Assigned' - } } } From 39b1cfb89ba03bbb9cea2f89a18d55ec95b288a9 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Mon, 26 Aug 2024 22:22:04 +0200 Subject: [PATCH 39/56] Add Intune Device Remediation global script export --- CHANGELOG.md | 9 ++- .../MSFT_IntuneDeviceRemediation.psm1 | 65 +++++++++++++++---- .../MSFT_IntuneDeviceRemediation.schema.mof | 3 +- .../MSFT_IntuneDeviceRemediation/readme.md | 8 +++ .../Modules/M365DSCDRGUtil.psm1 | 7 +- 5 files changed, 73 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d22e3cbaa..f30369cace 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,11 +30,16 @@ DeviceManagementConfiguration.ReadWrite.All to cope with getOmaSettingPlainTextValue which is only working if RW is granted FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) -* O365OrgSettings - * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) +* IntuneDeviceRemediation + * Add export of global remediation scripts. +* M365DSCDRGUtil + * Fixes an issue where the `MSFT_IntuneDeviceRemediationPolicyAssignments` + type would trigger an incorrect comparison in `Compare-M365DSCComplexObject`. * M365DSCUtil * Fix `Compare-PSCustomObjectArrays` by allowing empty arrays as input FIXES [#4952](https://github.com/microsoft/Microsoft365DSC/issues/4952) +* O365OrgSettings + * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) * MISC * Replace some `Write-Host` occurrences in core engine with appropriate alternatives. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.psm1 index e377aaaaa9..88c947479a 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.psm1 @@ -30,6 +30,10 @@ function Get-TargetResource [System.Boolean] $EnforceSignatureCheck, + [Parameter()] + [System.Boolean] + $IsGlobalScript, + [Parameter()] [System.String] $Publisher, @@ -211,6 +215,7 @@ function Get-TargetResource DeviceHealthScriptType = $enumDeviceHealthScriptType DisplayName = $getValue.DisplayName EnforceSignatureCheck = $getValue.EnforceSignatureCheck + IsGlobalScript = $getValue.IsGlobalScript Publisher = $getValue.Publisher RemediationScriptContent = [System.Convert]::ToBase64String($getValue.RemediationScriptContent) RemediationScriptParameters = $complexRemediationScriptParameters @@ -303,6 +308,10 @@ function Set-TargetResource [System.Boolean] $EnforceSignatureCheck, + [Parameter()] + [System.Boolean] + $IsGlobalScript, + [Parameter()] [System.String] $Publisher, @@ -385,20 +394,20 @@ function Set-TargetResource $currentInstance = Get-TargetResource @PSBoundParameters $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + $BoundParameters.Remove('IsGlobalScript') | Out-Null if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') { Write-Verbose -Message "Creating an Intune Device Remediation with DisplayName {$DisplayName}" $BoundParameters.Remove("Assignments") | Out-Null - $CreateParameters = ([Hashtable]$BoundParameters).clone() + $CreateParameters = ([Hashtable]$BoundParameters).Clone() $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters - $CreateParameters.Add('IsGlobalScript', $false) | Out-Null $CreateParameters.DetectionScriptContent = [System.Convert]::FromBase64String($CreateParameters.DetectionScriptContent) $CreateParameters.RemediationScriptContent = [System.Convert]::FromBase64String($CreateParameters.RemediationScriptContent) $CreateParameters.Remove('Id') | Out-Null - $keys = (([Hashtable]$CreateParameters).clone()).Keys + $keys = (([Hashtable]$CreateParameters).Clone()).Keys foreach ($key in $keys) { if ($null -ne $CreateParameters.$key -and $CreateParameters.$key.getType().Name -like '*cimInstance*') @@ -407,7 +416,6 @@ function Set-TargetResource } } #region resource generator code - $CreateParameters.Add("@odata.type", "#microsoft.graph.DeviceHealthScript") $policy = New-MgBetaDeviceManagementDeviceHealthScript -BodyParameter $CreateParameters $assignmentsHash = @() foreach ($assignment in $Assignments) @@ -457,14 +465,25 @@ function Set-TargetResource Write-Verbose -Message "Updating the Intune Device Remediation with Id {$($currentInstance.Id)}" $BoundParameters.Remove("Assignments") | Out-Null - $UpdateParameters = ([Hashtable]$BoundParameters).clone() + $UpdateParameters = ([Hashtable]$BoundParameters).Clone() $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters $UpdateParameters.DetectionScriptContent = [System.Convert]::FromBase64String($UpdateParameters.DetectionScriptContent) $UpdateParameters.RemediationScriptContent = [System.Convert]::FromBase64String($UpdateParameters.RemediationScriptContent) $UpdateParameters.Remove('DeviceHealthScriptType') | Out-Null $UpdateParameters.Remove('Id') | Out-Null - $keys = (([Hashtable]$UpdateParameters).clone()).Keys + if ($currentInstance.IsGlobalScript) + { + Write-Warning -Message "The Intune Device Remediation with Id {$($currentInstance.Id)} is a global script and only few properties can be updated." + $UpdateParameters = @{ + Id = $currentInstance.Id + RoleScopeTagIds = $RoleScopeTagIds + RunAs32Bit = $RunAs32Bit + RunAsAccount = $RunAsAccount + } + } + + $keys = (([Hashtable]$UpdateParameters).Clone()).Keys foreach ($key in $keys) { if ($null -ne $UpdateParameters.$key -and $UpdateParameters.$key.getType().Name -like '*cimInstance*') @@ -473,7 +492,6 @@ function Set-TargetResource } } #region resource generator code - $UpdateParameters.Add("@odata.type", "#microsoft.graph.DeviceHealthScript") Update-MgBetaDeviceManagementDeviceHealthScript ` -DeviceHealthScriptId $currentInstance.Id ` -BodyParameter $UpdateParameters @@ -519,6 +537,10 @@ function Set-TargetResource } elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') { + if ($currentInstance.IsGlobalScript) + { + throw "The Intune Device Remediation with Id {$($currentInstance.Id)} is a global script and cannot be removed." + } Write-Verbose -Message "Removing the Intune Device Remediation with Id {$($currentInstance.Id)}" #region resource generator code Remove-MgBetaDeviceManagementDeviceHealthScript -DeviceHealthScriptId $currentInstance.Id @@ -558,6 +580,10 @@ function Test-TargetResource [System.Boolean] $EnforceSignatureCheck, + [Parameter()] + [System.Boolean] + $IsGlobalScript, + [Parameter()] [System.String] $Publisher, @@ -641,7 +667,7 @@ function Test-TargetResource Write-Verbose -Message "Testing configuration of the Intune Device Remediation with Id {$Id} and DisplayName {$DisplayName}" $CurrentValues = Get-TargetResource @PSBoundParameters - $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() if ($CurrentValues.Ensure -ne $Ensure) { @@ -671,8 +697,23 @@ function Test-TargetResource } $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck.Remove('IsGlobalScript') | Out-Null $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + if ($CurrentValues.IsGlobalScript) + { + Write-Verbose -Message "Detected a global script, removing read-only properties from the comparison" + $ValuesToCheck.Remove('DetectionScriptContent') | Out-Null + $ValuesToCheck.Remove('RemediationScriptContent') | Out-Null + $ValuesToCheck.Remove('DetectionScriptParameters') | Out-Null + $ValuesToCheck.Remove('RemediationScriptParameters') | Out-Null + $ValuesToCheck.Remove('DeviceHealthScriptType') | Out-Null + $ValuesToCheck.Remove('Publisher') | Out-Null + $ValuesToCheck.Remove('EnforceSignatureCheck') | Out-Null + $ValuesToCheck.Remove('DisplayName') | Out-Null + $ValuesToCheck.Remove('Description') | Out-Null + } + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" @@ -750,9 +791,7 @@ function Export-TargetResource [array]$getValue = Get-MgBetaDeviceManagementDeviceHealthScript ` -Filter $Filter ` -All ` - -ErrorAction Stop | Where-Object -FilterScript { - $_.IsGlobalScript -eq $false - } + -ErrorAction Stop #endregion $i = 1 @@ -773,9 +812,9 @@ function Export-TargetResource } $displayedKey = $config.Id - if (-not [String]::IsNullOrEmpty($config.displayName)) + if (-not [String]::IsNullOrEmpty($config.DisplayName)) { - $displayedKey = $config.displayName + $displayedKey = $config.DisplayName } Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline $params = @{ diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.schema.mof index 9270cfc537..1510a7ca58 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/MSFT_IntuneDeviceRemediation.schema.mof @@ -46,7 +46,8 @@ class MSFT_IntuneDeviceRemediation : OMI_BaseResource [Write, Description("List of ComplexType DetectionScriptParameters objects."), EmbeddedInstance("MSFT_MicrosoftGraphdeviceHealthScriptParameter")] String DetectionScriptParameters[]; [Write, Description("DeviceHealthScriptType for the script policy. Possible values are: deviceHealthScript, managedInstallerScript."), ValueMap{"deviceHealthScript","managedInstallerScript"}, Values{"deviceHealthScript","managedInstallerScript"}] String DeviceHealthScriptType; [Required, Description("Name of the device health script")] String DisplayName; - [Write, Description("Indicate whether the script signature needs be checked")] Boolean EnforceSignatureCheck; + [Write, Description("Indicates whether the script signature needs be checked")] Boolean EnforceSignatureCheck; + [Write, Description("Indicates whether the script is a global script provided by Microsoft")] Boolean IsGlobalScript; [Write, Description("Name of the device health script publisher")] String Publisher; [Write, Description("The entire content of the remediation powershell script")] String RemediationScriptContent; [Write, Description("List of ComplexType RemediationScriptParameters objects."), EmbeddedInstance("MSFT_MicrosoftGraphdeviceHealthScriptParameter")] String RemediationScriptParameters[]; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/readme.md index 09ed9308a5..f33b62ac75 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/readme.md +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceRemediation/readme.md @@ -4,3 +4,11 @@ ## Description Intune Device Remediation + +**Important:** Global scripts only allow the update of the following properties: + +* Assignments +* RoleScopeTagIds +* RunAs32Bit +* RunAsAccount + diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 6f84482e14..8c3964599b 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -611,7 +611,8 @@ function Compare-M365DSCComplexObject } if ($Source[0].CimClass.CimClassName -eq 'MSFT_DeviceManagementConfigurationPolicyAssignments' -or - $Source[0].CimClass.CimClassName -like 'MSFT_Intune*Assignments') + ($Source[0].CimClass.CimClassName -like 'MSFT_Intune*Assignments' -and + $Source[0].CimClass.CimClassName -ne 'MSFT_IntuneDeviceRemediationPolicyAssignments')) { $compareResult = Compare-M365DSCIntunePolicyAssignment ` -Source @($Source) ` @@ -1865,7 +1866,7 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue $matchesId = $false $settingDefinitions = $SettingTemplates.SettingDefinitions ` | Where-Object -FilterScript { $_.Name -eq $key } - + # Edge case where the same setting is defined twice in the template, with the same name and id if ($settingDefinitions.Count -eq 2) { @@ -1884,7 +1885,7 @@ function Get-IntuneSettingCatalogPolicySettingDSCValue { $parentSettingName = $key.Split('_')[0] $parentDefinition = $SettingTemplates.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $parentSettingName } - $childDefinition = $SettingTemplates.SettingDefinitions | Where-Object -FilterScript { + $childDefinition = $SettingTemplates.SettingDefinitions | Where-Object -FilterScript { $_.Name -eq $SettingName -and (($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId.Contains($parentDefinition.Id)) -or ($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId.Contains($parentDefinition.Id)) From 2786689168fdc0efe0f4e1bdcbcbf2c98cfde641 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 27 Aug 2024 09:34:59 +0200 Subject: [PATCH 40/56] Fixed #3782 --- CHANGELOG.md | 3 +++ .../MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d22e3cbaa..cbdb8701a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,9 @@ FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) * O365OrgSettings * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) +* SCSensitivityLabel + * Corrected issue where ExternalAccess properties were configured inverted + FIXES [#3782](https://github.com/microsoft/Microsoft365DSC/issues/3782) * M365DSCUtil * Fix `Compare-PSCustomObjectArrays` by allowing empty arrays as input FIXES [#4952](https://github.com/microsoft/Microsoft365DSC/issues/4952) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 index b5a788ec74..056f92cf9f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 @@ -420,13 +420,13 @@ function Get-TargetResource $entry = $protectgroup | Where-Object -FilterScript { $_.Key -eq 'allowaccesstoguestusers' } if ($null -ne $entry) { - $siteAndGroupAccessToGuestUsersValue = -not [Boolean]::Parse($entry.Value) + $siteAndGroupAccessToGuestUsersValue = [Boolean]::Parse($entry.Value) } $entry = $protectgroup | Where-Object -FilterScript { $_.Key -eq 'allowemailfromguestusers' } if ($null -ne $entry) { - $siteAndGroupAllowEmailFromGuestUsers = -not [Boolean]::Parse($entry.Value) + $siteAndGroupAllowEmailFromGuestUsers = [Boolean]::Parse($entry.Value) } $entry = $protectsite | Where-Object -FilterScript { $_.Key -eq 'allowfullaccess' } From 1940d546d992c4aa71f0ca86629a534563f4cc8e Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 27 Aug 2024 10:07:17 +0200 Subject: [PATCH 41/56] Fixes #4989 --- CHANGELOG.md | 4 + .../MSFT_SCAutoSensitivityLabelRule.psm1 | 117 +++++++++--------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbdb8701a6..abe11478ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) * O365OrgSettings * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) +* SCAutoSensitivityLabelRule + * Fixes issue where the export was looping through all possible workloads + instead of the actually targeted workload + FIXES [#4989](https://github.com/microsoft/Microsoft365DSC/issues/4989) * SCSensitivityLabel * Corrected issue where ExternalAccess properties were configured inverted FIXES [#3782](https://github.com/microsoft/Microsoft365DSC/issues/3782) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelRule/MSFT_SCAutoSensitivityLabelRule.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelRule/MSFT_SCAutoSensitivityLabelRule.psm1 index 4f871a10dc..edabc166c2 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelRule/MSFT_SCAutoSensitivityLabelRule.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelRule/MSFT_SCAutoSensitivityLabelRule.psm1 @@ -1140,6 +1140,7 @@ function Export-TargetResource { Write-Host "`r`n" -NoNewline } + foreach ($rule in $rules) { if ($null -ne $Global:M365DSCExportResourceInstancesCount) @@ -1148,83 +1149,79 @@ function Export-TargetResource } Write-Host " |---[$i/$($rules.Length)] $($rule.Name)" -NoNewline + $Results = Get-TargetResource @PSBoundParameters ` + -Name $rule.name ` + -Policy $rule.ParentPolicyName ` + -Workload $rule.LogicalWorkload + + $IsCIMArray = $false + $IsSitCIMArray = $false - [Array]$workloads = $rule.Workload.Replace(' ', '').Split(',') - foreach ($workload in $workloads) + if ($Results.ContentContainsSensitiveInformation.Length -gt 1) { - $Results = Get-TargetResource @PSBoundParameters ` - -Name $rule.name ` - -Policy $rule.ParentPolicyName ` - -Workload $workload + $IsSitCIMArray = $true + } - $IsCIMArray = $false - $IsSitCIMArray = $false + if ($Results.ExceptIfContentContainsSensitiveInformation.Length -gt 1) + { + $IsCIMArray = $true + } - if ($Results.ContentContainsSensitiveInformation.Length -gt 1) + if ($null -ne $Results.ContentContainsSensitiveInformation) + { + if ($null -ne $results.ContentContainsSensitiveInformation.Groups) { - $IsSitCIMArray = $true + $Results.ContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationStringGroup -InformationArray $Results.ContentContainsSensitiveInformation } - - if ($Results.ExceptIfContentContainsSensitiveInformation.Length -gt 1) + else { - $IsCIMArray = $true - } - - if ($null -ne $Results.ContentContainsSensitiveInformation) - { - if ($null -ne $results.ContentContainsSensitiveInformation.Groups) - { - $Results.ContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationStringGroup -InformationArray $Results.ContentContainsSensitiveInformation - } - else - { - $Results.ContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationString -InformationArray $Results.ContentContainsSensitiveInformation - } + $Results.ContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationString -InformationArray $Results.ContentContainsSensitiveInformation } + } - if ($null -ne $Results.ExceptIfContentContainsSensitiveInformation) + if ($null -ne $Results.ExceptIfContentContainsSensitiveInformation) + { + if ($null -ne $results.ExceptIfContentContainsSensitiveInformation.Groups) { - if ($null -ne $results.ExceptIfContentContainsSensitiveInformation.Groups) - { - $Results.ExceptIfContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationStringGroup -InformationArray $Results.ExceptIfContentContainsSensitiveInformation - } - else - { - $Results.ExceptIfContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationString -InformationArray $Results.ExceptIfContentContainsSensitiveInformation - } + $Results.ExceptIfContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationStringGroup -InformationArray $Results.ExceptIfContentContainsSensitiveInformation } - - $IsHeaderPatternsCIMArray = $false - if ($null -ne $Results.HeaderMatchesPatterns -and $null -ne $Results.HeaderMatchesPatterns.Name) + else { - $Results.HeaderMatchesPatterns = ConvertTo-HeadersMatchesPatternString -Patterns $Results.HeaderMatchesPatterns + $Results.ExceptIfContentContainsSensitiveInformation = ConvertTo-SCDLPSensitiveInformationString -InformationArray $Results.ExceptIfContentContainsSensitiveInformation } + } - $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` - -Results $Results - $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` - -ConnectionMode $ConnectionMode ` - -ModulePath $PSScriptRoot ` - -Results $Results ` - -Credential $Credential + $IsHeaderPatternsCIMArray = $false + if ($null -ne $Results.HeaderMatchesPatterns -and $null -ne $Results.HeaderMatchesPatterns.Name) + { + $Results.HeaderMatchesPatterns = ConvertTo-HeadersMatchesPatternString -Patterns $Results.HeaderMatchesPatterns + } - if ($null -ne $Results.ContentContainsSensitiveInformation ) - { - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'ContentContainsSensitiveInformation' -IsCIMArray $IsSitCIMArray - } - if ($null -ne $Results.ExceptIfContentContainsSensitiveInformation ) - { - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'ExceptIfContentContainsSensitiveInformation' -IsCIMArray $IsCIMArray - } - if ($null -ne $Results.HeaderMatchesPatterns) - { - $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'HeaderMatchesPatterns' -IsCIMArray $false - } - $dscContent += $currentDSCBlock + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential - Save-M365DSCPartialExport -Content $currentDSCBlock ` - -FileName $Global:PartialExportFileName + if ($null -ne $Results.ContentContainsSensitiveInformation ) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'ContentContainsSensitiveInformation' -IsCIMArray $IsSitCIMArray + } + if ($null -ne $Results.ExceptIfContentContainsSensitiveInformation ) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'ExceptIfContentContainsSensitiveInformation' -IsCIMArray $IsCIMArray + } + if ($null -ne $Results.HeaderMatchesPatterns) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'HeaderMatchesPatterns' -IsCIMArray $false } + $dscContent += $currentDSCBlock + + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + Write-Host $Global:M365DSCEmojiGreenCheckMark $i++ } From de140f3348091495aba647d52a34acd4568a6341 Mon Sep 17 00:00:00 2001 From: Harleycox <68119890+Harleycox@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:35:39 +0100 Subject: [PATCH 42/56] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac989d634..33346ca3b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ * Replace some `Write-Host` occurrences in core engine with appropriate alternatives. FIXES [#4943](https://github.com/microsoft/Microsoft365DSC/issues/4943) + * Fixed a typo within M365DSCReport.psm1 related to a .png file + FIXES [#4983](https://github.com/microsoft/Microsoft365DSC/pull/4983) # 1.24.731.1 From 5ed9ab56c95b61d9ee4bb35912558e0f9a59e66b Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 27 Aug 2024 10:55:50 +0200 Subject: [PATCH 43/56] Fixes # 4990 --- CHANGELOG.md | 4 ++++ .../MSFT_SCAutoSensitivityLabelPolicy.psm1 | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe11478ba..fa3dd2dfc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) * O365OrgSettings * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) +* SCAutoSensitivityLabelPolicy + * Fixes issue where Mode=Enabled is not supported for SP and OD. Changing + property to TestWithoutNotifications in those instances. + FIXES [#4990](https://github.com/microsoft/Microsoft365DSC/issues/4990) * SCAutoSensitivityLabelRule * Fixes issue where the export was looping through all possible workloads instead of the actually targeted workload diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelPolicy/MSFT_SCAutoSensitivityLabelPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelPolicy/MSFT_SCAutoSensitivityLabelPolicy.psm1 index 0742054bf0..21ed857ab6 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelPolicy/MSFT_SCAutoSensitivityLabelPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCAutoSensitivityLabelPolicy/MSFT_SCAutoSensitivityLabelPolicy.psm1 @@ -384,8 +384,24 @@ function Set-TargetResource $CurrentPolicy = Get-TargetResource @PSBoundParameters + if ($PSBoundParameters.ContainsKey('SharePointLocation') -or $PSBoundParameters.ContainsKey('OneDriveLocation')) + { + if ($PSBoundParameters.ContainsKey('Mode') -eq $false) + { + Write-Verbose "SharePoint or OneDrive location has been specified. Setting Mode to TestWithoutNotifications." + $PSBoundParameters.Add('Mode', 'TestWithoutNotifications') + } + elseif ($PSBoundParameters.Mode -eq 'Enable') + { + Write-Verbose "SharePoint or OneDrive location has been specified. Changing Mode to TestWithoutNotifications." + $PSBoundParameters.Mode = 'TestWithoutNotifications' + } + } + if (('Present' -eq $Ensure) -and ('Absent' -eq $CurrentPolicy.Ensure)) { + Write-Verbose "Creating new Auto Sensitivity label policy $Name." + $CreationParams = $PSBoundParameters #Remove parameters not used in New-LabelPolicy @@ -412,8 +428,6 @@ function Set-TargetResource $CreationParams.Remove('ApplicationSecret') | Out-Null $CreationParams.Remove('AccessTokens') | Out-Null - Write-Verbose "Creating new Auto Sensitivity label policy $Name." - try { New-AutoSensitivityLabelPolicy @CreationParams From 5c49c2d5edf783b6345dcbd2d9ee8bb59cdebab7 Mon Sep 17 00:00:00 2001 From: Sandro Lanfranchi Date: Wed, 28 Aug 2024 13:58:54 +0200 Subject: [PATCH 44/56] fix #4994 --- .../MSFT_AADGroup/MSFT_AADGroup.psm1 | 73 ++++++++++++++++++- .../MSFT_AADGroup/MSFT_AADGroup.schema.mof | 1 + .../Examples/Resources/AADGroup/1-Create.ps1 | 2 + .../Examples/Resources/AADGroup/2-Update.ps1 | 2 + .../Microsoft365DSC.AADGroup.Tests.ps1 | 60 +++++++++++++++ 5 files changed, 137 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 index 02f13b01dc..0a74f43a58 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 @@ -24,6 +24,10 @@ function Get-TargetResource [System.String[]] $Members, + [Parameter()] + [System.String[]] + $GroupAsMembers, + [Parameter()] [System.String[]] $MemberOf, @@ -213,12 +217,17 @@ function Get-TargetResource # Members [Array]$members = Get-MgGroupMember -GroupId $Group.Id -All:$true $MembersValues = @() + $GroupAsMembersValues = @() foreach ($member in $members) { - if ($member.AdditionalProperties.userPrincipalName -ne $null) + if ($member.AdditionalProperties.'@odata.type' -eq "#microsoft.graph.user") { $MembersValues += $member.AdditionalProperties.userPrincipalName } + elseif($member.AdditionalProperties.'@odata.type' -eq "#microsoft.graph.group") + { + $GroupAsMembersValues += $member.AdditionalProperties.displayName + } } } @@ -265,6 +274,7 @@ function Get-TargetResource Id = $Group.Id Owners = $OwnersValues Members = $MembersValues + GroupAsMembers = $GroupAsMembersValues MemberOf = $MemberOfValues Description = $Group.Description GroupTypes = [System.String[]]$Group.GroupTypes @@ -327,6 +337,10 @@ function Set-TargetResource [System.String[]] $Members, + [Parameter()] + [System.String[]] + $GroupAsMembers, + [Parameter()] [System.String[]] $MemberOf, @@ -432,10 +446,12 @@ function Set-TargetResource $currentParameters.Remove('ManagedIdentity') | Out-Null $backCurrentOwners = $currentGroup.Owners $backCurrentMembers = $currentGroup.Members + $backCurrentGroupAsMembers = $currentGroup.GroupAsMembers $backCurrentMemberOf = $currentGroup.MemberOf $backCurrentAssignedToRole = $currentGroup.AssignedToRole $currentParameters.Remove('Owners') | Out-Null $currentParameters.Remove('Members') | Out-Null + $currentParameters.Remove('GroupAsMembers') | Out-Null $currentParameters.Remove('MemberOf') | Out-Null $currentParameters.Remove('AssignedToRole') | Out-Null @@ -728,6 +744,57 @@ function Set-TargetResource Write-Verbose -Message 'Ignoring membership since this is a dynamic group.' } + #GroupAsMembers + if ($MembershipRuleProcessingState -ne 'On' -and $PSBoundParameters.ContainsKey('GroupAsMembers')) + { + $currentGroupAsMembersValue = @() + if ($currentParameters.GroupAsMembers.Length -ne 0) + { + $currentGroupAsMembersValue = $backCurrentGroupAsMembers + } + $desiredGroupAsMembersValue = @() + if ($GroupAsMembers.Length -ne 0) + { + $desiredGroupAsMembersValue = $GroupAsMembers + } + if ($backCurrentGroupAsMembers -eq $null) + { + $backCurrentGroupAsMembers = @() + } + $groupAsMembersDiff = Compare-Object -ReferenceObject $backCurrentGroupAsMembers -DifferenceObject $desiredGroupAsMembersValue + foreach ($diff in $groupAsMembersDiff) + { + try + { + $groupAsMember = Get-MgGroup -Filter "DisplayName eq '$($diff.InputObject)'" -ErrorAction Stop + } + catch + { + $groupAsMember = $null + } + if ($null -eq $groupAsMember) + { + throw "Group '$($diff.InputObject)' does not exist" + } + else + { + if ($diff.SideIndicator -eq '=>') + { + Write-Verbose -Message "Adding AAD group {$($groupAsMember.DisplayName)} as member of AAD group {$($currentGroup.DisplayName)}" + $groupAsMemberObject = @{ + "@odata.id"= "https://graph.microsoft.com/v1.0/directoryObjects/$($groupAsMember.Id)" + } + New-MgGroupMemberByRef -GroupId ($currentGroup.Id) -Body $groupAsMemberObject | Out-Null + } + if ($diff.SideIndicator -eq '<=') + { + Write-Verbose -Message "Removing AAD Group {$($groupAsMember.DisplayName)} from AAD group {$($currentGroup.DisplayName)}" + Remove-MgGroupMemberDirectoryObjectByRef -GroupId ($currentGroup.Id) -DirectoryObjectId ($groupAsMember.Id) | Out-Null + } + } + } + } + #MemberOf if ($PSBoundParameters.ContainsKey('MemberOf')) { @@ -879,6 +946,10 @@ function Test-TargetResource [System.String[]] $Members, + [Parameter()] + [System.String[]] + $GroupAsMembers, + [Parameter()] [System.String[]] $MemberOf, diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.schema.mof index 8f9bc80293..5e3aaf41be 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.schema.mof @@ -14,6 +14,7 @@ class MSFT_AADGroup : OMI_BaseResource [Write, Description("Specifies an ID for the group.")] String Id; [Write, Description("User Service Principal values for the group's owners.")] String Owners[]; [Write, Description("User Service Principal values for the group's members.")] String Members[]; + [Write, Description("Displayname values for the groups member of the group.")] String GroupAsMembers[]; [Write, Description("DisplayName values for the groups that this group is a member of.")] String MemberOf[]; [Write, Description("Specifies that the group is a dynamic group. To create a dynamic group, specify a value of DynamicMembership.")] String GroupTypes[]; [Write, Description("Specifies the membership rule for a dynamic group.")] String MembershipRule; diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADGroup/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADGroup/1-Create.ps1 index 243f549348..fcd816c154 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADGroup/1-Create.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADGroup/1-Create.ps1 @@ -30,6 +30,8 @@ Configuration Example MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("admin@$TenantId", "AdeleV@$TenantId") + GroupAsMembers = @("Group1", "Group2") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADGroup/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADGroup/2-Update.ps1 index 827370cdcc..07b9ba1c62 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADGroup/2-Update.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADGroup/2-Update.ps1 @@ -29,6 +29,8 @@ Configuration Example MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("AdeleV@$TenantId") + GroupAsMembers = @("Group1") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroup.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroup.Tests.ps1 index 9bf9dfdaac..0215457741 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroup.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroup.Tests.ps1 @@ -37,6 +37,9 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgGroupMember -MockWith { } + Mock -CommandName Get-MgGroup -MockWith { + } + Mock -CommandName Restore-MgBetaDirectoryDeletedItem -MockWith { } Mock -CommandName Get-MgBetaDirectoryDeletedItemAsGroup -MockWith { @@ -500,6 +503,63 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + Context -Name 'The Group Exists but group is not assigned as member. Values are NOT in the desired state' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'DSCGroup' + ID = '12345-12345-12345-12345' + Description = 'Microsoft DSC Group' + SecurityEnabled = $True + MailEnabled = $true + GroupTypes = @() + MailNickname = 'M365DSC' + IsAssignableToRole = $true + GroupAsMembers = 'DSCGroupMember' + Ensure = 'Present' + Credential = $Credential + } + + + Mock -CommandName New-M365DSCConnection -MockWith { + return 'Credentials' + } + + Mock -CommandName Get-MgGroup -MockWith { + return @{ + DisplayName = 'DSCGroupMember' + ID = '12345-12345-12345-12345' + Description = 'Microsoft DSC Group' + SecurityEnabled = $True + MailEnabled = $true + GroupTypes = @() + MailNickname = 'M365DSC' + IsAssignableToRole = $true + AssignedToRole = @() + Ensure = 'Present' + } + } + + Mock -CommandName New-MgGroupMemberByRef -MockWith { + } + } + + It 'Should return Values from the Get method' { + Get-TargetResource @testParams + Should -Invoke -CommandName 'Get-MgGroup' -Exactly 1 + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'Get-MgGroup' -Exactly 2 + Should -Invoke -CommandName 'New-MgGroupMemberByRef' -Exactly 1 + #Should -Invoke -CommandName 'Remove-MgGroupMemberDirectoryObjectByRef' -Exactly 1 + } + } + Context -Name "The Group Exists and is assigned to a role but it shouldn't be. Values are NOT in the desired state" -Fixture { BeforeAll { $testParams = @{ From eb9f991b33344fbe09ad87149098e825527a8e11 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 12:50:49 +0000 Subject: [PATCH 45/56] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/intune/IntuneDeviceRemediation.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/docs/resources/intune/IntuneDeviceRemediation.md b/docs/docs/resources/intune/IntuneDeviceRemediation.md index acfe62a44f..f9763f951e 100644 --- a/docs/docs/resources/intune/IntuneDeviceRemediation.md +++ b/docs/docs/resources/intune/IntuneDeviceRemediation.md @@ -9,7 +9,8 @@ | **DetectionScriptParameters** | Write | MSFT_MicrosoftGraphdeviceHealthScriptParameter[] | List of ComplexType DetectionScriptParameters objects. | | | **DeviceHealthScriptType** | Write | String | DeviceHealthScriptType for the script policy. Possible values are: deviceHealthScript, managedInstallerScript. | `deviceHealthScript`, `managedInstallerScript` | | **DisplayName** | Required | String | Name of the device health script | | -| **EnforceSignatureCheck** | Write | Boolean | Indicate whether the script signature needs be checked | | +| **EnforceSignatureCheck** | Write | Boolean | Indicates whether the script signature needs be checked | | +| **IsGlobalScript** | Write | Boolean | Indicates whether the script is a global script provided by Microsoft | | | **Publisher** | Write | String | Name of the device health script publisher | | | **RemediationScriptContent** | Write | String | The entire content of the remediation powershell script | | | **RemediationScriptParameters** | Write | MSFT_MicrosoftGraphdeviceHealthScriptParameter[] | List of ComplexType RemediationScriptParameters objects. | | @@ -80,6 +81,14 @@ Intune Device Remediation +**Important:** Global scripts only allow the update of the following properties: + +* Assignments +* RoleScopeTagIds +* RunAs32Bit +* RunAsAccount + + ## Permissions ### Microsoft Graph From d57b28b589b65df511b1a6c67fe01e158de27e41 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 12:52:52 +0000 Subject: [PATCH 46/56] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index a5466b33ac..b040ce9b63 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -29612,6 +29612,11 @@ "Name": "EnforceSignatureCheck", "Option": "Write" }, + { + "CIMType": "Boolean", + "Name": "IsGlobalScript", + "Option": "Write" + }, { "CIMType": "String", "Name": "Publisher", From a0f7904b6b91d16785b644abed55272700fa51e4 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Wed, 28 Aug 2024 16:19:13 +0200 Subject: [PATCH 47/56] Corrected unit test --- .../Microsoft365DSC.SCAutoSensitivityLabelRule.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCAutoSensitivityLabelRule.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCAutoSensitivityLabelRule.Tests.ps1 index b07241dfe5..1c000eb901 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCAutoSensitivityLabelRule.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCAutoSensitivityLabelRule.Tests.ps1 @@ -329,7 +329,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { ParentPolicyName = 'TestPolicy' ProcessingLimitExceeded = $False ReportSeverityLevel = 'Low' - Workload = 'Exchange' + LogicalWorkload = 'Exchange' ContentContainsSensitiveInformation = @(@{maxconfidence = '100'; id = 'cb353f78-2b72-4c3c-8827-92ebe4f69fdf'; minconfidence = '75'; rulePackId = '00000000-0000-0000-0000-000000000000'; classifiertype = 'Content'; name = 'ABA Routing Number'; mincount = '1'; maxcount = '-1'; }) } } From 7831739a15b70d5a977e79a06f568f8c8c20876a Mon Sep 17 00:00:00 2001 From: Sandro Lanfranchi Date: Wed, 28 Aug 2024 16:26:13 +0200 Subject: [PATCH 48/56] add chengelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f4a243afd..4c12db6f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Change log for Microsoft365DSC # UNRELEASED - +* AADGroup + * FIXES [#4994](https://github.com/microsoft/Microsoft365DSC/issues/4994) * AADAdministrativeUnit * Fix Properties for Dynamic Administrative Units in Graph have moved * AADConditionalAccessPolicy From c207d3819a20f6dfc128c0e6d947a5658a8d4ab1 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 15:09:54 +0000 Subject: [PATCH 49/56] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/azure-ad/AADGroup.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/docs/resources/azure-ad/AADGroup.md b/docs/docs/resources/azure-ad/AADGroup.md index c9a32bcf2e..7eb2ef6775 100644 --- a/docs/docs/resources/azure-ad/AADGroup.md +++ b/docs/docs/resources/azure-ad/AADGroup.md @@ -10,6 +10,7 @@ | **Id** | Write | String | Specifies an ID for the group. | | | **Owners** | Write | StringArray[] | User Service Principal values for the group's owners. | | | **Members** | Write | StringArray[] | User Service Principal values for the group's members. | | +| **GroupAsMembers** | Write | StringArray[] | Displayname values for the groups member of the group. | | | **MemberOf** | Write | StringArray[] | DisplayName values for the groups that this group is a member of. | | | **GroupTypes** | Write | StringArray[] | Specifies that the group is a dynamic group. To create a dynamic group, specify a value of DynamicMembership. | | | **MembershipRule** | Write | String | Specifies the membership rule for a dynamic group. | | @@ -105,6 +106,8 @@ Configuration Example MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("admin@$TenantId", "AdeleV@$TenantId") + GroupAsMembers = @("Group1", "Group2") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" @@ -148,6 +151,8 @@ Configuration Example MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("AdeleV@$TenantId") + GroupAsMembers = @("Group1") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" From 4bf3c00de9c6265a94094537730d26e5bcf2941c Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 15:09:59 +0000 Subject: [PATCH 50/56] Updated {Update} AAD Integration Tests --- .../Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 index 3c148f7c95..2567b8af3a 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 @@ -663,6 +663,8 @@ MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("AdeleV@$TenantId") + GroupAsMembers = @("Group1") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" From 325fe8f50b7de1ddea2fddf16ecefc763fecd10e Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 15:10:07 +0000 Subject: [PATCH 51/56] Updated {Create} AAD Integration Tests --- .../Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 index b4182546dc..961f04f285 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Create.Tests.ps1 @@ -298,6 +298,8 @@ MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("admin@$TenantId", "AdeleV@$TenantId") + GroupAsMembers = @("Group1", "Group2") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" From 3a096bc8d0ec90251f0ed6e4f080932f4a77469a Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 15:10:22 +0000 Subject: [PATCH 52/56] Updated {Update} AAD Integration Tests --- .../Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 index 3c148f7c95..2567b8af3a 100644 --- a/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 +++ b/Tests/Integration/Microsoft365DSC/M365DSCIntegration.AAD.Update.Tests.ps1 @@ -663,6 +663,8 @@ MailEnabled = $True GroupTypes = @("Unified") MailNickname = "M365DSC" + Members = @("AdeleV@$TenantId") + GroupAsMembers = @("Group1") Visibility = "Private" Owners = @("admin@$TenantId", "AdeleV@$TenantId") Ensure = "Present" From 9ec5c52c056f4e7d05bd01c1f192f7b646959799 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 28 Aug 2024 15:11:42 +0000 Subject: [PATCH 53/56] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index b040ce9b63..8c4b298910 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -3517,6 +3517,11 @@ "Name": "Members", "Option": "Write" }, + { + "CIMType": "String[]", + "Name": "GroupAsMembers", + "Option": "Write" + }, { "CIMType": "String[]", "Name": "MemberOf", From 836ffa681e50b73f2fed31126c9ec32482f9f008 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Wed, 28 Aug 2024 22:22:59 +0200 Subject: [PATCH 54/56] Add EXO WMI memory usage troubleshooting entry --- .../user-guide/get-started/troubleshooting.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/docs/user-guide/get-started/troubleshooting.md b/docs/docs/user-guide/get-started/troubleshooting.md index 26e74199e7..f974c666ae 100644 --- a/docs/docs/user-guide/get-started/troubleshooting.md +++ b/docs/docs/user-guide/get-started/troubleshooting.md @@ -20,3 +20,47 @@ This is caused by the fact that the delegated Graph application has not been giv ### RESOLUTION This issue can be resolved by granting and consenting the correct permissions. You can do this via the Azure Admin Portal or by running using the Update-M365DSCAllowedGraphScopes cmdlet. More information about that process can be found here. + + +## Error "The WMI service or the WMI provider returned an unknown error: HRESULT 0x80041033" when running Exchange workload + +### ISSUE + +When you are running a configuration apply or test with many Exchange workload resources, it is possible that the WMI provider throws an error and high memory usage is detected. + +``` +The WS-Management service cannot process the request. The WMI service or the WMI provider returned an unknown error: HRESULT 0x80041033 ++ CategoryInfo : ResourceUnavailable: (root/Microsoft/...gurationManager:String) [], CimException ++ FullyQualifiedErrorId : HRESULT 0x80041033 ++ PSComputerName : localhost +``` + +### CAUSE + +This is caused by the `ExchangeOnlineManagement` PowerShell module consuming more memory than what is available to the wmiprvse.exe process (WMI Provider Host). The default is 4GB of memory on a Windows 11 computer. If those 4GB of memory are not enough, the WMI Provider Host will crash and might restart or not. + +### RESOLUTION + +This issue can be resolved by allowing the WMI Provider Host to allocate more than the default 4GB of memory. + +```powershell +$quotaConfiguration = Get-CimInstance -Namespace Root -ClassName "__ProviderHostQuotaConfiguration" +$quotaConfiguration.MemoryAllHosts = 4 * 4GB # Adjust the memory for all processes combined +$quotaConfiguration.MemoryPerHost = 3 * 4GB # Adjust the memory for a single wmiprvse.exe process +Set-CimInstance -InputObject $quotaConfiguration +``` + +If you want all memory of the computer to be available to the WMI Provider Host, you can do that as well, but a customized amount is most likely better suited: + +```powershell +$computerSystem = Get-CimInstance -ClassName "Win32_ComputerSystem" +$quotaConfiguration.MemoryAllHosts = $computerSystem.TotalPhysicalMemory +$quotaConfiguration.MemoryPerHost = $computerSystem.TotalPhysicalMemory +``` + +Optionally, for improved performance, you can increase the handles and threads per host (wmiprvse.exe process) as well: + +```powershell +$quotaConfiguration.HandlesPerHost = 8192 +$quotaConfiguration.ThreadsPerHost = 512 +``` From b482b54fd46b69009a5f2450b691d4afa825c3fa Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 28 Aug 2024 21:11:05 -0400 Subject: [PATCH 55/56] Release 1.24.828.1 --- CHANGELOG.md | 8 +++++--- Modules/Microsoft365DSC/Dependencies/Manifest.psd1 | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 609db226a7..332ce5de54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,7 @@ # Change log for Microsoft365DSC -# UNRELEASED -* AADGroup - * FIXES [#4994](https://github.com/microsoft/Microsoft365DSC/issues/4994) +# 1.24.828.1 + * AADAdministrativeUnit * Fix Properties for Dynamic Administrative Units in Graph have moved * AADConditionalAccessPolicy @@ -14,6 +13,8 @@ FIXES [#4960](https://github.com/microsoft/Microsoft365DSC/issues/4960) FIXES [#4734](https://github.com/microsoft/Microsoft365DSC/issues/4734) FIXES [#4725](https://github.com/microsoft/Microsoft365DSC/issues/4725) +* AADGroup + * FIXES [#4994](https://github.com/microsoft/Microsoft365DSC/issues/4994) * EXOAuthenticationPolicyAssignment * Removes the 1000 user limit when exporting authentication policy assignments FIXES [#4956](https://github.com/microsoft/Microsoft365DSC/issues/4956) @@ -70,6 +71,7 @@ FIXES [#4983](https://github.com/microsoft/Microsoft365DSC/pull/4983) * DEPENDENCIES * Updated MicrosoftTeams to version 6.5.0. + * Updated MSCloudLoginAssistant to version 1.1.19. # 1.24.731.1 diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index e09af9f836..e3f1d08163 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -90,7 +90,7 @@ }, @{ ModuleName = "MSCloudLoginAssistant" - RequiredVersion = "1.1.18" + RequiredVersion = "1.1.19" }, @{ ModuleName = 'PnP.PowerShell' From 30e872561116c60c5a6463c7c28f6b38f83093fe Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 28 Aug 2024 21:12:07 -0400 Subject: [PATCH 56/56] Update Microsoft365DSC.psd1 --- Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 92 +++++++++++++++----- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index 3cb2e86263..afbbe21dd2 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2024-08-01 +# Generated on: 2024-08-28 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.24.731.1' + ModuleVersion = '1.24.828.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -142,26 +142,76 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = '* AADAuthenticationMethodPolicyFido2 - * Add missing class identifier to schema. - FIXES [#4900](https://github.com/microsoft/Microsoft365DSC/issues/4900) - FIXES [#4079](https://github.com/microsoft/Microsoft365DSC/issues/4079) -* IntuneAntivirusPolicyWindows10SettingCatalog - * Fixes an issue where the template reference is not set correctly. - FIXES [#4925](https://github.com/microsoft/Microsoft365DSC/issues/4925) -* IntuneDeviceConfigurationEndpointProtectionPolicyWindows10 - * Fix compiling if `ProfileTypes` (in `FirewallRules`) is present and contains - more than one value - FIXES [#4936](https://github.com/microsoft/Microsoft365DSC/issues/4936) -* IntuneDeviceConfigurationPolicyiOS - * Fix export of property NetworkUsageRules - FIXES [#4934](https://github.com/microsoft/Microsoft365DSC/issues/4934) + ReleaseNotes = '* AADAdministrativeUnit + * Fix Properties for Dynamic Administrative Units in Graph have moved +* AADConditionalAccessPolicy + * Fixing issue where the resource crashed when trying to retrieve groups + and users from Entra ID which no longer existed + * Fixes an issue where the `AuthenticationFlows` property changed in Graph + and updates on the documentation for the possible values of `TransferMethods`. + FIXES [#4961](https://github.com/microsoft/Microsoft365DSC/issues/4961) + FIXES [#4960](https://github.com/microsoft/Microsoft365DSC/issues/4960) + FIXES [#4734](https://github.com/microsoft/Microsoft365DSC/issues/4734) + FIXES [#4725](https://github.com/microsoft/Microsoft365DSC/issues/4725) +* AADGroup + * FIXES [#4994](https://github.com/microsoft/Microsoft365DSC/issues/4994) +* EXOAuthenticationPolicyAssignment + * Removes the 1000 user limit when exporting authentication policy assignments + FIXES [#4956](https://github.com/microsoft/Microsoft365DSC/issues/4956) +* EXOHostedContentFilterRule + * Dont check if associated `EXOHostedContentFilterPolicy` is present + while removing resource since its not required + * EXORoleGroup + * Fix an issue where roles that have empty members cannot be compared + FIXES [#4977] (https://github.com/microsoft/Microsoft365DSC/issues/4977) +* IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy + * Fixed issue if `PasswordComplexity` was set to 5 by allowing that value + FIXES [#4963](https://github.com/microsoft/Microsoft365DSC/issues/4963) +* IntuneDeviceCompliancePolicyWindows10 + * Fix extraction of property `TpmRequired` +* IntuneDeviceConfigurationCustomPolicyWindows10 + * Change app and delegated permissions for reading to + DeviceManagementConfiguration.ReadWrite.All to cope with + getOmaSettingPlainTextValue which is only working if RW is granted + FIXES [#4412](https://github.com/microsoft/Microsoft365DSC/issues/4412) +* IntuneDeviceRemediation + * Add export of global remediation scripts. +* O365OrgSettings + * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) +* SCAutoSensitivityLabelPolicy + * Fixes issue where Mode=Enabled is not supported for SP and OD. Changing + property to TestWithoutNotifications in those instances. + FIXES [#4990](https://github.com/microsoft/Microsoft365DSC/issues/4990) +* SCAutoSensitivityLabelRule + * Fixes issue where the export was looping through all possible workloads + instead of the actually targeted workload + FIXES [#4989](https://github.com/microsoft/Microsoft365DSC/issues/4989) +* SCSensitivityLabel + * Corrected issue where ExternalAccess properties were configured inverted + FIXES [#3782](https://github.com/microsoft/Microsoft365DSC/issues/3782) +* M365DSCDRGUtil + * Update Intune Settings Catalog Handling. + * Fixes an issue where the `MSFT_IntuneDeviceRemediationPolicyAssignments` + type would trigger an incorrect comparison in `Compare-M365DSCComplexObject`. +* M365DSCResourceGenerator + * Update Intune resource generation for the Settings Catalog. +* M365DSCUtil + * Fix `Compare-PSCustomObjectArrays` by allowing empty arrays as input + FIXES [#4952](https://github.com/microsoft/Microsoft365DSC/issues/4952) +* O365OrgSettings + * FIXES [#4741](https://github.com/microsoft/Microsoft365DSC/issues/4741) * MISC - * M365DSCReport - * Update key properties for delta report in `AADGroup` resource. - FIXES [#4921](https://github.com/microsoft/Microsoft365DSC/issues/4921) - * Improve PowerShell Core support across the DSC resources. - FIXES [#4911](https://github.com/microsoft/Microsoft365DSC/issues/4911)' + * Improve module updates and PowerShell Core support across the DSC + resources. + FIXES [#4941](https://github.com/microsoft/Microsoft365DSC/issues/4941) + * Replace some `Write-Host` occurrences in core engine with + appropriate alternatives. + FIXES [#4943](https://github.com/microsoft/Microsoft365DSC/issues/4943) + * Fixed a typo within M365DSCReport.psm1 related to a .png file + FIXES [#4983](https://github.com/microsoft/Microsoft365DSC/pull/4983) +* DEPENDENCIES + * Updated MicrosoftTeams to version 6.5.0. + * Updated MSCloudLoginAssistant to version 1.1.19.' # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false