From 82bf49a175a5e10d70c39e1eb98eedc322f427aa Mon Sep 17 00:00:00 2001 From: subhashvinjamuri <34547586+subhashvinjamuri@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:25:15 -0500 Subject: [PATCH 01/33] Update MSFT_TeamsAppSetupPolicy.psm1 Fix the issue - https://github.com/microsoft/Microsoft365DSC/issues/5752 --- .../MSFT_TeamsAppSetupPolicy/MSFT_TeamsAppSetupPolicy.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsAppSetupPolicy/MSFT_TeamsAppSetupPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsAppSetupPolicy/MSFT_TeamsAppSetupPolicy.psm1 index e3e7159296..c5a4977019 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsAppSetupPolicy/MSFT_TeamsAppSetupPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsAppSetupPolicy/MSFT_TeamsAppSetupPolicy.psm1 @@ -230,7 +230,7 @@ function Set-TargetResource { foreach ($appInstance in $AppPresetMeetingList) { - $appPresetMeetingValues += [Microsoft.Teams.Policy.Administration.Cmdlets.Core.AppPreset]::New($appInstance) + $appPresetMeetingValues += [Microsoft.Teams.Policy.Administration.Cmdlets.Core.AppPresetMeeting]::New($appInstance) } } @@ -251,7 +251,7 @@ function Set-TargetResource $i = 1 foreach ($appInstance in $PinnedMessageBarApps) { - $pinnedMessageBarAppsValue += [Microsoft.Teams.Policy.Administration.Cmdlets.Core.PinnedApp]::New($appInstance, $i) + $pinnedMessageBarAppsValue += [Microsoft.Teams.Policy.Administration.Cmdlets.Core.PinnedMessageBarApp]::New($appInstance, $i) $i++ } } From 4037951f6430d46756a66ff33a105fd4772850b1 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Wed, 12 Feb 2025 16:26:49 +0100 Subject: [PATCH 02/33] Reduce call count when reconciling object type --- CHANGELOG.md | 5 +++- ...SFT_AADRoleEligibilityScheduleRequest.psm1 | 28 ++++--------------- .../settings.json | 6 ++++ ...ADRoleEligibilityScheduleRequest.Tests.ps1 | 11 +++++++- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84a6c4f592..08ccaed693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,11 @@ * AADGroupEligibilitySchedule * FIXES [#5741] Missing -All variable which prevented enumeration of more than 100 Groups +* AADRoleEligibilityScheduleRequest + * Reduce call count when reconciling object type + FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) -# UNRELEASED +# 1.25.212.1 * AADApplication * Changing the AuthenticationBehaviors parameters to string to allow diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 index 380bd0b92e..c1151299d7 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/MSFT_AADRoleEligibilityScheduleRequest.psm1 @@ -715,33 +715,15 @@ function Export-TargetResource Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline # Find the Principal Type $principalType = 'User' - $userInfo = Get-MgUser -UserId $config.PrincipalId -ErrorAction SilentlyContinue - - if ($null -eq $userInfo) + $userInfo = Get-MgBetaDirectoryObjectById -Ids $config.PrincipalId -ErrorAction SilentlyContinue + $principalType = $userInfo.AdditionalProperties['@odata.type'].Split('.')[2] + $PrincipalValue = if ($principalType -eq 'user' ) { - $principalType = 'Group' - $groupInfo = Get-MgGroup -GroupId $config.PrincipalId -ErrorAction SilentlyContinue - if ($null -eq $groupInfo) - { - $principalType = 'ServicePrincipal' - $spnInfo = Get-MgServicePrincipal -ServicePrincipalId $config.PrincipalId -ErrorAction SilentlyContinue - if ($null -ne $spnInfo) - { - $PrincipalValue = $spnInfo.DisplayName - } - else - { - $PrincipalValue = $null - } - } - else - { - $PrincipalValue = $groupInfo.DisplayName - } + $userInfo.AdditionalProperties['userPrincipalName'] } else { - $PrincipalValue = $userInfo.UserPrincipalName + $userInfo.AdditionalProperties['displayName'] } if ($null -ne $PrincipalValue) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json index 357f40c509..266aff2169 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleEligibilityScheduleRequest/settings.json @@ -15,11 +15,17 @@ "read": [ { "name": "RoleEligibilitySchedule.Read.Directory" + }, + { + "name": "Directory.Read.All" } ], "update": [ { "name": "RoleEligibilitySchedule.ReadWrite.Directory" + }, + { + "name": "Directory.Read.All" } ] } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 index a39b4805ab..03e119af21 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 @@ -46,6 +46,16 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + Mock -CommandName Get-MgBetaDirectoryObjectById -MockWith { + return @{ + Id = '123456' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.user' + userPrincipalName = 'John.Smith@contoso.com' + } + } + } + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleDefinition -MockWith { return @{ DisplayName = 'Teams Communications Administrator' @@ -172,7 +182,6 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Principal = "John.Smith@contoso.com"; RoleDefinition = "Teams Communications Administrator"; ScheduleInfo = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestSchedule -Property @{ - expiration = New-CimInstance -ClassName MSFT_AADRoleEligibilityScheduleRequestScheduleExpiration -Property @{ type = 'afterDateTime' } -ClientOnly From 74d03f598e4190c886eb9a129dbce971ddfe8848 Mon Sep 17 00:00:00 2001 From: subhashvinjamuri <34547586+subhashvinjamuri@users.noreply.github.com> Date: Wed, 12 Feb 2025 13:54:33 -0500 Subject: [PATCH 03/33] corrected Typecasting in TeamsAppPermissionPolicy TeamsAppPermissionPolicy (set-Target ) : corrected Typecasting for AppPresetMeeting, PinnedMessageBarApps --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c0572625..491390c304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ * EXOSmtpDaneInbound * Updated authentication properties to align with MOF definition. FIXES [#5709](https://github.com/microsoft/Microsoft365DSC/issues/5709) +* TeamsAppPermissionPolicy + * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps before adding them to the policy + FIXES [[#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) + * MISC * PowerPlatform resource revamp to use direct REST API calls. * Simplify export behavior for all resources and complex objects. From 6919b995e14beb743e71c74f01dc74f1becc0c30 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Wed, 12 Feb 2025 17:01:50 +0100 Subject: [PATCH 04/33] Add stub to tests --- ...ADRoleEligibilityScheduleRequest.Tests.ps1 | 4 +- Tests/Unit/Stubs/Microsoft365.psm1 | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 index 03e119af21..c67519aa7f 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADRoleEligibilityScheduleRequest.Tests.ps1 @@ -101,8 +101,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleRequest -MockWith { return $null } - - + Mock -CommandName Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -MockWith { return $null } @@ -309,6 +308,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } } + It 'Should Reverse Engineer resource from the Export method' { $result = Export-TargetResource @testParams $result | Should -Not -BeNullOrEmpty diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index fb456ea356..94492080d2 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -106175,3 +106175,41 @@ function Set-RetentionPolicyTag $Name ) } + +function Get-MgBetaDirectoryObjectById +{ + [CmdletBinding()] + param( + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [System.String[]] + $Ids, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.String[]] + $Types, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $WhatIf + ) +} From dc1c7e02af9eb88c9ba0bd85ea1ef215eb7aa707 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 13 Feb 2025 14:40:22 +0100 Subject: [PATCH 05/33] Fix credential export and indentation in export --- CHANGELOG.md | 5 ++ .../Modules/M365DSCDRGUtil.psm1 | 30 +++-------- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 52 ++----------------- 3 files changed, 16 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c0572625..56d05f4626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* M365DSCUtil + * Fixes an issue with `Credential` property being escaped and indentation. + # 1.25.212.1 * AADApplication diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index fdeec8809f..7b55351fba 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -292,8 +292,9 @@ function Get-M365DSCDRGComplexTypeToString { $currentProperty = @() $IndentLevel++ - foreach ($item in $ComplexObject) + for($i = 0; $i -lt $ComplexObject.Count; $i++) { + $item = $ComplexObject[$i] $splat = @{ 'ComplexObject' = $item 'CIMInstanceName' = $CIMInstanceName @@ -370,7 +371,6 @@ function Get-M365DSCDRGComplexTypeToString { $hashPropertyType = ([Array]($ComplexTypeMapping | Where-Object -FilterScript { $_.Name -eq $key }).CimInstanceName)[0] $hashProperty = $itemValue - #$currentProperty += "`r`n" } else { @@ -387,7 +387,7 @@ function Get-M365DSCDRGComplexTypeToString if ($ComplexObject.$key.Count -gt 0) { $currentProperty += $indent + $key + ' = ' - $currentProperty += '@(' + $currentProperty += "@(" } } @@ -413,11 +413,13 @@ function Get-M365DSCDRGComplexTypeToString } if ($i -ne 0) { - # Remove the line break at the start because every item contains a trailing line break - # which would lead to two line breaks between each item $nestedPropertyString = $nestedPropertyString.Substring(2) } $currentProperty += $nestedPropertyString + if (-not $currentProperty.EndsWith("`r`n")) + { + $currentProperty += "`r`n" + } } $IndentLevel-- } @@ -483,28 +485,12 @@ function Get-M365DSCDRGComplexTypeToString $indent = '' $indent = ' ' * ($IndentLevel -1) - if ($key -in $ComplexTypeMapping.Name) + if ($key -in $ComplexTypeMapping.Name -and -not $currentProperty.EndsWith("`r`n")) { $currentProperty += "`r`n" } $currentProperty += "$indent}" - <# - if ($IsArray -or $IndentLevel -gt 4) - { - $currentProperty += "`r`n" - } - #> - - #Indenting last parenthesis when the cim instance is an array - <# - if ($IndentLevel -eq 5) - { - $indent = ' ' * ($IndentLevel -2) - $currentProperty += $indent - } - #> - $emptyCIM = $currentProperty.Replace(' ', '').Replace("`r`n", '') if ($emptyCIM -eq "MSFT_$CIMInstanceName{}") { diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index f329c58844..42a7cdc4e1 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -3603,6 +3603,7 @@ function Update-M365DSCExportAuthenticationResults if ($ConnectionMode -eq 'Credentials') { $Results.Credential = Resolve-Credentials -UserName 'credential' + $noEscape += 'Credential' if ($Results.ContainsKey('ApplicationId')) { $Results.Remove('ApplicationId') | Out-Null @@ -3631,6 +3632,7 @@ function Update-M365DSCExportAuthenticationResults elseif ($ConnectionMode -eq 'CredentialsWithTenantId') { $Results.Credential = Resolve-Credentials -UserName 'credential' + $noEscape += 'Credential' if ($Results.ContainsKey('ApplicationId')) { $Results.Remove('ApplicationId') | Out-Null @@ -3661,6 +3663,7 @@ function Update-M365DSCExportAuthenticationResults elseif ($Results.ContainsKey('Credential') -and $ConnectionMode -eq 'CredentialsWithApplicationId') { $Results.Credential = Resolve-Credentials -UserName 'credential' + $noEscape += 'Credential' } if (-not [System.String]::IsNullOrEmpty($Results.ApplicationId)) { @@ -3950,55 +3953,6 @@ function Get-M365DSCExportContentForResource [void]$content.Append(" $ResourceName `"$instanceName`"`r`n") [void]$content.Append(" {`r`n") $partialContent = Get-DSCBlock -Params $Results -ModulePath $ModulePath -NoEscape $NoEscape - # Test for both Credentials and CredentialsWithApplicationId - if ($ConnectionMode -match 'Credentials') - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'Credential' - if (![System.String]::IsNullOrEmpty($Results.ApplicationId)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'ApplicationId' - } - } - else - { - if (![System.String]::IsNullOrEmpty($Results.ApplicationId)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'ApplicationId' - } - if (![System.String]::IsNullOrEmpty($Results.TenantId)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'TenantId' - } - if (![System.String]::IsNullOrEmpty($Results.ApplicationSecret)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'ApplicationSecret' - } - if (![System.String]::IsNullOrEmpty($Results.CertificatePath)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'CertificatePath' - } - if (![System.String]::IsNullOrEmpty($Results.CertificateThumbprint)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'CertificateThumbprint' - } - if (![System.String]::IsNullOrEmpty($Results.CertificatePassword)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'CertificatePassword' - } - if (![System.String]::IsNullOrEmpty($Results.AccessTokens)) - { - $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` - -ParameterName 'AccessTokens' - } - } if ($partialContent.ToLower().IndexOf($OrganizationName.ToLower()) -gt 0) { From 6bd7885e660e80011e39d9adf883aaccb21f0750 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 13 Feb 2025 17:20:27 +0100 Subject: [PATCH 06/33] Allow variables in strings and no authentication results update --- CHANGELOG.md | 2 ++ .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 23 ++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d05f4626..f4d52c2e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * M365DSCUtil * Fixes an issue with `Credential` property being escaped and indentation. + * Adds the possibility to allow variables in strings and no authentication + results update during conversion to final export. # 1.25.212.1 diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index 42a7cdc4e1..f637d76470 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -3810,13 +3810,24 @@ function Get-M365DSCExportContentForResource [Parameter()] [System.String[]] - $NoEscape + $NoEscape, + + [Parameter()] + [switch] + $SkipAuthenticationUpdate, + + [Parameter()] + [switch] + $AllowVariablesInStrings ) - $withoutAuthentication = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` - -Results $Results - $Results = $withoutAuthentication.Results - $NoEscape += $withoutAuthentication.NoEscape + if (-not $SkipAuthenticationUpdate) + { + $withoutAuthentication = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $Results = $withoutAuthentication.Results + $NoEscape += $withoutAuthentication.NoEscape + } $NoEscape = $NoEscape | Select-Object -Unique $OrganizationName = '' @@ -3952,7 +3963,7 @@ function Get-M365DSCExportContentForResource $content = [System.Text.StringBuilder]::New() [void]$content.Append(" $ResourceName `"$instanceName`"`r`n") [void]$content.Append(" {`r`n") - $partialContent = Get-DSCBlock -Params $Results -ModulePath $ModulePath -NoEscape $NoEscape + $partialContent = Get-DSCBlock -Params $Results -ModulePath $ModulePath -NoEscape $NoEscape -AllowVariablesInStrings:$AllowVariablesInStrings if ($partialContent.ToLower().IndexOf($OrganizationName.ToLower()) -gt 0) { From b9e003d8b6304d55f4eb719be3962850c0e1685f Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 13 Feb 2025 23:20:43 +0100 Subject: [PATCH 07/33] Add prefix to Remove-EmptyValue command --- CHANGELOG.md | 6 +++++ .../MSFT_EXOOrganizationRelationship.psm1 | 4 ++-- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 14 ++++++------ .../Microsoft365DSC.Utils.Tests.ps1 | 22 +++++++++---------- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c6cd4a666..d76833e416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* M365DSCUtil + * Add M365DSC prefix to `Remove-EmptyValue`. + FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) + # 1.25.212.2 * MISC diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOOrganizationRelationship/MSFT_EXOOrganizationRelationship.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOOrganizationRelationship/MSFT_EXOOrganizationRelationship.psm1 index e925c86fad..def8db43df 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOOrganizationRelationship/MSFT_EXOOrganizationRelationship.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOOrganizationRelationship/MSFT_EXOOrganizationRelationship.psm1 @@ -427,7 +427,7 @@ function Set-TargetResource Confirm = $false } # Removes empty properties from Splat to prevent function throwing errors if parameter is null or empty - Remove-EmptyValue -Splat $NewOrganizationRelationshipParams + Remove-M365DSCEmptyValue -Splat $NewOrganizationRelationshipParams $SetOrganizationRelationshipParams = @{ ArchiveAccessEnabled = $ArchiveAccessEnabled @@ -454,7 +454,7 @@ function Set-TargetResource Confirm = $false } # Removes empty properties from Splat to prevent function throwing errors if parameter is null or empty - Remove-EmptyValue -Splat $SetOrganizationRelationshipParams + Remove-M365DSCEmptyValue -Splat $SetOrganizationRelationshipParams # CASE: Organization Relationship doesn't exist but should; if ($Ensure -eq 'Present' -and $currentOrgRelationshipConfig.Ensure -eq 'Absent') diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index f329c58844..f1be1bf530 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -3516,13 +3516,13 @@ This function removes all empty values from a dictionary object .Functionality Internal #> -function Remove-EmptyValue +function Remove-M365DSCEmptyValue { - [alias('Remove-EmptyValues')] + [Alias('Remove-M365DSCEmptyValues')] [CmdletBinding()] param ( - [alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable, + [Alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable, [string[]] $ExcludeParameter, [switch] $Recursive, [int] $Rerun @@ -3542,7 +3542,7 @@ function Remove-EmptyValue } else { - Remove-EmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive + Remove-M365DSCEmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive } } else @@ -3566,7 +3566,7 @@ function Remove-EmptyValue { for ($i = 0; $i -lt $Rerun; $i++) { - Remove-EmptyValue -Hashtable $Hashtable -Recursive:$Recursive + Remove-M365DSCEmptyValue -Hashtable $Hashtable -Recursive:$Recursive } } } @@ -3764,7 +3764,7 @@ function Update-M365DSCExportAuthenticationResults $noEscape += 'AccessTokens' } } - + return @{ Results = $Results NoEscape = $noEscape @@ -5288,7 +5288,7 @@ Export-ModuleMember -Function @( 'New-M365DSCCmdletDocumentation', 'New-M365DSCConnection', 'New-M365DSCMissingResourcesExample', - 'Remove-EmptyValue', + 'Remove-M365DSCEmptyValue', 'Remove-M365DSCAuthenticationParameter', 'Remove-NullEntriesFromHashtable', 'Set-EXOSafeAttachmentRule', diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.Utils.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.Utils.Tests.ps1 index 04d475d653..0c90ce2529 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.Utils.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.Utils.Tests.ps1 @@ -21,7 +21,7 @@ Test6 = 6 } - Remove-EmptyValue -Splat $Splat + Remove-M365DSCEmptyValue -Splat $Splat { Test-FunctionHashtable @Splat } | Should -Not -Throw } It 'From OrderedDictionary' { @@ -44,7 +44,7 @@ Test5 = 0 Test6 = 6 } - Remove-EmptyValue -Splat $SplatDictionary + Remove-M365DSCEmptyValue -Splat $SplatDictionary { Test-FunctionOrderedDictionary @SplatDictionary } | Should -Not -Throw } It 'From OrderedDictionary but with ExcludedProperty' { @@ -56,7 +56,7 @@ Test5 = 0 Test6 = 6 } - Remove-EmptyValue -Splat $SplatDictionary -ExcludeParameter 'Test3' + Remove-M365DSCEmptyValue -Splat $SplatDictionary -ExcludeParameter 'Test3' $SplatDictionary['Test3'] | Should -Be '' } It 'From OrderedDictionary Recursive' { @@ -69,10 +69,10 @@ Test6 = 6 Test7 = @{} } - Remove-EmptyValue -Splat $SplatDictionary + Remove-M365DSCEmptyValue -Splat $SplatDictionary $SplatDictionary.Keys | Should -Contain 'Test7' - Remove-EmptyValue -Splat $SplatDictionary -Recursive + Remove-M365DSCEmptyValue -Splat $SplatDictionary -Recursive $SplatDictionary.Keys | Should -Not -Contain 'Test7' } It 'From OrderedDictionary Recursive with ILIST check' { @@ -91,11 +91,11 @@ } $SplatDictionary.Test6.Add($DummyObject) - Remove-EmptyValue -Splat $SplatDictionary + Remove-M365DSCEmptyValue -Splat $SplatDictionary $SplatDictionary.Keys | Should -Contain 'Test6' $SplatDictionary.Keys | Should -Contain 'Test7' - Remove-EmptyValue -Splat $SplatDictionary -Recursive + Remove-M365DSCEmptyValue -Splat $SplatDictionary -Recursive $SplatDictionary.Keys | Should -Not -Contain 'Test7' } It 'From OrderedDictionary Recursive with ILIST check for Empty Arrays' { @@ -117,14 +117,14 @@ } $SplatDictionary.Test6.Add($DummyObject) - Remove-EmptyValue -Splat $SplatDictionary + Remove-M365DSCEmptyValue -Splat $SplatDictionary $SplatDictionary.Keys | Should -Contain 'Test6' $SplatDictionary.Keys | Should -Contain 'Test7' $SplatDictionary.Keys | Should -Not -Contain 'Test8' $SplatDictionary.Keys | Should -Not -Contain 'Test9' $SplatDictionary.Keys | Should -Contain 'Test10' - Remove-EmptyValue -Splat $SplatDictionary -Recursive + Remove-M365DSCEmptyValue -Splat $SplatDictionary -Recursive $SplatDictionary.Keys | Should -Not -Contain 'Test7' } It 'Testing edge cases' { @@ -151,7 +151,7 @@ Rotate6 = $null, '' } - Remove-EmptyValue -Hashtable $Splat + Remove-M365DSCEmptyValue -Hashtable $Splat $Splat.Keys | Should -Contain 'Rotate6' $Splat.Keys | Should -Not -Contain 'Rotate5' $Splat.Keys | Should -Contain 'Rotate4' @@ -168,7 +168,7 @@ $Splat.Margins.Keys | Should -Contain TestBool2 $Splat.Margins.Keys | Should -Contain TestBoolArray - Remove-EmptyValue -Hashtable $Splat -Recursive + Remove-M365DSCEmptyValue -Hashtable $Splat -Recursive $Splat.Margins.Keys | Should -Not -Contain MarginRight2 } } From 7bc4f373061228773a276b8e01a07eb34848f2e3 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Fri, 14 Feb 2025 13:32:26 +0000 Subject: [PATCH 08/33] Updated Resources and Cmdlet documentation pages --- .../resources/azure-ad/AADRoleEligibilityScheduleRequest.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md b/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md index bfb455071a..f43e0b94a7 100644 --- a/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md +++ b/docs/docs/resources/azure-ad/AADRoleEligibilityScheduleRequest.md @@ -103,11 +103,11 @@ To authenticate with the Microsoft Graph API, this resource required the followi - **Read** - - RoleEligibilitySchedule.Read.Directory + - RoleEligibilitySchedule.Read.Directory, Directory.Read.All - **Update** - - RoleEligibilitySchedule.ReadWrite.Directory + - RoleEligibilitySchedule.ReadWrite.Directory, Directory.Read.All ## Examples From 4322d969a719e9d17fee4d3ee7be9993c858db5b Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 14 Feb 2025 10:16:41 -0500 Subject: [PATCH 09/33] ADOSecurityPolicy - Fix Default Value Parsing --- CHANGELOG.md | 3 ++ .../MSFT_ADOSecurityPolicy.psm1 | 32 +++++++++++++++++++ .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 1 + 3 files changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4142ce7d52..2f9adfcd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * AADRoleEligibilityScheduleRequest * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) +* ADOSecurityPolicy + * Fixes an issues where the resource threw an error trying to parse the default + values. * M365DSCUtil * Add M365DSC prefix to `Remove-EmptyValue`. FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 index ab8e0e9e11..f6647166f1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_ADOSecurityPolicy/MSFT_ADOSecurityPolicy.psm1 @@ -91,27 +91,59 @@ function Get-TargetResource $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.DisallowOAuthAuthentication?defaultValue" $DisallowOAuthAuthenticationValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($DisallowOAuthAuthenticationValue)) + { + $DisallowOAuthAuthenticationValue = $true + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.DisallowSecureShell?defaultValue" $DisallowSecureShellValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($DisallowSecureShellValue)) + { + $DisallowSecureShellValue = $false + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.LogAuditEvents?defaultValue" $LogAuditEventsValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($LogAuditEventsValue)) + { + $LogAuditEventsValue = $false + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.AllowAnonymousAccess?defaultValue" $AllowAnonymousAccessValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($AllowAnonymousAccessValue)) + { + $AllowAnonymousAccessValue = $false + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.ArtifactsExternalPackageProtectionToken?defaultValue" $ArtifactsExternalPackageProtectionTokenValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($ArtifactsExternalPackageProtectionTokenValue)) + { + $ArtifactsExternalPackageProtectionTokenValue = $true + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.EnforceAADConditionalAccess?defaultValue" $EnforceAADConditionalAccessValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($EnforceAADConditionalAccessValue)) + { + $EnforceAADConditionalAccessValue = $false + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.AllowTeamAdminsInvitationsAccessToken?defaultValue" $AllowTeamAdminsInvitationsAccessTokenValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($AllowTeamAdminsInvitationsAccessTokenValue)) + { + $AllowTeamAdminsInvitationsAccessTokenValue = $true + } $uri = "https://dev.azure.com/$($OrganizationName)/_apis/OrganizationPolicy/Policies/Policy.AllowRequestAccessToken?defaultValue" $AllowRequestAccessTokenValue = (Invoke-M365DSCAzureDevOPSWebRequest -Uri $uri).Value + if ([System.String]::IsNullOrEmpty($AllowRequestAccessTokenValue)) + { + $AllowRequestAccessTokenValue = $true + } $results = @{ OrganizationName = $OrganizationName diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index f1be1bf530..67f290711e 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -3960,6 +3960,7 @@ function Get-M365DSCExportContentForResource $partialContent = Convert-DSCStringParamToVariable -DSCBlock $partialContent ` -ParameterName 'ApplicationId' } + $partialContent = $partialContent.Replace('`$Credscredential;', '$Credscredential;') } else { From 52add86948810c85c0d2e7c4ccec5fe65ed09430 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 14 Feb 2025 10:17:21 -0500 Subject: [PATCH 10/33] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f9adfcd3f..6c80344499 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) * ADOSecurityPolicy - * Fixes an issues where the resource threw an error trying to parse the default + * Fixes an issue where the resource threw an error trying to parse the default values. * M365DSCUtil * Add M365DSC prefix to `Remove-EmptyValue`. From 56d0359713036727be612beeeef182e10b3a041a Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 14 Feb 2025 23:44:36 +0100 Subject: [PATCH 11/33] Remove ensure property from export --- CHANGELOG.md | 5 ++++- .../DSCResources/MSFT_TeamsM365App/MSFT_TeamsM365App.psm1 | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4142ce7d52..a80f2c0306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,10 @@ FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) * TeamsAppPermissionPolicy * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps before adding them to the policy - FIXES [[#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) + FIXES [#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) +* TeamsM365App + * Remove `Ensure` property from being exported. + FIXES [#5781](https://github.com/microsoft/Microsoft365DSC/issues/5781) # 1.25.212.2 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsM365App/MSFT_TeamsM365App.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsM365App/MSFT_TeamsM365App.psm1 index ce787cc6a5..77d84fc9ae 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsM365App/MSFT_TeamsM365App.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsM365App/MSFT_TeamsM365App.psm1 @@ -69,7 +69,6 @@ function Get-TargetResource #endregion $nullResult = $PSBoundParameters - $nullResult.Ensure = 'Absent' try { if ($null -ne $Script:exportedInstances -and $Script:ExportMode) @@ -112,7 +111,6 @@ function Get-TargetResource AssignmentType = $instance.AvailableTo.AssignmentType Users = $usersValue Groups = $groupsValue - Ensure = 'Present' Credential = $Credential ApplicationId = $ApplicationId TenantId = $TenantId @@ -199,7 +197,6 @@ function Set-TargetResource $currentInstance = Get-TargetResource @PSBoundParameters - $PSBoundParameters.Remove('Ensure') | Out-Null $PSBoundParameters.Remove('Credential') | Out-Null $PSBoundParameters.Remove('ApplicationId') | Out-Null $PSBoundParameters.Remove('ApplicationSecret') | Out-Null From 77bd1ec48c91e3d413ba04d0cf4c7535df07cd95 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 17 Feb 2025 08:08:08 -0500 Subject: [PATCH 12/33] Various Fixes --- CHANGELOG.md | 4 +++ .../MSFT_SCSensitivityLabel.psm1 | 30 ++++++++++++------- .../MSFT_SCSensitivityLabel.schema.mof | 2 +- .../Dependencies/Manifest.psd1 | 2 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c80344499..e1f0784d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,13 @@ * M365DSCUtil * Add M365DSC prefix to `Remove-EmptyValue`. FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) +* SCSensitivityLabel + * Fixes invalid accepted content type values. * TeamsAppPermissionPolicy * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps before adding them to the policy FIXES [[#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) +* DEPENDENCIES + * Updated ReverseDSC to version 2.0.0.26 # 1.25.212.2 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 index a6e6ce5f13..9820891230 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.psm1 @@ -194,7 +194,7 @@ function Get-TargetResource $ApplyWaterMarkingText, [Parameter()] - [ValidateSet('File, Email', 'Site, UnifiedGroup', 'PurviewAssets', 'Teamwork', 'SchematizedData')] + [ValidateSet('File', 'Email', 'Site', 'UnifiedGroup', 'PurviewAssets', 'Teamwork', 'SchematizedData')] [System.String[]] $ContentType, @@ -401,14 +401,6 @@ function Get-TargetResource $currentContentType = @() switch -Regex ($label.ContentType) { - 'File, Email' - { - $currentContentType += 'File, Email' - } - 'Site, UnifiedGroup' - { - $currentContentType += 'Site, UnifiedGroup' - } 'PurviewAssets' { $currentContentType += 'PurviewAssets' @@ -421,6 +413,22 @@ function Get-TargetResource { $currentContentType += 'SchematizedData' } + 'File' + { + $currentContentType += 'File' + } + 'Email' + { + $currentContentType += 'Email' + } + 'Site' + { + $currentContentType += 'Site' + } + 'UnifiedGroup' + { + $currentContentType += 'UnifiedGroup' + } } # Encryption @@ -809,7 +817,7 @@ function Set-TargetResource $ApplyWaterMarkingText, [Parameter()] - [ValidateSet('File, Email', 'Site, UnifiedGroup', 'PurviewAssets', 'Teamwork', 'SchematizedData')] + [ValidateSet('File', 'Email', 'Site', 'UnifiedGroup', 'PurviewAssets', 'Teamwork', 'SchematizedData')] [System.String[]] $ContentType, @@ -1348,7 +1356,7 @@ function Test-TargetResource $ApplyWaterMarkingText, [Parameter()] - [ValidateSet('File, Email', 'Site, UnifiedGroup', 'PurviewAssets', 'Teamwork', 'SchematizedData')] + [ValidateSet('File', 'Email', 'Site', 'UnifiedGroup', 'PurviewAssets', 'Teamwork', 'SchematizedData')] [System.String[]] $ContentType, diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.schema.mof index 4653fd23be..e0590ee87c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCSensitivityLabel/MSFT_SCSensitivityLabel.schema.mof @@ -70,7 +70,7 @@ class MSFT_SCSensitivityLabel : OMI_BaseResource [Write, Description("The ApplyWaterMarkingFontSize parameter specifies the font size (in points) of the watermark text.")] SInt32 ApplyWaterMarkingFontSize; [Write, Description("The ApplyWaterMarkingAlignment parameter specifies the watermark alignment."), ValueMap{"Horizontal","Diagonal"}, Values{"Horizontal","Diagonal"}] String ApplyWaterMarkingLayout; [Write, Description("The ApplyWaterMarkingText parameter specifies the watermark text. If the value contains spaces, enclose the value in quotation marks.")] String ApplyWaterMarkingText; - [Write, Description("The ContentType parameter specifies where the sensitivity label can be applied."), ValueMap{"File, Email","Site, UnifiedGroup","PurviewAssets","Teamwork","SchematizedData"}, Values{"File, Email","Site, UnifiedGroup","PurviewAssets","Teamwork","SchematizedData"}] String ContentType[]; + [Write, Description("The ContentType parameter specifies where the sensitivity label can be applied."), ValueMap{"File", "Email","Site", "UnifiedGroup","PurviewAssets","Teamwork","SchematizedData"}, Values{"File", "Email","Site", "UnifiedGroup","PurviewAssets","Teamwork","SchematizedData"}] String ContentType[]; [Write, Description("The EncryptionContentExpiredOnDateInDaysOrNever parameter specifies when the encrypted content expires. Valid values are integer or never.")] String EncryptionContentExpiredOnDateInDaysOrNever; [Write, Description("The EncryptionDoNotForward parameter specifies whether the Do Not Forward template is applied.")] Boolean EncryptionDoNotForward; [Write, Description("The EncryptionEncryptOnly parameter specifies whether the encrypt-only template is applied.")] Boolean EncryptionEncryptOnly; diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index 9ed829c60a..9c367a9226 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -134,7 +134,7 @@ }, @{ ModuleName = 'ReverseDSC' - RequiredVersion = '2.0.0.25' + RequiredVersion = '2.0.0.26' } ) } From 9ac6b061d6a51c719007741390dad5ae6d60f19a Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 17 Feb 2025 08:22:17 -0500 Subject: [PATCH 13/33] Update --- CHANGELOG.md | 2 +- Modules/Microsoft365DSC/Dependencies/Manifest.psd1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1f0784d73..ebac57c83e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps before adding them to the policy FIXES [[#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) * DEPENDENCIES - * Updated ReverseDSC to version 2.0.0.26 + * Updated ReverseDSC to version 2.0.0.27 # 1.25.212.2 diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index 9c367a9226..10e2ddc694 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -134,7 +134,7 @@ }, @{ ModuleName = 'ReverseDSC' - RequiredVersion = '2.0.0.26' + RequiredVersion = '2.0.0.27' } ) } From 8f0b3a5fa3af1bb263dc81b629b5fe122a03a393 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Mon, 17 Feb 2025 14:00:00 +0000 Subject: [PATCH 14/33] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/security-compliance/SCSensitivityLabel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/security-compliance/SCSensitivityLabel.md b/docs/docs/resources/security-compliance/SCSensitivityLabel.md index 6d2c1e8fe0..642c9b9ba7 100644 --- a/docs/docs/resources/security-compliance/SCSensitivityLabel.md +++ b/docs/docs/resources/security-compliance/SCSensitivityLabel.md @@ -30,7 +30,7 @@ | **ApplyWaterMarkingFontSize** | Write | SInt32 | The ApplyWaterMarkingFontSize parameter specifies the font size (in points) of the watermark text. | | | **ApplyWaterMarkingLayout** | Write | String | The ApplyWaterMarkingAlignment parameter specifies the watermark alignment. | `Horizontal`, `Diagonal` | | **ApplyWaterMarkingText** | Write | String | The ApplyWaterMarkingText parameter specifies the watermark text. If the value contains spaces, enclose the value in quotation marks. | | -| **ContentType** | Write | StringArray[] | The ContentType parameter specifies where the sensitivity label can be applied. | `File, Email`, `Site, UnifiedGroup`, `PurviewAssets`, `Teamwork`, `SchematizedData` | +| **ContentType** | Write | StringArray[] | The ContentType parameter specifies where the sensitivity label can be applied. | `File`, `Email`, `Site`, `UnifiedGroup`, `PurviewAssets`, `Teamwork`, `SchematizedData` | | **EncryptionContentExpiredOnDateInDaysOrNever** | Write | String | The EncryptionContentExpiredOnDateInDaysOrNever parameter specifies when the encrypted content expires. Valid values are integer or never. | | | **EncryptionDoNotForward** | Write | Boolean | The EncryptionDoNotForward parameter specifies whether the Do Not Forward template is applied. | | | **EncryptionEncryptOnly** | Write | Boolean | The EncryptionEncryptOnly parameter specifies whether the encrypt-only template is applied. | | From 23c4c2e06c67ece36051dbe8b947926b09245264 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 17 Feb 2025 15:28:14 -0500 Subject: [PATCH 15/33] Update MSFT_EXORoleGroup.psm1 --- .../DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 index 55ac6c9624..587ab48e42 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 @@ -102,7 +102,7 @@ function Get-TargetResource $result = @{ Name = $RoleGroup.Name Description = $RoleGroup.Description - Members = $roleGroupMember.DisplayName + Members = $roleGroupMember.PrimarySmtpAddress Roles = $RoleGroup.Roles Ensure = 'Present' Credential = $Credential From bb134d80e9fa084ee40b4d9f2f87c7413ef031b7 Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 15:21:31 -0800 Subject: [PATCH 16/33] Fix issue prevent export of AADGroupEligibilitySchedule and detection of PrincipalType --- CHANGELOG.md | 3 ++ .../MSFT_AADGroupEligibilitySchedule.psm1 | 33 +++++++++++++------ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..ad5ee173bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,9 @@ * TeamsM365App * Remove `Ensure` property from being exported. FIXES [#5781](https://github.com/microsoft/Microsoft365DSC/issues/5781) +* AADGroupEligibilitySchedule + * FIXES [#5792](https://github.com/microsoft/Microsoft365DSC/issues/5792) issue where complete DSC isn't exported after generated + * FIXES [#5793](https://github.com/microsoft/Microsoft365DSC/issues/5793) issue where PrincipalType isn't correctly captured in AzureGov * DEPENDENCIES * Updated ReverseDSC to version 2.0.0.27 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroupEligibilitySchedule/MSFT_AADGroupEligibilitySchedule.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroupEligibilitySchedule/MSFT_AADGroupEligibilitySchedule.psm1 index a81083fccd..986d9440f0 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroupEligibilitySchedule/MSFT_AADGroupEligibilitySchedule.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroupEligibilitySchedule/MSFT_AADGroupEligibilitySchedule.psm1 @@ -217,17 +217,27 @@ function Get-TargetResource } #endregion - switch ($getValue.PrincipalType) + if ([string]::IsNullOrEmpty($getValue.PrincipalType)) { - 'group' { - $PrincipalDisplayName = (Get-MgGroup -GroupId $getvalue.PrincipalId).DisplayName - } - 'user' { - $PrincipalDisplayName = (Get-MgUser -UserId $getvalue.PrincipalId).DisplayName - } + $getValue.PrincipalType = "unknown" } - $GroupDisplayName = (Get-MgGroup -GroupId $getvalue.GroupId).DisplayName + switch ($getValue.PrincipalType) + { + 'group' { + $PrincipalDisplayName = (Get-MgGroup -GroupId $getvalue.PrincipalId).DisplayName + } + 'user' { + $PrincipalDisplayName = (Get-MgUser -UserId $getvalue.PrincipalId).DisplayName + } + 'unknown' { + $objectInfo = Get-MgBetaDirectoryObjectById -Ids $getvalue.PrincipalId -ErrorAction SilentlyContinue + $getValue.PrincipalType = $objectInfo.AdditionalProperties['@odata.type'].Split('.')[2] + $PrincipalDisplayName = $objectInfo.AdditionalProperties['displayName'] + } + } + + $GroupDisplayName = (Get-MgGroup -GroupId $getvalue.GroupId).DisplayName $results = @{ #region resource generator code @@ -235,7 +245,7 @@ function Get-TargetResource GroupId = $getValue.groupId GroupDisplayName = $GroupDisplayName MemberType = $enumMemberType - PrincipalType = $PrincipalType + PrincipalType = $getValue.PrincipalType PrincipalDisplayname = $PrincipalDisplayName ScheduleInfo = $complexScheduleInfo Id = $getValue.Id @@ -794,6 +804,9 @@ function Export-TargetResource { Write-Host "`r`n" -NoNewline } + + $dscContent = '' + foreach ($group in $groups) { Write-Host " |---[$j/$($groups.Count)] $($group.DisplayName)" -NoNewline @@ -804,7 +817,7 @@ function Export-TargetResource -ErrorAction SilentlyContinue $i = 1 - $dscContent = '' + if ($getValue.Length -eq 0) { Write-Host $Global:M365DSCEmojiGreenCheckMark From 5f4f64700c5c3692a1bfd9cc0a0690e36407020a Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 15:37:41 -0800 Subject: [PATCH 17/33] Add exception handling for delegatedPermissionClassifications with Managed Identities --- CHANGELOG.md | 2 ++ .../MSFT_AADServicePrincipal.psm1 | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..5d5a9fabfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ * ADOSecurityPolicy * Fixes an issue where the resource threw an error trying to parse the default values. +* AADServicePrincipal + * FIXES [#5359](https://github.com/microsoft/Microsoft365DSC/issues/5359) AADServicePrincipal fails on Managed Identities when DelegatedPermissions returns 500 response * M365DSCUtil * Add M365DSC prefix to `Remove-EmptyValue`. * Fixes an issue with `Credential` property being escaped and indentation. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 index f8da43f8ad..ed0174a5dd 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 @@ -230,8 +230,17 @@ function Get-TargetResource } [Array]$complexDelegatedPermissionClassifications = @() - $Uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + "v1.0/servicePrincipals/$($AADServicePrincipal.Id)/delegatedPermissionClassifications" - $permissionClassifications = Invoke-MgGraphRequest -Uri $Uri -Method Get + #Managed Identities in AzureGov return exception when pulling delegatedPermissionClassifications + try + { + $Uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + "v1.0/servicePrincipals/$($AADServicePrincipal.Id)/delegatedPermissionClassifications" + $permissionClassifications = Invoke-MgGraphRequest -Uri $Uri -Method Get + } + catch + { + Write-Verbose -Message "Service Principal didn't return delegated permission classifications. Expected for Managedidentities." + } + foreach ($permissionClassification in $permissionClassifications.Value) { $hashtable = @{ From fbccb0641194381e4bf80d79a48a409cbd9b520d Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 15:44:05 -0800 Subject: [PATCH 18/33] Add missing permission for AADAccessReviewPolicy Application Read --- CHANGELOG.md | 2 ++ .../DSCResources/MSFT_AADAccessReviewPolicy/settings.json | 3 +++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..4be411b2ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # UNRELEASED +* AADAccessReviewPolicy + * FIXES [#5796](https://github.com/microsoft/Microsoft365DSC/issues/5796) Missing AccessReview permission for Application Read access * AADRoleEligibilityScheduleRequest * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAccessReviewPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAccessReviewPolicy/settings.json index 64be16a4f7..3684362096 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADAccessReviewPolicy/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADAccessReviewPolicy/settings.json @@ -15,6 +15,9 @@ "read": [ { "name": "Policy.Read.All" + }, + { + "name": "AccessReview.Read.All" } ], "update": [ From 65534f96b0140256d1aff69128c410639f3003ae Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 16:27:47 -0800 Subject: [PATCH 19/33] Fix AADDeviceRegistrationPolicy to correctly use parsed Group and User objects for Select EntraJoin --- .../MSFT_AADDeviceRegistrationPolicy.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 index ae8fb8351c..569a4282de 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 @@ -406,8 +406,8 @@ function Set-TargetResource isAdminConfigurable = $AzureADJoinIsAdminConfigurable allowedToJoin = @{ '@odata.type' = $azureADRegistrationAllowedToRegister - users = $AzureADAllowedToJoinUsers - groups = $AzureADAllowedToJoinGroups + users = $azureADRegistrationAllowedUsers + groups = $azureADRegistrationAllowedGroups } localAdmins = @{ enableGlobalAdmins = $LocalAdminsEnableGlobalAdmins From d68dc250afe79bdcefb777b2d35e3ee0e620c0a8 Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 16:30:57 -0800 Subject: [PATCH 20/33] Update changelog for AADDeviceRegistrationPolicy 5798 change --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..3ff34dda41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ # UNRELEASED +* AADDeviceRegistrationPolicy + * FIXES [#5798](https://github.com/microsoft/Microsoft365DSC/issues/5798) - Fix issue setting Selected Users and Groups for Entra Join * AADRoleEligibilityScheduleRequest * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) From 6e7005b404db30f64a2547a2765f0a326f5d0b26 Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 19:52:33 -0800 Subject: [PATCH 21/33] Add null check for object lookup --- .../MSFT_AADRoleAssignmentScheduleRequest.psm1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 index ff1fd4a37d..fc9713a9b3 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADRoleAssignmentScheduleRequest/MSFT_AADRoleAssignmentScheduleRequest.psm1 @@ -138,6 +138,10 @@ function Get-TargetResource $PrincipalValue = $PrincipalInstance.DisplayName } + if ([System.String]::IsNullOrEmpty($PrincipalValue)) { + return $nullResult + } + Write-Verbose -Message 'Found Principal' $RoleDefinitionId = (Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq '$RoleDefinition'").Id Write-Verbose -Message "Retrieved role definition {$RoleDefinition} with ID {$RoleDefinitionId}" From 904a060feb9cdc0afa66e2e551e43e99c45163c8 Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Mon, 17 Feb 2025 19:54:46 -0800 Subject: [PATCH 22/33] Add CHANGELog for AADRoleEligibilityScheduleRequest lookup failure --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..0e10761b5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ * AADRoleEligibilityScheduleRequest * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) + * Add check if object lookup fails + FIXES [#5801](https://github.com/microsoft/Microsoft365DSC/issues/5801) * ADOSecurityPolicy * Fixes an issue where the resource threw an error trying to parse the default values. From 4b825ea39ec93794cd228b2419eee41448e36279 Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Tue, 18 Feb 2025 10:14:16 +0000 Subject: [PATCH 23/33] Fix for #5592 & #5593 - Updated IntuneDeviceCompliancePolicyAndroidDeviceOwner/IntuneDeviceCompliancePolicyAndroidWorkProfile * IntuneDeviceCompliancePolicyAndroidDeviceOwner Added missing properties for androidForWorkCompliancePolicy resource type: https://learn.microsoft.com/en-us/graph/api/resources/intune-deviceconfig-androiddeviceownercompliancepolicy?view=graph-rest-beta. Non-compliance/scheduled actions now supported * IntuneDeviceCompliancePolicyAndroidWorkProfile Added missing properties for androidForWorkCompliancePolicy resource type: https://learn.microsoft.com/en-us/graph/api/resources/intune-deviceconfig-androidforworkcompliancepolicy?view=graph-rest-beta. Non-compliance/scheduled actions now supported --- CHANGELOG.md | 6 + ...iceCompliancePolicyAndroidDeviceOwner.psm1 | 272 ++++++++++++-- ...pliancePolicyAndroidDeviceOwner.schema.mof | 21 ++ ...iceCompliancePolicyAndroidWorkProfile.psm1 | 282 ++++++++++++-- ...pliancePolicyAndroidWorkProfile.schema.mof | 21 ++ ...mpliancePolicyAndroidDeviceOwner.Tests.ps1 | 296 ++++++++++++++- ...mpliancePolicyAndroidWorkProfile.Tests.ps1 | 346 +++++++++++++++++- 7 files changed, 1145 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..4063acc5b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) * SCSensitivityLabel * Fixes invalid accepted content type values. +* IntuneDeviceCompliancePolicyAndroidDeviceOwner + * Adds support for Scheduled Actions and other missing properties + FIXES [#5593] (https://github.com/microsoft/Microsoft365DSC/issues/5593) +* IntuneDeviceCompliancePolicyAndroidWorkProfile + * Adds support for Scheduled Actions and other missing properties + FIXES [#5593] (https://github.com/microsoft/Microsoft365DSC/issues/5592) * TeamsAppPermissionPolicy * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps before adding them to the policy * TeamsAppSetupPolicy diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.psm1 index 1951ccfd38..209a152cc9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.psm1 @@ -16,6 +16,47 @@ function Get-TargetResource [System.Boolean] $DeviceThreatProtectionEnabled, + [Parameter()] + [System.String] + $MinAndroidSecurityPatchLevel, + + [Parameter()] + [System.Int32] + $PasswordMinimumLetterCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumLowerCaseCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumNonLetterCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumNumericCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumSymbolCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumUpperCaseCharacters, + + [Parameter()] + [System.Boolean] + $RequireNoPendingSystemUpdates, + + [Parameter()] + [System.String] + [ValidateSet('basic', 'hardwareBacked')] + $SecurityRequiredAndroidSafetyNetEvaluationType, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $ScheduledActionsForRule, + [Parameter()] [System.String] [ValidateSet('unavailable', 'secured', 'low', 'medium', 'high', 'notSet')] @@ -143,11 +184,13 @@ function Get-TargetResource $devicePolicy = Get-MgBetaDeviceManagementDeviceCompliancePolicy ` -All ` + -ExpandProperty 'scheduledActionsForRule($expand=scheduledActionConfigurations)' ` -ErrorAction Stop | Where-Object ` -FilterScript { $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidDeviceOwnerCompliancePolicy' -and ` $_.displayName -eq $($DisplayName) } + if (([array]$devicePolicy).count -gt 1) { throw "A policy with a duplicated displayName {'$DisplayName'} was found - Ensure displayName is unique" @@ -164,9 +207,43 @@ function Get-TargetResource } Write-Verbose -Message "Found Intune Android Device Owner Device Compliance Policy with displayName {$DisplayName}" + + #scheduledActionsForRule needs processing before we can interact with it + $psCustomObject = $devicePolicy.ScheduledActionsForRule | convertTo-JSON | ConvertFrom-JSON + $scheduledActionsForRuleHashTable = @{} + $psCustomObject.PsObject.Properties | ForEach-Object { + $scheduledActionsForRuleHashTable[$_.Name] = $_.Value + + } + $hashtable = @{} + $complexScheduledActionsForRule = @() + $scheduledActionsForRuleHashTable.ScheduledActionConfigurations.PsObject.Properties | ForEach-Object { + if($_.Value -match "ActionType") + { + foreach($item in $_.Value){ + $hashtable = @{} + $hashtable.Add('actionType', $item.ActionType) + $hashtable.Add('gracePeriodHours', $item.GracePeriodHours) + $hashtable.Add('notificationMessageCcList', ([Array]$item.NotificationMessageCcList -split " ") ) + $hashtable.Add('notificationTemplateId', $item.NotificationTemplateId) + $complexScheduledActionsForRule += $hashtable + } + } + } + $results = @{ DisplayName = $devicePolicy.DisplayName Description = $devicePolicy.Description + MinAndroidSecurityPatchLevel = $devicePolicy.AdditionalProperties.minAndroidSecurityPatchLevel + PasswordMinimumLetterCharacters = $devicePolicy.AdditionalProperties.passwordMinimumLetterCharacters + PasswordMinimumLowerCaseCharacters = $devicePolicy.AdditionalProperties.passwordMinimumLowerCaseCharacters + PasswordMinimumNonLetterCharacters = $devicePolicy.AdditionalProperties.passwordMinimumNonLetterCharacters + PasswordMinimumNumericCharacters = $devicePolicy.AdditionalProperties.passwordMinimumNumericCharacters + PasswordMinimumSymbolCharacters = $devicePolicy.AdditionalProperties.passwordMinimumSymbolCharacters + PasswordMinimumUpperCaseCharacters = $devicePolicy.AdditionalProperties.passwordMinimumUpperCaseCharacters + RequireNoPendingSystemUpdates = $devicePolicy.AdditionalProperties.requireNoPendingSystemUpdates + SecurityRequiredAndroidSafetyNetEvaluationType = $devicePolicy.AdditionalProperties.securityRequiredAndroidSafetyNetEvaluationType + ScheduledActionsForRule = $complexScheduledActionsForRule DeviceThreatProtectionEnabled = $devicePolicy.AdditionalProperties.deviceThreatProtectionEnabled DeviceThreatProtectionRequiredSecurityLevel = $devicePolicy.AdditionalProperties.deviceThreatProtectionRequiredSecurityLevel AdvancedThreatProtectionRequiredSecurityLevel = $devicePolicy.AdditionalProperties.advancedThreatProtectionRequiredSecurityLevel @@ -235,6 +312,47 @@ function Set-TargetResource [System.Boolean] $DeviceThreatProtectionEnabled, + [Parameter()] + [System.String] + $MinAndroidSecurityPatchLevel, + + [Parameter()] + [System.Int32] + $PasswordMinimumLetterCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumLowerCaseCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumNonLetterCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumNumericCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumSymbolCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumUpperCaseCharacters, + + [Parameter()] + [System.Boolean] + $RequireNoPendingSystemUpdates, + + [Parameter()] + [System.String] + [ValidateSet('basic', 'hardwareBacked')] + $SecurityRequiredAndroidSafetyNetEvaluationType, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $ScheduledActionsForRule, + [Parameter()] [System.String] [ValidateSet('unavailable', 'secured', 'low', 'medium', 'high', 'notSet')] @@ -354,24 +472,22 @@ function Set-TargetResource #endregion $currentDeviceAndroidPolicy = Get-TargetResource @PSBoundParameters - - $PSBoundParameters.Remove('Ensure') | Out-Null - $PSBoundParameters.Remove('Credential') | Out-Null - $PSBoundParameters.Remove('ApplicationId') | Out-Null - $PSBoundParameters.Remove('TenantId') | Out-Null - $PSBoundParameters.Remove('ApplicationSecret') | Out-Null - $PSBoundParameters.Remove('CertificateThumbprint') | Out-Null - $PSBoundParameters.Remove('ManagedIdentity') | Out-Null - $PSBoundParameters.Remove('AccessTokens') | Out-Null - - $scheduledActionsForRule = @{ - ruleName = 'PasswordRequired' - scheduledActionConfigurations = @( - @{ - '@odata.type' = '#microsoft.graph.deviceComplianceActionItem' - actionType = 'block' - } - ) + + $PSBoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + + #$allTargetValues = Convert-M365DscHashtableToString -Hashtable $PSBoundParameters + + #reconstruct scheduled action configurations for use with New/Update-MgBetaDeviceManagementDeviceCompliancePolicy + $hashtable = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $PSBoundParameters.ScheduledActionsForRule + $scheduledActionConfigurations = @() + $scheduledActionConfigurations += $hashtable + $PSBoundParameters.Remove('ScheduledActionsForRule') | Out-Null + + $myScheduledActionsForRule = @{ + '@odata.type' = '#microsoft.graph.deviceComplianceScheduledActionForRule' + ruleName = '' #this is always blank and can't be set in GUI + scheduledActionConfigurations = $scheduledActionConfigurations } if ($Ensure -eq 'Present' -and $currentDeviceAndroidPolicy.Ensure -eq 'Absent') @@ -385,7 +501,7 @@ function Set-TargetResource $policy = New-MgBetaDeviceManagementDeviceCompliancePolicy -DisplayName $DisplayName ` -Description $Description ` -AdditionalProperties $AdditionalProperties ` - -ScheduledActionsForRule $scheduledActionsForRule + -ScheduledActionsForRule $myScheduledActionsForRule #region Assignments $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments @@ -415,7 +531,15 @@ function Set-TargetResource $AdditionalProperties = Get-M365DSCIntuneDeviceCompliancePolicyAndroidDeviceOwnerAdditionalProperties -Properties ([System.Collections.Hashtable]$PSBoundParameters) Update-MgBetaDeviceManagementDeviceCompliancePolicy -AdditionalProperties $AdditionalProperties ` -Description $Description ` - -DeviceCompliancePolicyId $configDeviceAndroidPolicy.Id + -DeviceCompliancePolicyId $configDeviceAndroidPolicy.Id#` + #-ScheduledActionsForRule $myScheduledActionsForRule #This does not work even though it is a valid parameter + + #handle ScheduledActionsForRule separately with Invoke-MgGraph + $Uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + "beta/deviceManagement/deviceCompliancePolicies/$($configDeviceAndroidPolicy.Id)/scheduleActionsForRules" + $mgGraphScheduledActionForRules = @{ + deviceComplianceScheduledActionForRules = @( $myScheduledActionsForRule ) + } + Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $($mgGraphScheduledActionForRules | ConvertTo-Json -Depth 10) -Verbose #region Assignments $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments @@ -456,6 +580,47 @@ function Test-TargetResource [System.Boolean] $DeviceThreatProtectionEnabled, + [Parameter()] + [System.String] + $MinAndroidSecurityPatchLevel, + + [Parameter()] + [System.Int32] + $PasswordMinimumLetterCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumLowerCaseCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumNonLetterCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumNumericCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumSymbolCharacters, + + [Parameter()] + [System.Int32] + $PasswordMinimumUpperCaseCharacters, + + [Parameter()] + [System.Boolean] + $RequireNoPendingSystemUpdates, + + [Parameter()] + [System.String] + [ValidateSet('basic', 'hardwareBacked')] + $SecurityRequiredAndroidSafetyNetEvaluationType, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $ScheduledActionsForRule, + [Parameter()] [System.String] [ValidateSet('unavailable', 'secured', 'low', 'medium', 'high', 'notSet')] @@ -569,40 +734,56 @@ function Test-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - Write-Verbose -Message "Testing configuration of Intune Android Work Profile Device Compliance Policy {$DisplayName}" + Write-Verbose -Message "Testing configuration of {$Id}" $CurrentValues = Get-TargetResource @PSBoundParameters - if (-not (Test-M365DSCAuthenticationParameter -BoundParameters $CurrentValues)) + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) { - Write-Verbose "An error occured in Get-TargetResource, the policy {$displayName} will not be processed" - throw "An error occured in Get-TargetResource, the policy {$displayName} will not be processed. Refer to the event viewer logs for more information." + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) { break } + + $ValuesToCheck.Remove($key) | Out-Null + } } + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" - Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" - $ValuesToCheck = $PSBoundParameters - $testResult = $true - #region Assignments - if ($testResult) + #Convert any DateTime to String + foreach ($key in $ValuesToCheck.Keys) { - $source = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $PSBoundParameters.Assignments - $target = $CurrentValues.Assignments - $testResult = Compare-M365DSCIntunePolicyAssignment -Source $source -Target $target - $ValuesToCheck.Remove('Assignments') | Out-Null + if (($null -ne $CurrentValues[$key]) ` + -and ($CurrentValues[$key].getType().Name -eq 'DateTime')) + { + $CurrentValues[$key] = $CurrentValues[$key].toString() + } } - #endregion if ($testResult) { - $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` -ValuesToCheck $ValuesToCheck.Keys } - Write-Verbose -Message "Test-TargetResource returned $TestResult" - return $TestResult + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult } function Export-TargetResource @@ -667,6 +848,7 @@ function Export-TargetResource $Filter = Remove-ComplexFunctionsFromFilterQuery -FilterQuery $Filter } [array]$configDeviceAndroidPolicies = Get-MgBetaDeviceManagementDeviceCompliancePolicy ` + -ExpandProperty 'scheduledActionsForRule($expand=scheduledActionConfigurations)' ` -ErrorAction Stop -All:$true -Filter $Filter | Where-Object ` -FilterScript { $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidDeviceOwnerCompliancePolicy' @@ -725,13 +907,27 @@ function Export-TargetResource } } + if ($Results.ScheduledActionsForRule) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.ScheduledActionsForRule ` + -CIMInstanceName MSFT_scheduledActionConfigurations + if ($complexTypeStringResult) + { + $Results.ScheduledActionsForRule = $complexTypeStringResult + } + else + { + $Results.Remove('ScheduledActionsForRule') | Out-Null + } + } $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` -ConnectionMode $ConnectionMode ` -ModulePath $PSScriptRoot ` -Results $Results ` -Credential $Credential ` - -NoEscape @('Assignments') + -NoEscape @('Assignments', 'ScheduledActionsForRule') $dscContent += $currentDSCBlock diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.schema.mof index 5721daf152..beff197684 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner/MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner.schema.mof @@ -9,12 +9,32 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; }; +[ClassVersion("1.0.0.0")] +class MSFT_scheduledActionConfigurations +{ + [Write, Description("The unique identifier of the action configuration.")] String id; + [Write, Description("Number of hours to wait till the action will be enforced. Valid values 0 to 8760.")] Uint32 gracePeriodHours; + [Write, Description("The action to take."), ValueMap{"notification", "block", "retire", "remoteLock", "pushNotification"}, Values{"notification", "block", "retire", "remoteLock", "pushNotification"}] String actionType; + [Write, Description("The notification Message template to use.")] String notificationTemplateId; + [Write, Description("A list of group IDs to specify who to CC this notification message to.")] String notificationMessageCCList[]; +}; + [ClassVersion("1.0.0.0"), FriendlyName("IntuneDeviceCompliancePolicyAndroidDeviceOwner")] class MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner : OMI_BaseResource { [Key, Description("Display name of the Android Device Owner device compliance policy.")] String DisplayName; [Write, Description("Description of the Android Device Owner device compliance policy.")] String Description; [Write, Description("Assignments of the Intune Policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [Write, Description("Minimum Android security patch level.")] String MinAndroidSecurityPatchLevel; + [Write, Description("Indicates the minimum number of letter characters required for device password. Valid values 1 to 16.")] Uint32 PasswordMinimumLetterCharacters; + [Write, Description("Indicates the minimum number of lower case characters required for device password. Valid values 1 to 16.")] Uint32 PasswordMinimumLowerCaseCharacters; + [Write, Description("Indicates the minimum number of non-letter characters required for device password. Valid values 1 to 16.")] Uint32 PasswordMinimumNonLetterCharacters; + [Write, Description("Indicates the minimum number of numeric characters required for device password. Valid values 1 to 16.")] Uint32 PasswordMinimumNumericCharacters; + [Write, Description("Indicates the minimum number of symbol characters required for device password. Valid values 1 to 16.")] Uint32 PasswordMinimumSymbolCharacters; + [Write, Description("Indicates the minimum number of upper case letter characters required for device password. Valid values 1 to 16.")] Uint32 PasswordMinimumUpperCaseCharacters; + [Write, Description("Require device to have no pending Android system updates.")] Boolean RequireNoPendingSystemUpdates; + [Write, Description("Require a specific Play Integrity evaluation type for compliance. Possible values are: basic, hardwareBacked."), ValueMap{"basic","hardwareBacked"}, Values{"basic","hardwareBacked"}] String SecurityRequiredAndroidSafetyNetEvaluationType; + [Write, Description("Specifies the non-compliance actions."), EmbeddedInstance("MSFT_scheduledActionConfigurations")] String ScheduledActionsForRule[]; [Write, Description("DeviceThreatProtectionEnabled of the Android Device Owner device compliance policy.")] Boolean DeviceThreatProtectionEnabled; [Write, Description("DeviceThreatProtectionRequiredSecurityLevel of the Android Device Owner device compliance policy.")] String DeviceThreatProtectionRequiredSecurityLevel; [Write, Description("AdvancedThreatProtectionRequiredSecurityLevel of the Android Device Owner device compliance policy.")] String AdvancedThreatProtectionRequiredSecurityLevel; @@ -40,3 +60,4 @@ class MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner : OMI_BaseResource [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; [Write, Description("Access token used for authentication.")] String AccessTokens[]; }; + diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.psm1 index 3468c44dff..f0eb794d10 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.psm1 @@ -12,6 +12,53 @@ function Get-TargetResource [System.String] $Description, + [Parameter()] + [System.String] + [ValidateSet('none', 'low', 'medium', 'high')] + $RequiredPasswordComplexity, + + [Parameter()] + [System.Boolean] + $SecurityBlockDeviceAdministratorManagedDevices, + + [Parameter()] + [System.String[]] + $RestrictedApps, + + [Parameter()] + [System.String] + [ValidateSet('deviceDefault', 'lowSecurityBiometric', 'required', 'atLeastNumeric', 'numericComplex', 'atLeastAlphabetic', 'atLeastAlphanumeric', 'alphanumericWithSymbols')] #Specifies Android Work Profile password type. + $WorkProfilePasswordRequiredType, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Low', 'Medium', 'High')] + $WorkProfileRequiredPasswordComplexity, + + [Parameter()] + [System.Boolean] + $WorkProfileRequirePassword, + + [Parameter()] + [System.Int32] + $WorkProfilePreviousPasswordBlockCount, + + [Parameter()] + [System.Int32] + $WorkProfileInactiveBeforeScreenLockInMinutes, + + [Parameter()] + [System.Int32] + $WorkProfilePasswordMinimumLength, + + [Parameter()] + [System.Int32] + $WorkProfilePasswordExpirationInDays, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $ScheduledActionsForRule, + [Parameter()] [System.Boolean] $PasswordRequired, @@ -180,6 +227,7 @@ function Get-TargetResource $devicePolicy = Get-MgBetaDeviceManagementDeviceCompliancePolicy ` -All ` + -ExpandProperty 'scheduledActionsForRule($expand=scheduledActionConfigurations)' ` -ErrorAction SilentlyContinue | Where-Object ` -FilterScript { $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidWorkProfileCompliancePolicy' -and ` $_.displayName -eq $($DisplayName) } @@ -199,9 +247,43 @@ function Get-TargetResource } Write-Verbose -Message "Found Intune Android Work Profile Device Compliance Policy with displayName {$DisplayName}" + + #scheduledActionsForRule needs processing before we can interact with it + $psCustomObject = $devicePolicy.ScheduledActionsForRule | convertTo-JSON | ConvertFrom-JSON + $scheduledActionsForRuleHashTable = @{} + $psCustomObject.PsObject.Properties | ForEach-Object { + $scheduledActionsForRuleHashTable[$_.Name] = $_.Value + } + $hashtable = @{} + $complexScheduledActionsForRule = @() + $scheduledActionsForRuleHashTable.ScheduledActionConfigurations.PsObject.Properties | ForEach-Object { + if($_.Value -match "ActionType") + { + foreach($item in $_.Value){ + $hashtable = @{} + $hashtable.Add('actionType', $item.ActionType) + $hashtable.Add('gracePeriodHours', $item.GracePeriodHours) + $hashtable.Add('notificationMessageCcList', ([Array]$item.NotificationMessageCcList -split " ") ) + $hashtable.Add('notificationTemplateId', $item.NotificationTemplateId) + $complexScheduledActionsForRule += $hashtable + } + } + } + $results = @{ DisplayName = $devicePolicy.DisplayName Description = $devicePolicy.Description + RequiredPasswordComplexity = $devicePolicy.AdditionalProperties.requiredPasswordComplexity + SecurityBlockDeviceAdministratorManagedDevices = $devicePolicy.AdditionalProperties.securityBlockDeviceAdministratorManagedDevices + RestrictedApps = $devicePolicy.AdditionalProperties.restrictedApps + WorkProfilePasswordRequiredType = $devicePolicy.AdditionalProperties.workProfilePasswordRequiredType + WorkProfileRequiredPasswordComplexity = $devicePolicy.AdditionalProperties.workProfileRequiredPasswordComplexity + WorkProfileRequirePassword = $devicePolicy.AdditionalProperties.workProfileRequirePassword + WorkProfilePreviousPasswordBlockCount = $devicePolicy.AdditionalProperties.workProfilePreviousPasswordBlockCount + WorkProfileInactiveBeforeScreenLockInMinutes = $devicePolicy.AdditionalProperties.workProfileInactiveBeforeScreenLockInMinutes + WorkProfilePasswordMinimumLength = $devicePolicy.AdditionalProperties.workProfilePasswordMinimumLength + WorkProfilePasswordExpirationInDays = $devicePolicy.AdditionalProperties.workProfilePasswordExpirationInDays + ScheduledActionsForRule = $complexScheduledActionsForRule PasswordRequired = $devicePolicy.AdditionalProperties.passwordRequired PasswordMinimumLength = $devicePolicy.AdditionalProperties.passwordMinimumLength PasswordRequiredType = $devicePolicy.AdditionalProperties.passwordRequiredType @@ -226,7 +308,6 @@ function Get-TargetResource SecurityRequireUpToDateSecurityProviders = $devicePolicy.AdditionalProperties.securityRequireUpToDateSecurityProviders SecurityRequireCompanyPortalAppIntegrity = $devicePolicy.AdditionalProperties.securityRequireCompanyPortalAppIntegrity SecurityRequiredAndroidSafetyNetEvaluationType = $devicePolicy.AdditionalProperties.securityRequiredAndroidSafetyNetEvaluationType - RoleScopeTagIds = $devicePolicy.AdditionalProperties.roleScopeTagIds Ensure = 'Present' Credential = $Credential @@ -276,6 +357,53 @@ function Set-TargetResource [System.String] $Description, + [Parameter()] + [System.String] + [ValidateSet('none', 'low', 'medium', 'high')] + $RequiredPasswordComplexity, + + [Parameter()] + [System.Boolean] + $SecurityBlockDeviceAdministratorManagedDevices, + + [Parameter()] + [System.String[]] + $RestrictedApps, + + [Parameter()] + [System.String] + [ValidateSet('deviceDefault', 'lowSecurityBiometric', 'required', 'atLeastNumeric', 'numericComplex', 'atLeastAlphabetic', 'atLeastAlphanumeric', 'alphanumericWithSymbols')] #Specifies Android Work Profile password type. + $WorkProfilePasswordRequiredType, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Low', 'Medium', 'High')] + $WorkProfileRequiredPasswordComplexity, + + [Parameter()] + [System.Boolean] + $WorkProfileRequirePassword, + + [Parameter()] + [System.Int32] + $WorkProfilePreviousPasswordBlockCount, + + [Parameter()] + [System.Int32] + $WorkProfileInactiveBeforeScreenLockInMinutes, + + [Parameter()] + [System.Int32] + $WorkProfilePasswordMinimumLength, + + [Parameter()] + [System.Int32] + $WorkProfilePasswordExpirationInDays, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $ScheduledActionsForRule, + [Parameter()] [System.Boolean] $PasswordRequired, @@ -437,23 +565,18 @@ function Set-TargetResource $currentDeviceAndroidPolicy = Get-TargetResource @PSBoundParameters - $PSBoundParameters.Remove('Ensure') | Out-Null - $PSBoundParameters.Remove('Credential') | Out-Null - $PSBoundParameters.Remove('ApplicationId') | Out-Null - $PSBoundParameters.Remove('TenantId') | Out-Null - $PSBoundParameters.Remove('ApplicationSecret') | Out-Null - $PSBoundParameters.Remove('AccessTokens') | Out-Null + $PSBoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters - $scheduledActionsForRule = @{ + #reconstruct scheduled action configurations for use with New/Update-MgBetaDeviceManagementDeviceCompliancePolicy + $hashtable = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $PSBoundParameters.ScheduledActionsForRule + $scheduledActionConfigurations = @() + $scheduledActionConfigurations += $hashtable + $PSBoundParameters.Remove('ScheduledActionsForRule') | Out-Null + $myScheduledActionsForRule = @{ '@odata.type' = '#microsoft.graph.deviceComplianceScheduledActionForRule' - ruleName = 'PasswordRequired' - scheduledActionConfigurations = @( - @{ - '@odata.type' = '#microsoft.graph.deviceComplianceActionItem' - actionType = 'block' - } - ) - } + ruleName = '' #this is always blank and can't be set in GUI + scheduledActionConfigurations = $scheduledActionConfigurations + } if ($Ensure -eq 'Present' -and $currentDeviceAndroidPolicy.Ensure -eq 'Absent') { @@ -466,7 +589,7 @@ function Set-TargetResource $policy = New-MgBetaDeviceManagementDeviceCompliancePolicy -DisplayName $DisplayName ` -Description $Description ` -AdditionalProperties $AdditionalProperties ` - -ScheduledActionsForRule $scheduledActionsForRule + -ScheduledActionsForRule $myScheduledActionsForRule #region Assignments $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments @@ -494,6 +617,14 @@ function Set-TargetResource Update-MgBetaDeviceManagementDeviceCompliancePolicy -AdditionalProperties $AdditionalProperties ` -Description $Description ` -DeviceCompliancePolicyId $configDeviceAndroidPolicy.Id + #-ScheduledActionsForRule $myScheduledActionsForRule #This does not work even though it is a valid parameter + + #handle ScheduledActionsForRule separately with Invoke-MgGraph + $Uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + "beta/deviceManagement/deviceCompliancePolicies/$($configDeviceAndroidPolicy.Id)/scheduleActionsForRules" + $mgGraphScheduledActionForRules = @{ + deviceComplianceScheduledActionForRules = @( $myScheduledActionsForRule ) + } + Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $($mgGraphScheduledActionForRules | ConvertTo-Json -Depth 10) -Verbose #region Assignments $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments @@ -528,6 +659,53 @@ function Test-TargetResource [System.String] $Description, + [Parameter()] + [System.String] + [ValidateSet('none', 'low', 'medium', 'high')] + $RequiredPasswordComplexity, + + [Parameter()] + [System.Boolean] + $SecurityBlockDeviceAdministratorManagedDevices, + + [Parameter()] + [System.String[]] + $RestrictedApps, + + [Parameter()] + [System.String] + [ValidateSet('deviceDefault', 'lowSecurityBiometric', 'required', 'atLeastNumeric', 'numericComplex', 'atLeastAlphabetic', 'atLeastAlphanumeric', 'alphanumericWithSymbols')] #Specifies Android Work Profile password type. + $WorkProfilePasswordRequiredType, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Low', 'Medium', 'High')] + $WorkProfileRequiredPasswordComplexity, + + [Parameter()] + [System.Boolean] + $WorkProfileRequirePassword, + + [Parameter()] + [System.Int32] + $WorkProfilePreviousPasswordBlockCount, + + [Parameter()] + [System.Int32] + $WorkProfileInactiveBeforeScreenLockInMinutes, + + [Parameter()] + [System.Int32] + $WorkProfilePasswordMinimumLength, + + [Parameter()] + [System.Int32] + $WorkProfilePasswordExpirationInDays, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $ScheduledActionsForRule, + [Parameter()] [System.Boolean] $PasswordRequired, @@ -674,47 +852,64 @@ function Test-TargetResource Confirm-M365DSCDependencies #region Telemetry - $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') $CommandName = $MyInvocation.MyCommand $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` -CommandName $CommandName ` -Parameters $PSBoundParameters Add-M365DSCTelemetryEvent -Data $data #endregion - Write-Verbose -Message "Testing configuration of Intune Android Work Profile Device Compliance Policy {$DisplayName}" + + Write-Verbose -Message "Testing configuration of {$Id}" $CurrentValues = Get-TargetResource @PSBoundParameters - if (-not (Test-M365DSCAuthenticationParameter -BoundParameters $CurrentValues)) + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) { - Write-Verbose "An error occured in Get-TargetResource, the policy {$displayName} will not be processed" - throw "An error occured in Get-TargetResource, the policy {$displayName} will not be processed. Refer to the event viewer logs for more information." + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) { break } + + $ValuesToCheck.Remove($key) | Out-Null + } } + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" - Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" - $ValuesToCheck = $PSBoundParameters - $testResult = $true - #region Assignments - if ($testResult) + #Convert any DateTime to String + foreach ($key in $ValuesToCheck.Keys) { - $source = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $PSBoundParameters.Assignments - $target = $CurrentValues.Assignments - $testResult = Compare-M365DSCIntunePolicyAssignment -Source $source -Target $target - $ValuesToCheck.Remove('Assignments') | Out-Null + if (($null -ne $CurrentValues[$key]) ` + -and ($CurrentValues[$key].getType().Name -eq 'DateTime')) + { + $CurrentValues[$key] = $CurrentValues[$key].toString() + } } - #endregion if ($testResult) { - $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` -ValuesToCheck $ValuesToCheck.Keys } - Write-Verbose -Message "Test-TargetResource returned $TestResult" - return $TestResult + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult } function Export-TargetResource @@ -779,6 +974,7 @@ function Export-TargetResource $Filter = Remove-ComplexFunctionsFromFilterQuery -FilterQuery $Filter } [array]$configDeviceAndroidPolicies = Get-MgBetaDeviceManagementDeviceCompliancePolicy ` + -ExpandProperty 'scheduledActionsForRule($expand=scheduledActionConfigurations)' ` -ErrorAction Stop -All:$true -Filter $Filter | Where-Object ` -FilterScript { $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidWorkProfileCompliancePolicy' } $configDeviceAndroidPolicies = Find-GraphDataUsingComplexFunctions -ComplexFunctions $complexFunctions -Policies $configDeviceAndroidPolicies @@ -835,13 +1031,27 @@ function Export-TargetResource } } + if ($Results.ScheduledActionsForRule) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.ScheduledActionsForRule ` + -CIMInstanceName MSFT_scheduledActionConfigurations + if ($complexTypeStringResult) + { + $Results.ScheduledActionsForRule = $complexTypeStringResult + } + else + { + $Results.Remove('ScheduledActionsForRule') | Out-Null + } + } $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` -ConnectionMode $ConnectionMode ` -ModulePath $PSScriptRoot ` -Results $Results ` -Credential $Credential ` - -NoEscape @('Assignments') + -NoEscape @('Assignments', 'ScheduledActionsForRule') $dscContent += $currentDSCBlock Save-M365DSCPartialExport -Content $currentDSCBlock ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.schema.mof index 4444ae768f..b1e6516908 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile/MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile.schema.mof @@ -9,12 +9,33 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; }; +[ClassVersion("1.0.0.0")] +class MSFT_scheduledActionConfigurations +{ + [Write, Description("The unique identifier of the action configuration.")] String id; + [Write, Description("Number of hours to wait till the action will be enforced. Valid values 0 to 8760.")] Uint32 gracePeriodHours; + [Write, Description("The action to take."), ValueMap{"notification", "block", "retire", "remoteLock", "pushNotification"}, Values{"notification", "block", "retire", "remoteLock", "pushNotification"}] String actionType; + [Write, Description("The notification Message template to use.")] String notificationTemplateId; + [Write, Description("A list of group IDs to specify who to CC this notification message to.")] String notificationMessageCCList[]; +}; + [ClassVersion("1.0.0.0"), FriendlyName("IntuneDeviceCompliancePolicyAndroidWorkProfile")] class MSFT_IntuneDeviceCompliancePolicyAndroidWorkProfile : OMI_BaseResource { [Key, Description("Display name of the AndroidWorkProfile device compliance policy.")] String DisplayName; [Write, Description("Description of the AndroidWorkProfile device compliance policy.")] String Description; [Write, Description("Assignments of the Intune Policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [Write, Description("The password complexity types that can be set on Android. One of: NONE, LOW, MEDIUM, HIGH. This is an API targeted to Android 11+."), ValueMap{"none", "low", "medium", "high"}, Values{"none", "low", "medium", "high"}] String RequiredPasswordComplexity; + [Write, Description("Setting securityBlockDeviceAdministratorManagedDevices to true enhances security by preventing devices managed through the legacy device administrator method from accessing corporate resources.")] Boolean SecurityBlockDeviceAdministratorManagedDevices; + [Write, Description("Specify applications that users are prohibited from installing or using on their devices.")] String RestrictedApps[]; + [Write, Description("Specifies Android Work Profile password type."), ValueMap{"deviceDefault", "lowSecurityBiometric", "required", "atLeastNumeric", "numericComplex", "atLeastAlphabetic", "atLeastAlphanumeric", "alphanumericWithSymbols"}, Values{"deviceDefault", "lowSecurityBiometric", "required", "atLeastNumeric", "numericComplex", "atLeastAlphabetic", "atLeastAlphanumeric", "alphanumericWithSymbols"}] String WorkProfilePasswordRequiredType; + [Write, Description("Specifies Android Work Profile password complexity."), ValueMap{"None", "Low", "Medium", "High"}, Values{"None", "Low", "Medium", "High"}] String WorkProfileRequiredPasswordComplexity; + [Write, Description("Specifies if Android Work Profile password is required.")] Boolean WorkProfileRequirePassword; + [Write, Description("Specifies the number of previous passwords that cannot be reused in an Android Work Profile compliance policy.")] Uint32 WorkProfilePreviousPasswordBlockCount; + [Write, Description("Defines the duration of inactivity (in minutes) after which the screen is locked.")] Uint32 WorkProfileInactiveBeforeScreenLockInMinutes; + [Write, Description("Specifies the minimum number of characters required in a password for an Android Work Profile.")] Uint32 WorkProfilePasswordMinimumLength; + [Write, Description("Specifies the number of days before a password expires for an Android Work Profile.")] Uint32 WorkProfilePasswordExpirationInDays; + [Write, Description("Specifies the non-compliance actions."), EmbeddedInstance("MSFT_scheduledActionConfigurations")] String ScheduledActionsForRule[]; [Write, Description("PasswordRequired of the AndroidWorkProfile device compliance policy.")] Boolean PasswordRequired; [Write, Description("PasswordMinimumLength of the AndroidWorkProfile device compliance policy.")] Uint32 PasswordMinimumLength; [Write, Description("PasswordRequiredType of the AndroidWorkProfile device compliance policy."), ValueMap{"deviceDefault", "alphabetic", "alphanumeric", "alphanumericWithSymbols", "lowSecurityBiometric", "numeric", "numericComplex", "any"}, Values{"deviceDefault", "alphabetic", "alphanumeric", "alphanumericWithSymbols", "lowSecurityBiometric", "numeric", "numericComplex", "any"}] String PasswordRequiredType; diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidDeviceOwner.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidDeviceOwner.Tests.ps1 index 37aac318f1..198a2d8724 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidDeviceOwner.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidDeviceOwner.Tests.ps1 @@ -60,6 +60,13 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { $testParams = @{ DisplayName = 'Test Android Device Owner Device Compliance Policy' Description = 'Test Android Device Owner Device Compliance Policy Description' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -75,8 +82,41 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { PasswordPreviousPasswordCountToBlock = 10 StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True + MinAndroidSecurityPatchLevel = '2024-01-24' + SecurityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' Ensure = 'Present' - Credential = $Credential + Credential = $Credential + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) } Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { @@ -103,6 +143,13 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { $testParams = @{ DisplayName = 'Test Android Device Owner Device Compliance Policy' Description = 'Test Android Device Owner Device Compliance Policy Description' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -118,17 +165,88 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { PasswordPreviousPasswordCountToBlock = 10 StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True + minAndroidSecurityPatchLevel = '2024-01-24' + securityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' Ensure = 'Present' - Credential = $Credential - } + Credential = $Credential + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) + } - Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { - return @{ - DisplayName = 'Test Android Device Owner Device Compliance Policy' - Description = 'Different Value' - Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { + return @{ + DisplayName = 'Test Android Device Owner Device Compliance Policy' + Description = 'Different Value' + Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidDeviceOwnerCompliancePolicy' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -145,6 +263,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True RoleScopeTagIds = '0' + minAndroidSecurityPatchLevel = '2024-01-24' + securityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' } } } @@ -169,6 +289,13 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { $testParams = @{ DisplayName = 'Test Android Device Owner Device Compliance Policy' Description = 'Test Android Device Owner Device Compliance Policy Description' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -185,7 +312,40 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True Ensure = 'Present' + minAndroidSecurityPatchLevel = '2024-01-24' + securityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' Credential = $Credential + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) } Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { @@ -193,8 +353,46 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DisplayName = 'Test Android Device Owner Device Compliance Policy' Description = 'Test Android Device Owner Device Compliance Policy Description' Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidDeviceOwnerCompliancePolicy' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -211,6 +409,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True RoleScopeTagIds = '0' + minAndroidSecurityPatchLevel = '2024-01-24' + securityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' } } } @@ -234,8 +434,46 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DisplayName = 'Test Android Device Owner Device Compliance Policy' Description = 'Test Android Device Owner Device Compliance Policy Description' Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidDeviceOwnerCompliancePolicy' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -252,6 +490,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True RoleScopeTagIds = '0' + minAndroidSecurityPatchLevel = '2024-01-24' + securityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' } } } @@ -284,8 +524,46 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { DisplayName = 'Test Android Device Owner Device Compliance Policy' Description = 'Test Android Device Owner Device Compliance Policy Description' Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidDeviceOwnerCompliancePolicy' + PasswordMinimumLetterCharacters = 1 + PasswordMinimumLowerCaseCharacters = 1 + PasswordMinimumNonLetterCharacters = 1 + PasswordMinimumNumericCharacters = 1 + PasswordMinimumSymbolCharacters = 1 + PasswordMinimumUpperCaseCharacters = 1 + RequireNoPendingSystemUpdates = $true DeviceThreatProtectionEnabled = $True DeviceThreatProtectionRequiredSecurityLevel = 'Unavailable' AdvancedThreatProtectionRequiredSecurityLevel = 'Unavailable' @@ -302,6 +580,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { StorageRequireEncryption = $True SecurityRequireIntuneAppIntegrity = $True RoleScopeTagIds = '0' + minAndroidSecurityPatchLevel = '2024-01-24' + securityRequiredAndroidSafetyNetEvaluationType = 'hardwareBacked' } } } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidWorkProfile.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidWorkProfile.Tests.ps1 index 013e22afc6..316dc24406 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidWorkProfile.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceCompliancePolicyAndroidWorkProfile.Tests.ps1 @@ -82,8 +82,49 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireGooglePlayServices = $True SecurityRequireUpToDateSecurityProviders = $True SecurityRequireCompanyPortalAppIntegrity = $True + MinAndroidSecurityPatchLevel = "2024-01-01"; + RequiredPasswordComplexity = "medium"; + SecurityRequiredAndroidSafetyNetEvaluationType = "hardwareBacked" + WorkProfileInactiveBeforeScreenLockInMinutes = 480 + WorkProfilePasswordExpirationInDays = 30 + WorkProfilePasswordMinimumLength = 12 + WorkProfilePasswordRequiredType = "atLeastNumeric" + WorkProfilePreviousPasswordBlockCount = 5 + WorkProfileRequiredPasswordComplexity = "high" + WorkProfileRequirePassword = $True Ensure = 'Present' Credential = $Credential + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) } Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { @@ -132,21 +173,96 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireGooglePlayServices = $True SecurityRequireUpToDateSecurityProviders = $True SecurityRequireCompanyPortalAppIntegrity = $True + MinAndroidSecurityPatchLevel = "2024-01-01"; + SecurityRequiredAndroidSafetyNetEvaluationType = "hardwareBacked" + WorkProfileInactiveBeforeScreenLockInMinutes = 480 + WorkProfilePasswordExpirationInDays = 30 + WorkProfilePasswordMinimumLength = 12 + WorkProfilePasswordRequiredType = "atLeastNumeric" + WorkProfilePreviousPasswordBlockCount = 5 + WorkProfileRequiredPasswordComplexity = "high" + WorkProfileRequirePassword = $True Ensure = 'Present' Credential = $Credential + RequiredPasswordComplexity = 'low' + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) + } Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { return @{ - DisplayName = 'Test Android Work Profile Device Compliance Policy' - Description = 'Test Android Work Profile Device Compliance Policy Description' - Id = '9c4e2ed7-706e-4874-a826-0c2778352d47' + DisplayName = 'Test Android Work Profile Device Compliance Policy' + Description = 'Test Android Work Profile Device Compliance Policy Description' + Id = '9c4e2ed7-706e-4874-a826-0c2778352d47' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidWorkProfileCompliancePolicy' PasswordRequired = $True PasswordMinimumLength = 6 PasswordRequiredType = 'DeviceDefault' - RequiredPasswordComplexity = 'None' + RequiredPasswordComplexity = 'low' PasswordMinutesOfInactivityBeforeLock = 5 PasswordExpirationDays = 365 PasswordPreviousPasswordBlockCount = 10 @@ -167,6 +283,17 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireUpToDateSecurityProviders = $True SecurityRequireCompanyPortalAppIntegrity = $True RoleScopeTagIds = '0' + MinAndroidSecurityPatchLevel = "2024-01-01"; + SecurityRequiredAndroidSafetyNetEvaluationType = "hardwareBacked" + WorkProfileInactiveBeforeScreenLockInMinutes = 480 + WorkProfilePasswordExpirationInDays = 30 + WorkProfilePasswordMinimumLength = 12 + WorkProfilePasswordRequiredType = "atLeastNumeric" + WorkProfilePreviousPasswordBlockCount = 5 + WorkProfileRequiredPasswordComplexity = "high" + WorkProfileRequirePassword = $True + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') } } } @@ -212,22 +339,96 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireSafetyNetAttestationCertifiedDevice = $True SecurityRequireGooglePlayServices = $True SecurityRequireUpToDateSecurityProviders = $True - SecurityRequireCompanyPortalAppIntegrity = $True + SecurityRequireCompanyPortalAppIntegrity = $True + MinAndroidSecurityPatchLevel = "2024-01-01"; + SecurityRequiredAndroidSafetyNetEvaluationType = "hardwareBacked" + WorkProfileInactiveBeforeScreenLockInMinutes = 480 + WorkProfilePasswordExpirationInDays = 30 + WorkProfilePasswordMinimumLength = 12 + WorkProfilePasswordRequiredType = "atLeastNumeric" + WorkProfilePreviousPasswordBlockCount = 5 + WorkProfileRequiredPasswordComplexity = "high" + WorkProfileRequirePassword = $True Ensure = 'Present' Credential = $Credential + RequiredPasswordComplexity = 'low' + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) } Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { return @{ - DisplayName = 'Test Android Work Profile Device Compliance Policy' - Description = 'Test Android Work Profile Device Compliance Policy Description' - Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + DisplayName = 'Test Android Work Profile Device Compliance Policy' + Description = 'Test Android Work Profile Device Compliance Policy Description' + Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidWorkProfileCompliancePolicy' PasswordRequired = $True PasswordMinimumLength = 6 PasswordRequiredType = 'DeviceDefault' - RequiredPasswordComplexity = 'None' + RequiredPasswordComplexity = 'low' PasswordMinutesOfInactivityBeforeLock = 5 PasswordExpirationDays = 365 PasswordPreviousPasswordBlockCount = 10 @@ -248,6 +449,17 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireUpToDateSecurityProviders = $True SecurityRequireCompanyPortalAppIntegrity = $True RoleScopeTagIds = '0' + MinAndroidSecurityPatchLevel = "2024-01-01"; + SecurityRequiredAndroidSafetyNetEvaluationType = "hardwareBacked" + WorkProfileInactiveBeforeScreenLockInMinutes = 480 + WorkProfilePasswordExpirationInDays = 30 + WorkProfilePasswordMinimumLength = 12 + WorkProfilePasswordRequiredType = "atLeastNumeric" + WorkProfilePreviousPasswordBlockCount = 5 + WorkProfileRequiredPasswordComplexity = "high" + WorkProfileRequirePassword = $True + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') } } } @@ -287,19 +499,84 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireCompanyPortalAppIntegrity = $True Ensure = 'Absent' Credential = $Credential + RequiredPasswordComplexity = 'low' + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') + ScheduledActionsForRule = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + } -ClientOnly) + (New-CimInstance ` + -ClassName MSFT_scheduledActionConfigurations ` + -Property @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } -ClientOnly) + ) } Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { return @{ - DisplayName = 'Test Android Work Profile Device Compliance Policy' - Description = 'Test Android Work Profile Device Compliance Policy Description' - Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + DisplayName = 'Test Android Work Profile Device Compliance Policy' + Description = 'Test Android Work Profile Device Compliance Policy Description' + Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidWorkProfileCompliancePolicy' PasswordRequired = $True PasswordMinimumLength = 6 PasswordRequiredType = 'DeviceDefault' - RequiredPasswordComplexity = 'None' + RequiredPasswordComplexity = 'low' PasswordMinutesOfInactivityBeforeLock = 5 PasswordExpirationDays = 365 PasswordPreviousPasswordBlockCount = 10 @@ -320,6 +597,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireUpToDateSecurityProviders = $True SecurityRequireCompanyPortalAppIntegrity = $True RoleScopeTagIds = '0' + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') } } } @@ -349,15 +628,46 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicy -MockWith { return @{ - DisplayName = 'Test Android Device Compliance Policy' - Description = 'Test Android Device Compliance Policy Description' - Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + DisplayName = 'Test Android Device Compliance Policy' + Description = 'Test Android Device Compliance Policy Description' + Id = '9c4e2ed7-706e-4874-a826-0c2778352d46' + ScheduledActionsForRule =@( + @{ + ruleName = '' + scheduledActionConfigurations = @( + @{ + actionType = 'block' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'pushNotification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'remoteLock' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @() + }, + @{ + actionType = 'Notification' + gracePeriodHours = 0 + notificationTemplateId = '00000000-0000-0000-0000-000000000000' + notificationMessageCCList = @('00000000-0000-0000-0000-000000000000','00000000-0000-0000-0000-000000000000') + } + ) + } + ) AdditionalProperties = @{ '@odata.type' = '#microsoft.graph.androidWorkProfileCompliancePolicy' PasswordRequired = $True PasswordMinimumLength = 6 PasswordRequiredType = 'DeviceDefault' - RequiredPasswordComplexity = 'None' + RequiredPasswordComplexity = 'low' PasswordMinutesOfInactivityBeforeLock = 5 PasswordExpirationDays = 365 PasswordPreviousPasswordBlockCount = 10 @@ -377,6 +687,8 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { SecurityRequireGooglePlayServices = $True SecurityRequireUpToDateSecurityProviders = $True SecurityRequireCompanyPortalAppIntegrity = $True + SecurityBlockDeviceAdministratorManagedDevices = $true + RestrictedApps = @('App1', 'App2', 'App3') } } } From 31f91f6b8abfd921de819221bb07f4d3ec7b96aa Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 19 Feb 2025 16:44:48 -0500 Subject: [PATCH 24/33] Multiple Fixes --- CHANGELOG.md | 26 +++++++++++++++++-- .../MSFT_AADApplication.psm1 | 21 ++++++++++----- .../MSFT_AADDeviceRegistrationPolicy.psm1 | 1 + .../MSFT_AADGroup/MSFT_AADGroup.psm1 | 4 +-- .../MSFT_AADServicePrincipal.psm1 | 11 ++++---- .../MSFT_EXODistributionGroup.psm1 | 13 +++++++--- .../MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 | 16 ++++++++++-- ...ManagementEnrollmentAndroidGooglePlay.psm1 | 10 +++---- .../MSFT_M365DSCRuleEvaluation.psm1 | 16 ++++++++++++ .../MSFT_M365DSCRuleEvaluation.schema.mof | 1 + .../MSFT_SCInsiderRiskPolicy.psm1 | 20 ++++++++++++-- .../MSFT_SCInsiderRiskPolicy.schema.mof | 2 +- .../Modules/M365DSCDRGUtil.psm1 | 2 +- 13 files changed, 112 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 902d2e9b38..916c30c4fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,22 +2,45 @@ # UNRELEASED +* AADApplication + * Test-TargetResource logic updated to skip evaluating CIMArrays that are empty + when passed as desired values. +* AADDeviceRegistrationPolicy + * Fixed an issue where the AzureADJoinIsAdminConfigurable was not returned by the + Get-TargetResource function. +* AADGroup + * Returns an empty array for roles and licenses from the Get-TargetResource + function instead of null when no instances are found. * AADRoleEligibilityScheduleRequest * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) +* AADServicePrincipal + * Evaluating assigned users based on UPN and not just on DisplayName. * ADOSecurityPolicy * Fixes an issue where the resource threw an error trying to parse the default values. +* EXODistributionGroup + * Changed logic to retrieve existing members by UserPrincipalName. +* EXORoleGroup + * Evaluating assigned users based on UPN and not just on DisplayName if they + have an associated mailbox. +* IntuneDeviceManagementEnrollmentAndroidGooglePlay + * Marked the Id property as mandatory in the resource. +* M365DSCRuleEvaluation + * Added support for specifying a Filter property. * M365DSCUtil * Add M365DSC prefix to `Remove-EmptyValue`. * Fixes an issue with `Credential` property being escaped and indentation. * Adds the possibility to allow variables in strings and no authentication results update during conversion to final export. FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) +* SCInsiderRiskPolicy + * Enforces the MDATPTriageStatus to be a string array. * SCSensitivityLabel * Fixes invalid accepted content type values. * TeamsAppPermissionPolicy - * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps before adding them to the policy + * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps + before adding them to the policy * TeamsAppSetupPolicy * FIXES [[#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) * TeamsM365App @@ -48,7 +71,6 @@ * EXOSmtpDaneInbound * Updated authentication properties to align with MOF definition. FIXES [#5709](https://github.com/microsoft/Microsoft365DSC/issues/5709) - * MISC * PowerPlatform resource revamp to use direct REST API calls. * Simplify export behavior for all resources and complex objects. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 index e27093e3f1..922475a5a4 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 @@ -1425,14 +1425,21 @@ function Test-TargetResource $target = $CurrentValues.$key if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') { - $testResult = Compare-M365DSCComplexObject ` - -Source ($source) ` - -Target ($target) - - if (-not $testResult) + if (-not ($source.GetType().Name -eq 'CimInstance[]' -and $source.Count -eq 0)) { - Write-Verbose "TestResult returned False for $source" - $testTargetResource = $false + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) + { + Write-Verbose "TestResult returned False for $source" + $testTargetResource = $false + } + else + { + $ValuesToCheck.Remove($key) | Out-Null + } } else { diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 index ae8fb8351c..c95c3c1073 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADDeviceRegistrationPolicy/MSFT_AADDeviceRegistrationPolicy.psm1 @@ -215,6 +215,7 @@ function Get-TargetResource } $results = @{ IsSingleInstance = 'Yes' + AzureADJoinIsAdminConfigurable = [Boolean]$getValue.AzureAdJoin.IsAdminConfigurable AzureADAllowedToJoin = $AzureADAllowedToJoin AzureADAllowedToJoinGroups = $AzureADAllowedToJoinGroups AzureADAllowedToJoinUsers = $AzureADAllowedToJoinUsers diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 index 065609a14f..0c1464c0a5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADGroup/MSFT_AADGroup.psm1 @@ -245,7 +245,7 @@ function Get-TargetResource } # AssignedToRole - $AssignedToRoleValues = $null + $AssignedToRoleValues = @() if ($Group.IsAssignableToRole -eq $true) { $AssignedToRoleValues = @() @@ -258,7 +258,7 @@ function Get-TargetResource } # Licenses - $assignedLicensesValues = $null + $assignedLicensesValues = @() $uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + "v1.0/groups/$($Group.Id)/assignedLicenses" $assignedLicensesRequest = Invoke-MgGraphRequest -Method 'GET' ` -Uri $uri diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 index f8da43f8ad..90db33a7f6 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADServicePrincipal/MSFT_AADServicePrincipal.psm1 @@ -175,14 +175,12 @@ function Get-TargetResource $appInstance = Get-MgApplication -Filter "DisplayName eq '$AppId'" if ($appInstance) { - $AADServicePrincipal = Get-MgServicePrincipal -Filter "AppID eq '$($appInstance.AppId)'" ` - -Expand 'AppRoleAssignedTo' + $AADServicePrincipal = Get-MgServicePrincipal -Filter "AppID eq '$($appInstance.AppId)'" } } else { - $AADServicePrincipal = Get-MgServicePrincipal -Filter "AppID eq '$($AppId)'" ` - -Expand 'AppRoleAssignedTo' + $AADServicePrincipal = Get-MgServicePrincipal -Filter "AppID eq '$($AppId)'" } } if ($null -eq $AADServicePrincipal) @@ -196,7 +194,8 @@ function Get-TargetResource } $AppRoleAssignedToValues = @() - foreach ($principal in $AADServicePrincipal.AppRoleAssignedTo) + $assignmentsValue = Get-MgServicePrincipalAppROleAssignedTo -ServicePrincipalId $AADServicePrincipal.Id -ErrorAction SilentlyContinue + foreach ($principal in $assignmentsValue) { $currentAssignment = @{ PrincipalType = $null @@ -206,7 +205,7 @@ function Get-TargetResource { $user = Get-MgUser -UserId $principal.PrincipalId $currentAssignment.PrincipalType = 'User' - $currentAssignment.Identity = $user.UserPrincipalName.Split('@')[0] + $currentAssignment.Identity = $user.UserPrincipalName $AppRoleAssignedToValues += $currentAssignment } elseif ($principal.PrincipalType -eq 'Group') diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 index 14e27556d8..d573a7fcfd 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 @@ -241,7 +241,7 @@ function Get-TargetResource $nullReturn = $PSBoundParameters $nullReturn.Ensure = 'Absent' - if ($null -ne $PrimarySmtpAddress) + if (-not [System.String]::IsNullOrEmpty($PrimarySmtpAddress)) { $distributionGroup = Get-DistributionGroup -Identity $PrimarySmtpAddress -ErrorAction Stop } @@ -261,7 +261,7 @@ function Get-TargetResource $distributionGroup = $Script:exportedInstance } - if ($null -ne $PrimarySmtpAddress) + if (-not [System.String]::IsNullOrEmpty($PrimarySmtpAddress)) { $distributionGroupMembers = Get-DistributionGroupMember -Identity $PrimarySmtpAddress ` -ErrorAction 'Stop' ` @@ -274,6 +274,13 @@ function Get-TargetResource -ResultSize 'Unlimited' } + $distributionMembersValue = @() + foreach ($member in $distributionGroupMembers) + { + $user = Get-User -Identity $member -ErrorAction Stop + $distributionMembersValue += $user.UserPrincipalName + } + Write-Verbose -Message "Found existing Distribution Group {$Identity}." $descriptionValue = $null if ($distributionGroup.Description.Length -gt 0) @@ -331,7 +338,7 @@ function Get-TargetResource ManagedBy = $ManagedByValue MemberDepartRestriction = $distributionGroup.MemberDepartRestriction MemberJoinRestriction = $distributionGroup.MemberJoinRestriction - Members = $distributionGroupMembers.Name + Members = $distributionMembersValue ModeratedBy = $ModeratedByValue ModerationEnabled = $distributionGroup.ModerationEnabled Name = $distributionGroup.Name diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 index 587ab48e42..bf78b62162 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXORoleGroup/MSFT_EXORoleGroup.psm1 @@ -97,12 +97,24 @@ function Get-TargetResource } # Get RoleGroup Members DN if RoleGroup exists. This is required especially when adding Members like "Exchange Administrator" or "Global Administrator" that have different Names across Tenants - $roleGroupMember = Get-RoleGroupMember -Identity $Name | Select-Object DisplayName + $roleGroupMembers = Get-RoleGroupMember -Identity $Name | Select-Object DisplayName, RecipientTypeDetails, PrimarySmtpAddress + $roleGroupMembersValue = @() + foreach ($member in $roleGroupMembers) + { + if ($member.RecipientTypeDetails -eq 'UserMailbox' -and -not [System.String]::IsNullOrEmpty($member.PrimarySmtpAddress)) + { + $roleGroupMembersValue += $member.PrimarySmtpAddress + } + else + { + $roleGroupMembersValue += $member.DisplayName + } + } $result = @{ Name = $RoleGroup.Name Description = $RoleGroup.Description - Members = $roleGroupMember.PrimarySmtpAddress + Members = $roleGroupMembersValue Roles = $RoleGroup.Roles Ensure = 'Present' Credential = $Credential diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay.psm1 index 45ae0c0e68..baf3e898ef 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay/MSFT_IntuneDeviceManagementEnrollmentAndroidGooglePlay.psm1 @@ -6,7 +6,7 @@ function Get-TargetResource ( #region Intune resource parameters - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $Id, @@ -70,7 +70,7 @@ function Get-TargetResource $AccessTokens ) - Write-Verbose -Message "Getting configuration of the Intune Device Management Android Google Play Enrollment with Id {$Id} and DisplayName {$DisplayName}" + Write-Verbose -Message "Getting configuration of the Intune Device Management Android Google Play Enrollment with Id {$Id}" try { @@ -152,7 +152,7 @@ function Set-TargetResource ( #region Intune resource parameters - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $Id, @@ -274,7 +274,7 @@ function Test-TargetResource ( #region Intune resource parameters - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $Id, @@ -350,7 +350,7 @@ function Test-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - Write-Verbose -Message "Testing configuration of the Intune Device Management Android Google Play Enrollment with Id {$Id} and DisplayName {$DisplayName}" + Write-Verbose -Message "Testing configuration of the Intune Device Management Android Google Play Enrollment with Id {$Id}" $CurrentValues = Get-TargetResource @PSBoundParameters $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.psm1 index e0b3ae74d1..772fa36435 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.psm1 @@ -20,6 +20,10 @@ function Get-TargetResource [System.String] $AfterRuleCountQuery, + [Parameter()] + [System.String] + $Filter, + [Parameter()] [System.Management.Automation.PSCredential] $Credential, @@ -72,6 +76,10 @@ function Set-TargetResource [System.String] $AfterRuleCountQuery, + [Parameter()] + [System.String] + $Filter, + [Parameter()] [System.Management.Automation.PSCredential] $Credential, @@ -125,6 +133,10 @@ function Test-TargetResource [System.String] $AfterRuleCountQuery, + [Parameter()] + [System.String] + $Filter, + [Parameter()] [System.Management.Automation.PSCredential] $Credential, @@ -183,6 +195,10 @@ function Test-TargetResource { $params.Add('AccessTokens', $PSBoundParameters.AccessTokens) } + if ($null -ne $PSBoundParameters.Filter) + { + $params.Add('Filter', $Filter) + } Write-Verbose -Message "Importing module from Path {$($module)}" Import-Module $module -Force -Function 'Export-TargetResource' | Out-Null diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.schema.mof index 094e09a844..5adf1094ea 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_M365DSCRuleEvaluation/MSFT_M365DSCRuleEvaluation.schema.mof @@ -5,6 +5,7 @@ class MSFT_M365DSCRuleEvaluation : OMI_BaseResource [Key, Description("Specify the rules to monitor the resource for.")] String RuleDefinition; [Write, Description("Custom display name for the rule. This will show up in the logs on drift detection.")] String RuleName; [Write, Description("Query to check how many instances exist, using PowerShell format")] String AfterRuleCountQuery; + [Write, Description("Specifies a filter for the current resource type to be evaluated. This reduces the overall set of instances the rule will be evaluated against.")] String Filter; [Write, Description("Credentials of the Azure Active Directory Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.psm1 index bcf2365adf..2433d1b0e9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.psm1 @@ -807,6 +807,12 @@ function Get-TargetResource $RaiseAuditAlertValue = [Boolean]::Parse($tenantSettings.FeatureSettings.RaiseAuditAlert) } + $MDATPTriageStatusValue = @() + if (-not [System.String]::IsNullOrEmpty($tenantSettings.IntelligentDetections.MDATPTriageStatus)) + { + $MDATPTriageStatusValue = [Array]($tenantSettings.IntelligentDetections.MDATPTriageStatus.Replace('"', '').Replace('[', '').Replace(']', '').Split(',')) + } + $tenantSettingsHash = @{ Anonymization = $AnonymizationValue DLPUserRiskSync = $DLPUserRiskSyncValue @@ -814,7 +820,7 @@ function Get-TargetResource RaiseAuditAlert = $RaiseAuditAlertValue FileVolCutoffLimits = $tenantSettings.IntelligentDetections.FileVolCutoffLimits AlertVolume = $tenantSettings.IntelligentDetections.AlertVolume - MDATPTriageStatus = $tenantSettings.IntelligentDetections.MDATPTriageStatus + MDATPTriageStatus = $MDATPTriageStatusValue AnomalyDetections = ($tenantSettings.Indicators | Where-Object -FilterScript { $_.Name -eq 'AnomalyDetections' }).Enabled CopyToPersonalCloud = ($tenantSettings.Indicators | Where-Object -FilterScript { $_.Name -eq 'CopyToPersonalCloud' }).Enabled CopyToUSB = ($tenantSettings.Indicators | Where-Object -FilterScript { $_.Name -eq 'CopyToUSB' }).Enabled @@ -1843,8 +1849,18 @@ function Set-TargetResource } # Tenant Settings + $MDATPTriageStatusValue = "[" + foreach ($status in $MDATPTriageStatus) + { + $MDATPTriageStatusValue += "\`"$($status)\`"," + } + if ($MDATPTriageStatusValue.EndsWith(',')) + { + $MDATPTriageStatusValue = $MDATPTriageStatusValue.Substring(0, $MDATPTriageStatusValue.Length -1) + } + $MDATPTriageStatusValue += "]" $featureSettingsValue = "{`"Anonymization`":$($Anonymization.ToString().ToLower()), `"DLPUserRiskSync`":$($DLPUserRiskSync.ToString().ToLower()), `"OptInIRMDataExport`":$($OptInIRMDataExport.ToString().ToLower()), `"RaiseAuditAlert`":$($RaiseAuditAlert.ToString().ToLower()), `"EnableTeam`":$($EnableTeam.ToString().ToLower())}" - $intelligentDetectionValue = "{`"FileVolCutoffLimits`":`"$($FileVolCutoffLimits)`", `"AlertVolume`":`"$($AlertVolume)`", `"MDATPTriageStatus`": `"$($MDATPTriageStatus)`"}" + $intelligentDetectionValue = "{`"FileVolCutoffLimits`":`"$($FileVolCutoffLimits)`", `"AlertVolume`":`"$($AlertVolume)`", `"MDATPTriageStatus`": `"$($MDATPTriageStatusValue)`"}" $tenantSettingsValue = "{`"Region`":`"WW`", `"FeatureSettings`":$($featureSettingsValue), " + ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.schema.mof index af9a3b71e8..389493261b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCInsiderRiskPolicy/MSFT_SCInsiderRiskPolicy.schema.mof @@ -171,7 +171,7 @@ class MSFT_SCInsiderRiskPolicy : OMI_BaseResource [Write, Description("Official documentation to come.")] UInt32 ProfileInScopeTimeSpan; [Write, Description("Official documentation to come.")] UInt32 GPUUtilizationLimit; [Write, Description("Official documentation to come.")] UInt32 CPUUtilizationLimit; - [Write, Description("Official documentation to come.")] String MDATPTriageStatus; + [Write, Description("Official documentation to come.")] String MDATPTriageStatus[]; [Write, Description("Present ensures the instance exists, absent ensures it is removed."), ValueMap{"Absent","Present"}, Values{"Absent","Present"}] string Ensure; [Write, Description("Credentials of the workload's Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 549a6d9934..d4a6573b91 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -853,7 +853,7 @@ function Compare-M365DSCComplexObject } $compareResult = $true - $ordinalComparison = [System.String]::Equals($referenceObject, $differenceObject, [System.StringComparison]::Ordinal) + $ordinalComparison = [System.String]::Equals($referenceObject, $differenceObject, [System.StringComparison]::OrdinalIgnoreCase) if (-not $ordinalComparison) { $compareResult = $false From be085046eb389879e71598d5d917ca7f809d8b74 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 19 Feb 2025 17:31:14 -0500 Subject: [PATCH 25/33] Fixes --- .../MSFT_EXODistributionGroup.psm1 | 11 +++++++++-- ...65DSC.PPDLPPolicyConnectorConfigurations.Tests.ps1 | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 index d573a7fcfd..60f3a497ab 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXODistributionGroup/MSFT_EXODistributionGroup.psm1 @@ -277,8 +277,15 @@ function Get-TargetResource $distributionMembersValue = @() foreach ($member in $distributionGroupMembers) { - $user = Get-User -Identity $member -ErrorAction Stop - $distributionMembersValue += $user.UserPrincipalName + $user = Get-User -Identity $member.DisplayName -ErrorAction SilentlyContinue + if ($null -ne $user) + { + $distributionMembersValue += $user.UserPrincipalName + } + else + { + $distributionMembersValue += $member.DisplayName + } } Write-Verbose -Message "Found existing Distribution Group {$Identity}." diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.PPDLPPolicyConnectorConfigurations.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.PPDLPPolicyConnectorConfigurations.Tests.ps1 index 4aa6e7bc18..a5db1d5a05 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.PPDLPPolicyConnectorConfigurations.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.PPDLPPolicyConnectorConfigurations.Tests.ps1 @@ -259,7 +259,7 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { connectorActionConfigurations = @( @{ connectorId = '/providers/Microsoft.PowerApps/apis/shared_aadinvitationmanager' - defaultConnectorActionRuleBehavior = 'Allow' + defaultConnectorActionRuleBehavior = 'Deny' #Drift actionRules = @( @{ actionId = "CreateInvitation" From c2dc21066e57eee0d9d5ddf47cf7b8f9e5f27c2f Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 19 Feb 2025 23:38:38 +0000 Subject: [PATCH 26/33] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/general/M365DSCRuleEvaluation.md | 1 + docs/docs/resources/security-compliance/SCInsiderRiskPolicy.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/resources/general/M365DSCRuleEvaluation.md b/docs/docs/resources/general/M365DSCRuleEvaluation.md index a543010d45..8e87899d8c 100644 --- a/docs/docs/resources/general/M365DSCRuleEvaluation.md +++ b/docs/docs/resources/general/M365DSCRuleEvaluation.md @@ -8,6 +8,7 @@ | **RuleDefinition** | Key | String | Specify the rules to monitor the resource for. | | | **RuleName** | Write | String | Custom display name for the rule. This will show up in the logs on drift detection. | | | **AfterRuleCountQuery** | Write | String | Query to check how many instances exist, using PowerShell format | | +| **Filter** | Write | String | Specifies a filter for the current resource type to be evaluated. This reduces the overall set of instances the rule will be evaluated against. | | | **Credential** | Write | PSCredential | Credentials of the Azure Active Directory Admin | | | **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | | **TenantId** | Write | String | Id of the Azure Active Directory tenant used for authentication. | | diff --git a/docs/docs/resources/security-compliance/SCInsiderRiskPolicy.md b/docs/docs/resources/security-compliance/SCInsiderRiskPolicy.md index 57b972c764..7f758a81bc 100644 --- a/docs/docs/resources/security-compliance/SCInsiderRiskPolicy.md +++ b/docs/docs/resources/security-compliance/SCInsiderRiskPolicy.md @@ -174,7 +174,7 @@ | **ProfileInScopeTimeSpan** | Write | UInt32 | Official documentation to come. | | | **GPUUtilizationLimit** | Write | UInt32 | Official documentation to come. | | | **CPUUtilizationLimit** | Write | UInt32 | Official documentation to come. | | -| **MDATPTriageStatus** | Write | String | Official documentation to come. | | +| **MDATPTriageStatus** | Write | StringArray[] | Official documentation to come. | | | **Ensure** | Write | String | Present ensures the instance exists, absent ensures it is removed. | `Absent`, `Present` | | **Credential** | Write | PSCredential | Credentials of the workload's Admin | | | **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | From c1abde9e22753bf82d6e123c0f40c59f219350bd Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 19 Feb 2025 23:40:39 +0000 Subject: [PATCH 27/33] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index 2bb42d5ccc..b3310a4c38 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -53558,6 +53558,11 @@ "Name": "AfterRuleCountQuery", "Option": "Write" }, + { + "CIMType": "String", + "Name": "Filter", + "Option": "Write" + }, { "CIMType": "MSFT_Credential", "Name": "Credential", @@ -58819,7 +58824,7 @@ "Option": "Write" }, { - "CIMType": "String", + "CIMType": "String[]", "Name": "MDATPTriageStatus", "Option": "Write" }, From a3badbb6c150575caf4f076c9ca410e28e6ead3e Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Wed, 19 Feb 2025 23:58:32 +0000 Subject: [PATCH 28/33] Updated Resources and Cmdlet documentation pages --- docs/docs/resources/azure-ad/AADAccessReviewPolicy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/resources/azure-ad/AADAccessReviewPolicy.md b/docs/docs/resources/azure-ad/AADAccessReviewPolicy.md index 2814c66bfc..01311aa922 100644 --- a/docs/docs/resources/azure-ad/AADAccessReviewPolicy.md +++ b/docs/docs/resources/azure-ad/AADAccessReviewPolicy.md @@ -39,7 +39,7 @@ To authenticate with the Microsoft Graph API, this resource required the followi - **Read** - - Policy.Read.All + - Policy.Read.All, AccessReview.Read.All - **Update** From cb0c26896ea7076a5d239951e5ee63a41b8f1431 Mon Sep 17 00:00:00 2001 From: Mike Poulson Date: Wed, 19 Feb 2025 21:05:53 -0800 Subject: [PATCH 29/33] Update AADGroupEligibilitySchedule unit tests --- ...5DSC.AADGroupEligibilitySchedule.Tests.ps1 | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroupEligibilitySchedule.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroupEligibilitySchedule.Tests.ps1 index 40605f742d..a004f0e4dd 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroupEligibilitySchedule.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADGroupEligibilitySchedule.Tests.ps1 @@ -131,6 +131,15 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + Mock -CommandName Get-MgBetaDirectoryObjectById -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.group' + displayName = 'FakeStringValue' + } + } + } + Mock -CommandName New-MgBetaIdentityGovernancePrivilegedAccessGroupEligibilityScheduleRequest -MockWith { return $null } @@ -193,6 +202,15 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + Mock -CommandName Get-MgBetaDirectoryObjectById -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.group' + displayName = 'FakePrincipal' + } + } + } + Mock -CommandName Invoke-GraphRequest -MockWith { return @{ AccessId = 'member' @@ -266,6 +284,15 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } } + Mock -CommandName Get-MgBetaDirectoryObjectById -MockWith { + return @{ + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.group' + displayName = 'FakeStringValue' + } + } + } + Mock -CommandName Invoke-GraphRequest -MockWith { return @{ AccessId = 'member' From f22bc8e0b0c45730826378a68e1388033996c371 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Thu, 20 Feb 2025 12:14:36 +0000 Subject: [PATCH 30/33] Updated Resources and Cmdlet documentation pages --- ...eviceCompliancePolicyAndroidDeviceOwner.md | 22 ++++++++++++++++++ ...eviceCompliancePolicyAndroidWorkProfile.md | 23 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidDeviceOwner.md b/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidDeviceOwner.md index 674e6e1ce3..c42cddacf0 100644 --- a/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidDeviceOwner.md +++ b/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidDeviceOwner.md @@ -7,6 +7,16 @@ | **DisplayName** | Key | String | Display name of the Android Device Owner device compliance policy. | | | **Description** | Write | String | Description of the Android Device Owner device compliance policy. | | | **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Assignments of the Intune Policy. | | +| **MinAndroidSecurityPatchLevel** | Write | String | Minimum Android security patch level. | | +| **PasswordMinimumLetterCharacters** | Write | UInt32 | Indicates the minimum number of letter characters required for device password. Valid values 1 to 16. | | +| **PasswordMinimumLowerCaseCharacters** | Write | UInt32 | Indicates the minimum number of lower case characters required for device password. Valid values 1 to 16. | | +| **PasswordMinimumNonLetterCharacters** | Write | UInt32 | Indicates the minimum number of non-letter characters required for device password. Valid values 1 to 16. | | +| **PasswordMinimumNumericCharacters** | Write | UInt32 | Indicates the minimum number of numeric characters required for device password. Valid values 1 to 16. | | +| **PasswordMinimumSymbolCharacters** | Write | UInt32 | Indicates the minimum number of symbol characters required for device password. Valid values 1 to 16. | | +| **PasswordMinimumUpperCaseCharacters** | Write | UInt32 | Indicates the minimum number of upper case letter characters required for device password. Valid values 1 to 16. | | +| **RequireNoPendingSystemUpdates** | Write | Boolean | Require device to have no pending Android system updates. | | +| **SecurityRequiredAndroidSafetyNetEvaluationType** | Write | String | Require a specific Play Integrity evaluation type for compliance. Possible values are: basic, hardwareBacked. | `basic`, `hardwareBacked` | +| **ScheduledActionsForRule** | Write | MSFT_scheduledActionConfigurations[] | Specifies the non-compliance actions. | | | **DeviceThreatProtectionEnabled** | Write | Boolean | DeviceThreatProtectionEnabled of the Android Device Owner device compliance policy. | | | **DeviceThreatProtectionRequiredSecurityLevel** | Write | String | DeviceThreatProtectionRequiredSecurityLevel of the Android Device Owner device compliance policy. | | | **AdvancedThreatProtectionRequiredSecurityLevel** | Write | String | AdvancedThreatProtectionRequiredSecurityLevel of the Android Device Owner device compliance policy. | | @@ -45,6 +55,18 @@ | **groupDisplayName** | Write | String | The group Display Name that is the target of the assignment. | | | **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | +### MSFT_scheduledActionConfigurations + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **id** | Write | String | The unique identifier of the action configuration. | | +| **gracePeriodHours** | Write | UInt32 | Number of hours to wait till the action will be enforced. Valid values 0 to 8760. | | +| **actionType** | Write | String | The action to take. | `notification`, `block`, `retire`, `remoteLock`, `pushNotification` | +| **notificationTemplateId** | Write | String | The notification Message template to use. | | +| **notificationMessageCCList** | Write | StringArray[] | A list of group IDs to specify who to CC this notification message to. | | + ## Description This resource configures the settings of Android Work Profile device compliance policies diff --git a/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidWorkProfile.md b/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidWorkProfile.md index be23f3a17d..74f71efc49 100644 --- a/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidWorkProfile.md +++ b/docs/docs/resources/intune/IntuneDeviceCompliancePolicyAndroidWorkProfile.md @@ -7,6 +7,17 @@ | **DisplayName** | Key | String | Display name of the AndroidWorkProfile device compliance policy. | | | **Description** | Write | String | Description of the AndroidWorkProfile device compliance policy. | | | **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Assignments of the Intune Policy. | | +| **RequiredPasswordComplexity** | Write | String | The password complexity types that can be set on Android. One of: NONE, LOW, MEDIUM, HIGH. This is an API targeted to Android 11+. | `none`, `low`, `medium`, `high` | +| **SecurityBlockDeviceAdministratorManagedDevices** | Write | Boolean | Setting securityBlockDeviceAdministratorManagedDevices to true enhances security by preventing devices managed through the legacy device administrator method from accessing corporate resources. | | +| **RestrictedApps** | Write | StringArray[] | Specify applications that users are prohibited from installing or using on their devices. | | +| **WorkProfilePasswordRequiredType** | Write | String | Specifies Android Work Profile password type. | `deviceDefault`, `lowSecurityBiometric`, `required`, `atLeastNumeric`, `numericComplex`, `atLeastAlphabetic`, `atLeastAlphanumeric`, `alphanumericWithSymbols` | +| **WorkProfileRequiredPasswordComplexity** | Write | String | Specifies Android Work Profile password complexity. | `None`, `Low`, `Medium`, `High` | +| **WorkProfileRequirePassword** | Write | Boolean | Specifies if Android Work Profile password is required. | | +| **WorkProfilePreviousPasswordBlockCount** | Write | UInt32 | Specifies the number of previous passwords that cannot be reused in an Android Work Profile compliance policy. | | +| **WorkProfileInactiveBeforeScreenLockInMinutes** | Write | UInt32 | Defines the duration of inactivity (in minutes) after which the screen is locked. | | +| **WorkProfilePasswordMinimumLength** | Write | UInt32 | Specifies the minimum number of characters required in a password for an Android Work Profile. | | +| **WorkProfilePasswordExpirationInDays** | Write | UInt32 | Specifies the number of days before a password expires for an Android Work Profile. | | +| **ScheduledActionsForRule** | Write | MSFT_scheduledActionConfigurations[] | Specifies the non-compliance actions. | | | **PasswordRequired** | Write | Boolean | PasswordRequired of the AndroidWorkProfile device compliance policy. | | | **PasswordMinimumLength** | Write | UInt32 | PasswordMinimumLength of the AndroidWorkProfile device compliance policy. | | | **PasswordRequiredType** | Write | String | PasswordRequiredType of the AndroidWorkProfile device compliance policy. | `deviceDefault`, `alphabetic`, `alphanumeric`, `alphanumericWithSymbols`, `lowSecurityBiometric`, `numeric`, `numericComplex`, `any` | @@ -54,6 +65,18 @@ | **groupDisplayName** | Write | String | The group Display Name that is the target of the assignment. | | | **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | +### MSFT_scheduledActionConfigurations + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **id** | Write | String | The unique identifier of the action configuration. | | +| **gracePeriodHours** | Write | UInt32 | Number of hours to wait till the action will be enforced. Valid values 0 to 8760. | | +| **actionType** | Write | String | The action to take. | `notification`, `block`, `retire`, `remoteLock`, `pushNotification` | +| **notificationTemplateId** | Write | String | The notification Message template to use. | | +| **notificationMessageCCList** | Write | StringArray[] | A list of group IDs to specify who to CC this notification message to. | | + ## Description This resource configures the settings of Android Work Profile device compliance policies From 1035fec2f8b92a638ebb806a142b8dbdb848d2d9 Mon Sep 17 00:00:00 2001 From: NikCharlebois Date: Thu, 20 Feb 2025 12:16:54 +0000 Subject: [PATCH 31/33] Updated Schema Definition --- Modules/Microsoft365DSC/SchemaDefinition.json | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/Modules/Microsoft365DSC/SchemaDefinition.json b/Modules/Microsoft365DSC/SchemaDefinition.json index b3310a4c38..a17501a2ee 100644 --- a/Modules/Microsoft365DSC/SchemaDefinition.json +++ b/Modules/Microsoft365DSC/SchemaDefinition.json @@ -28845,6 +28845,36 @@ } ] }, + { + "ClassName": "MSFT_scheduledActionConfigurations", + "Parameters": [ + { + "CIMType": "String", + "Name": "id", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "gracePeriodHours", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "actionType", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "notificationTemplateId", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "notificationMessageCCList", + "Option": "Write" + } + ] + }, { "ClassName": "MSFT_IntuneDeviceCompliancePolicyAndroidDeviceOwner", "Parameters": [ @@ -28863,6 +28893,56 @@ "Name": "Assignments", "Option": "Write" }, + { + "CIMType": "String", + "Name": "MinAndroidSecurityPatchLevel", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "PasswordMinimumLetterCharacters", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "PasswordMinimumLowerCaseCharacters", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "PasswordMinimumNonLetterCharacters", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "PasswordMinimumNumericCharacters", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "PasswordMinimumSymbolCharacters", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "PasswordMinimumUpperCaseCharacters", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "RequireNoPendingSystemUpdates", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "SecurityRequiredAndroidSafetyNetEvaluationType", + "Option": "Write" + }, + { + "CIMType": "MSFT_scheduledActionConfigurations[]", + "Name": "ScheduledActionsForRule", + "Option": "Write" + }, { "CIMType": "Boolean", "Name": "DeviceThreatProtectionEnabled", @@ -29003,6 +29083,61 @@ "Name": "Assignments", "Option": "Write" }, + { + "CIMType": "String", + "Name": "RequiredPasswordComplexity", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "SecurityBlockDeviceAdministratorManagedDevices", + "Option": "Write" + }, + { + "CIMType": "String[]", + "Name": "RestrictedApps", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "WorkProfilePasswordRequiredType", + "Option": "Write" + }, + { + "CIMType": "String", + "Name": "WorkProfileRequiredPasswordComplexity", + "Option": "Write" + }, + { + "CIMType": "Boolean", + "Name": "WorkProfileRequirePassword", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "WorkProfilePreviousPasswordBlockCount", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "WorkProfileInactiveBeforeScreenLockInMinutes", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "WorkProfilePasswordMinimumLength", + "Option": "Write" + }, + { + "CIMType": "Uint32", + "Name": "WorkProfilePasswordExpirationInDays", + "Option": "Write" + }, + { + "CIMType": "MSFT_scheduledActionConfigurations[]", + "Name": "ScheduledActionsForRule", + "Option": "Write" + }, { "CIMType": "Boolean", "Name": "PasswordRequired", From 9b6455c75eafd2c8003b207ee829e5d337211b64 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 20 Feb 2025 07:27:49 -0500 Subject: [PATCH 32/33] Updated Dependencies --- CHANGELOG.md | 4 +- .../Dependencies/Manifest.psd1 | 46 +++++++++---------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 763c693a0a..69079b9b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ * Reduce call count when reconciling object type FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) * AADServicePrincipal - * Evaluating assigned users based on UPN and not just on DisplayName. + * Evaluating assigned users based on UPN and not just on DisplayName. * FIXES [#5359](https://github.com/microsoft/Microsoft365DSC/issues/5359) AADServicePrincipal fails on Managed Identities when DelegatedPermissions returns 500 response * ADOSecurityPolicy * Fixes an issue where the resource threw an error trying to parse the default @@ -53,6 +53,8 @@ * Remove `Ensure` property from being exported. FIXES [#5781](https://github.com/microsoft/Microsoft365DSC/issues/5781) * DEPENDENCIES + * Updated ExchangeOnlineManagement to version 3.7.1 + * Updated Microsoft.Graph modules to version 2.26.0 * Updated ReverseDSC to version 2.0.0.27 # 1.25.212.2 diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index 10e2ddc694..45baefb6ec 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -22,95 +22,95 @@ }, @{ ModuleName = 'ExchangeOnlineManagement' - RequiredVersion = '3.4.0' + RequiredVersion = '3.7.1' }, @{ ModuleName = 'Microsoft.Graph.Applications' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Applications' - Requiredversion = '2.25.0' + Requiredversion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Authentication' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DeviceManagement' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Devices.CorporateManagement' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DeviceManagement.Administration' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DeviceManagement.Enrollment' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.NetworkAccess' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Identity.DirectoryManagement' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Identity.Governance' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Identity.SignIns' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Reports' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Search' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Teams' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.DeviceManagement.Administration' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.DirectoryObjects' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Groups' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Beta.Groups' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Planner' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Sites' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Users' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'Microsoft.Graph.Users.Actions' - RequiredVersion = '2.25.0' + RequiredVersion = '2.26.0' }, @{ ModuleName = 'MicrosoftTeams' From 78e54115b2b4374f9df3e596d7b5cf4fcfc3316b Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 20 Feb 2025 07:31:03 -0500 Subject: [PATCH 33/33] Release 1.25.219.1 --- CHANGELOG.md | 2 +- Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 60 ++++++++++++++++++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69079b9b7d..bcc7d170f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change log for Microsoft365DSC -# UNRELEASED +# 1.25.219.1 * AADAccessReviewPolicy * Missing AccessReview permission for Application Read access diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index f011c60ccf..618a37d13a 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2025-02-13 +# Generated on: 2025-02-20 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.25.212.2' + ModuleVersion = '1.25.219.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -149,8 +149,60 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = '* MISC - * Fixing connection errors in Power Platforms resources.' + ReleaseNotes = '* AADAccessReviewPolicy + * Missing AccessReview permission for Application Read access + FIXES [#5796](https://github.com/microsoft/Microsoft365DSC/issues/5796) +* AADApplication + * Test-TargetResource logic updated to skip evaluating CIMArrays that are empty + when passed as desired values. +* AADDeviceRegistrationPolicy + * Fixed an issue where the AzureADJoinIsAdminConfigurable was not returned by the + Get-TargetResource function. + * Fix issue setting Selected Users and Groups for Entra Join. + FIXES [#5798](https://github.com/microsoft/Microsoft365DSC/issues/5798) +* AADGroup + * Returns an empty array for roles and licenses from the Get-TargetResource + function instead of null when no instances are found. +* AADRoleEligibilityScheduleRequest + * Reduce call count when reconciling object type + FIXES [#5621](https://github.com/microsoft/Microsoft365DSC/issues/5621) +* AADServicePrincipal + * Evaluating assigned users based on UPN and not just on DisplayName. + * FIXES [#5359](https://github.com/microsoft/Microsoft365DSC/issues/5359) AADServicePrincipal fails on Managed Identities when DelegatedPermissions returns 500 response +* ADOSecurityPolicy + * Fixes an issue where the resource threw an error trying to parse the default + values. +* EXODistributionGroup + * Changed logic to retrieve existing members by UserPrincipalName. +* EXORoleGroup + * Evaluating assigned users based on UPN and not just on DisplayName if they + have an associated mailbox. +* IntuneDeviceManagementEnrollmentAndroidGooglePlay + * Marked the Id property as mandatory in the resource. +* M365DSCRuleEvaluation + * Added support for specifying a Filter property. +* M365DSCUtil + * Add M365DSC prefix to `Remove-EmptyValue`. + * Fixes an issue with `Credential` property being escaped and indentation. + * Adds the possibility to allow variables in strings and no authentication + results update during conversion to final export. + FIXES [#3861](https://github.com/microsoft/Microsoft365DSC/issues/3861) +* SCInsiderRiskPolicy + * Enforces the MDATPTriageStatus to be a string array. +* SCSensitivityLabel + * Fixes invalid accepted content type values. +* TeamsAppPermissionPolicy + * Updated correct Typecasting for AppPresetMeeting and PinnedMessagebarApps + before adding them to the policy +* TeamsAppSetupPolicy + * FIXES [[#5752](https://github.com/microsoft/Microsoft365DSC/issues/5752) +* TeamsM365App + * Remove `Ensure` property from being exported. + FIXES [#5781](https://github.com/microsoft/Microsoft365DSC/issues/5781) +* DEPENDENCIES + * Updated ExchangeOnlineManagement to version 3.7.1 + * Updated Microsoft.Graph modules to version 2.26.0 + * Updated ReverseDSC to version 2.0.0.27' # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false