From 716fc9fcd3a47f124547aeec6ee9c07d7e460446 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Tue, 8 Oct 2024 14:35:20 +0200 Subject: [PATCH] Add Intune Account Protection Policy for Windows10 --- CHANGELOG.md | 6 + ...ntuneAccountProtectionPolicyWindows10.psm1 | 764 ++++++++++++++++++ ...ccountProtectionPolicyWindows10.schema.mof | 63 ++ .../readme.md | 6 + .../settings.json | 32 + .../Modules/M365DSCDRGUtil.psm1 | 122 ++- .../M365DSCResourceGenerator.psm1 | 91 ++- ...AccountProtectionPolicyWindows10.Tests.ps1 | 390 +++++++++ 8 files changed, 1445 insertions(+), 29 deletions(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/settings.json create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicyWindows10.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index a42713a14c..0e0790e272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ * Initial release. * EXOMigrationEndpoint * Initial Release +* IntuneAccountProtectionPolicyWindows10 + * Initial Release + FIXES [#5073](https://github.com/microsoft/Microsoft365DSC/issues/5073) * IntuneAppAndBrowserIsolationPolicyWindows10 * Initial release. FIXES [#3028](https://github.com/microsoft/Microsoft365DSC/issues/3028) @@ -24,6 +27,9 @@ Settings Catalog. FIXES [#5086](https://github.com/microsoft/Microsoft365DSC/issues/5086) * Add Set support for secret Settings Catalog values * Removed unused functions + * Add support for device / user scoped settings. +* ResourceGenerator + * Add support for device / user scoped settings. * DEPENDENCIES * Updated DSCParser to version 2.0.0.11 * Updated ReverseDSC to version 2.0.0.21 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.psm1 new file mode 100644 index 0000000000..5188f9fe59 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.psm1 @@ -0,0 +1,764 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $DeviceSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $UserSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = $null + #region resource generator code + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $Id -ErrorAction SilentlyContinue + + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Account Protection Policy for Windows10 with Id {$Id}" + + if (-not [System.String]::IsNullOrEmpty($DisplayName)) + { + $getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter "Name eq '$DisplayName'" ` + -ErrorAction SilentlyContinue + } + } + #endregion + if ($null -eq $getValue) + { + Write-Verbose -Message "Could not find an Intune Account Protection Policy for Windows10 with Name {$DisplayName}." + return $nullResult + } + $Id = $getValue.Id + Write-Verbose -Message "An Intune Account Protection Policy for Windows10 with Id {$Id} and Name {$DisplayName} was found" + + # Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementConfigurationPolicySetting ` + -DeviceManagementConfigurationPolicyId $Id ` + -ExpandProperty 'settingDefinitions' ` + -ErrorAction Stop + + $policySettings = @{} + $policySettings = Export-IntuneSettingCatalogPolicySettings -Settings $settings -ReturnHashtable $policySettings -ContainsDeviceAndUserSettings + + #region resource generator code + $complexDeviceSettings = @{} + if ($null -ne $policySettings.deviceSettings.lsaCfgFlags) + { + $complexDeviceSettings.Add('LsaCfgFlags', $policySettings.deviceSettings.lsaCfgFlags) + } + if ($null -ne $policySettings.deviceSettings.facialFeaturesUseEnhancedAntiSpoofing) + { + $complexDeviceSettings.Add('FacialFeaturesUseEnhancedAntiSpoofing', $policySettings.deviceSettings.facialFeaturesUseEnhancedAntiSpoofing) + } + if ($null -ne $policySettings.deviceSettings.enablePinRecovery) + { + $complexDeviceSettings.Add('EnablePinRecovery', $policySettings.deviceSettings.enablePinRecovery) + } + if ($null -ne $policySettings.deviceSettings.expiration) + { + $complexDeviceSettings.Add('Expiration', $policySettings.deviceSettings.expiration) + } + if ($null -ne $policySettings.deviceSettings.history) + { + $complexDeviceSettings.Add('History', $policySettings.deviceSettings.history) + } + if ($null -ne $policySettings.deviceSettings.lowercaseLetters) + { + $complexDeviceSettings.Add('LowercaseLetters', $policySettings.deviceSettings.lowercaseLetters) + } + if ($null -ne $policySettings.deviceSettings.maximumPINLength) + { + $complexDeviceSettings.Add('MaximumPINLength', $policySettings.deviceSettings.maximumPINLength) + } + if ($null -ne $policySettings.deviceSettings.minimumPINLength) + { + $complexDeviceSettings.Add('MinimumPINLength', $policySettings.deviceSettings.minimumPINLength) + } + if ($null -ne $policySettings.deviceSettings.specialCharacters) + { + $complexDeviceSettings.Add('SpecialCharacters', $policySettings.deviceSettings.specialCharacters) + } + if ($null -ne $policySettings.deviceSettings.uppercaseLetters) + { + $complexDeviceSettings.Add('UppercaseLetters', $policySettings.deviceSettings.uppercaseLetters) + } + if ($null -ne $policySettings.deviceSettings.requireSecurityDevice) + { + $complexDeviceSettings.Add('RequireSecurityDevice', $policySettings.deviceSettings.requireSecurityDevice) + } + if ($null -ne $policySettings.deviceSettings.useCertificateForOnPremAuth) + { + $complexDeviceSettings.Add('UseCertificateForOnPremAuth', $policySettings.deviceSettings.useCertificateForOnPremAuth) + } + if ($null -ne $policySettings.deviceSettings.usePassportForWork) + { + $complexDeviceSettings.Add('UsePassportForWork', $policySettings.deviceSettings.usePassportForWork) + } + if ($complexDeviceSettings.Values.Where({ $_ -ne $null }).Count -eq 0) + { + $complexDeviceSettings = $null + } + + $complexUserSettings = @{} + if ($null -ne $policySettings.userSettings.enablePinRecovery) + { + $complexUserSettings.Add('EnablePinRecovery', $policySettings.userSettings.enablePinRecovery) + } + if ($null -ne $policySettings.userSettings.expiration) + { + $complexUserSettings.Add('Expiration', $policySettings.userSettings.expiration) + } + if ($null -ne $policySettings.userSettings.history) + { + $complexUserSettings.Add('History', $policySettings.userSettings.history) + } + if ($null -ne $policySettings.userSettings.lowercaseLetters) + { + $complexUserSettings.Add('LowercaseLetters', $policySettings.userSettings.lowercaseLetters) + } + if ($null -ne $policySettings.userSettings.maximumPINLength) + { + $complexUserSettings.Add('MaximumPINLength', $policySettings.userSettings.maximumPINLength) + } + if ($null -ne $policySettings.userSettings.minimumPINLength) + { + $complexUserSettings.Add('MinimumPINLength', $policySettings.userSettings.minimumPINLength) + } + if ($null -ne $policySettings.userSettings.specialCharacters) + { + $complexUserSettings.Add('SpecialCharacters', $policySettings.userSettings.specialCharacters) + } + if ($null -ne $policySettings.userSettings.uppercaseLetters) + { + $complexUserSettings.Add('UppercaseLetters', $policySettings.userSettings.uppercaseLetters) + } + if ($null -ne $policySettings.userSettings.requireSecurityDevice) + { + $complexUserSettings.Add('RequireSecurityDevice', $policySettings.userSettings.requireSecurityDevice) + } + if ($null -ne $policySettings.userSettings.usePassportForWork) + { + $complexUserSettings.Add('UsePassportForWork', $policySettings.userSettings.usePassportForWork) + } + if ($complexUserSettings.Values.Where({ $_ -ne $null }).Count -eq 0) + { + $complexUserSettings = $null + } + + $policySettings.Remove('deviceSettings') | Out-Null + $policySettings.Remove('userSettings') | Out-Null + #endregion + + $results = @{ + #region resource generator code + Description = $getValue.Description + DisplayName = $getValue.Name + RoleScopeTagIds = $getValue.RoleScopeTagIds + Id = $getValue.Id + DeviceSettings = $complexDeviceSettings + UserSettings = $complexUserSettings + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + #endregion + } + $results += $policySettings + + $assignmentsValues = Get-MgBetaDeviceManagementConfigurationPolicyAssignment -DeviceManagementConfigurationPolicyId $Id + $assignmentResult = @() + if ($assignmentsValues.Count -gt 0) + { + $assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments $assignmentsValues -IncludeDeviceFilter $true + } + $results.Add('Assignments', $assignmentResult) + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $DeviceSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $UserSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentInstance = Get-TargetResource @PSBoundParameters + + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + $templateReferenceId = 'fcef01f2-439d-4c3f-9184-823fd6e97646_1' + $platforms = 'windows10' + $technologies = 'mdm' + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Account Protection Policy for Windows10 with Name {$DisplayName}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId ` + -ContainsDeviceAndUserSettings + + $createParameters = @{ + Name = $DisplayName + Description = $Description + TemplateReference = @{ templateId = $templateReferenceId } + Platforms = $platforms + Technologies = $technologies + Settings = $settings + } + + #region resource generator code + $policy = New-MgBetaDeviceManagementConfigurationPolicy -BodyParameter $createParameters + + if ($policy.Id) + { + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $policy.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Intune Account Protection Policy for Windows10 with Id {$($currentInstance.Id)}" + $BoundParameters.Remove("Assignments") | Out-Null + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$BoundParameters) ` + -TemplateId $templateReferenceId ` + -ContainsDeviceAndUserSettings + + Update-IntuneDeviceConfigurationPolicy ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Name $DisplayName ` + -Description $Description ` + -TemplateReferenceId $templateReferenceId ` + -Platforms $platforms ` + -Technologies $technologies ` + -Settings $settings + + #region resource generator code + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentInstance.Id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/configurationPolicies' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Intune Account Protection Policy for Windows10 with Id {$($currentInstance.Id)}" + #region resource generator code + Remove-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $DeviceSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $UserSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $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 the Intune Account Protection Policy for Windows10 with Id {$Id} and Name {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + [Hashtable]$ValuesToCheck = @{} + $MyInvocation.MyCommand.Parameters.GetEnumerator() | ForEach-Object { + if ($_.Key -notlike '*Variable' -or $_.Key -notin @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction')) + { + if ($null -ne $CurrentValues[$_.Key] -or $null -ne $PSBoundParameters[$_.Key]) + { + $ValuesToCheck.Add($_.Key, $null) + if (-not $PSBoundParameters.ContainsKey($_.Key)) + { + $PSBoundParameters.Add($_.Key, $null) + } + } + } + } + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($null -ne $source -and $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)" + + if ($testResult) + { + $testResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + } + + Write-Verbose -Message "Test-TargetResource returned $testResult" + + return $testResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace('MSFT_', '') + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + #region resource generator code + $policyTemplateID = "fcef01f2-439d-4c3f-9184-823fd6e97646_1" + [array]$getValue = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter $Filter ` + -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { + $_.TemplateReference.TemplateId -eq $policyTemplateID + } + #endregion + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + $displayedKey = $config.Id + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + elseif (-not [string]::IsNullOrEmpty($config.name)) + { + $displayedKey = $config.name + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + DisplayName = $config.Name + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + if ($null -ne $Results.DeviceSettings) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.DeviceSettings ` + -CIMInstanceName 'MicrosoftGraphIntuneSettingsCatalogDeviceSettings' + if (-not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.DeviceSettings = $complexTypeStringResult + } + else + { + $Results.Remove('DeviceSettings') | Out-Null + } + } + if ($null -ne $Results.UserSettings) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.UserSettings ` + -CIMInstanceName 'MicrosoftGraphIntuneSettingsCatalogUserSettings' + if (-not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.UserSettings = $complexTypeStringResult + } + else + { + $Results.Remove('UserSettings') | Out-Null + } + } + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + if ($Results.DeviceSettings) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "DeviceSettings" -IsCIMArray:$True + } + if ($Results.UserSettings) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "UserSettings" -IsCIMArray:$True + } + + if ($Results.Assignments) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "Assignments" -IsCIMArray:$true + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.schema.mof new file mode 100644 index 0000000000..269777f6a7 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/MSFT_IntuneAccountProtectionPolicyWindows10.schema.mof @@ -0,0 +1,63 @@ +[ClassVersion("1.0.0.0")] +class MSFT_DeviceManagementConfigurationPolicyAssignments +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType; + [Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude."), ValueMap{"none","include","exclude"}, Values{"none","include","exclude"}] String deviceAndAppManagementAssignmentFilterType; + [Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [Write, Description("The group Id that is the target of the assignment.")] String groupId; + [Write, Description("The group Display Name that is the target of the assignment.")] String groupDisplayName; + [Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; + +[ClassVersion("1.0.0.0")] +class MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings +{ + [Write, Description("Credential Guard (0: (Disabled) Turns off Credential Guard remotely if configured previously without UEFI Lock., 1: (Enabled with UEFI lock) Turns on Credential Guard with UEFI lock., 2: (Enabled without lock) Turns on Credential Guard without UEFI lock.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String LsaCfgFlags; + [Write, Description("Facial Features Use Enhanced Anti Spoofing (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String FacialFeaturesUseEnhancedAntiSpoofing; + [Write, Description("Enable Pin Recovery (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String EnablePinRecovery; + [Write, Description("Expiration")] SInt32 Expiration; + [Write, Description("PIN History")] SInt32 History; + [Write, Description("Lowercase Letters (0: Allows the use of lowercase letters in PIN., 1: Requires the use of at least one lowercase letters in PIN., 2: Does not allow the use of lowercase letters in PIN.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String LowercaseLetters; + [Write, Description("Maximum PIN Length")] SInt32 MaximumPINLength; + [Write, Description("Minimum PIN Length")] SInt32 MinimumPINLength; + [Write, Description("Special Characters (0: Allows the use of special characters in PIN., 1: Requires the use of at least one special characters in PIN., 2: Does not allow the use of special characters in PIN.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String SpecialCharacters; + [Write, Description("Uppercase Letters (0: Allows the use of uppercase letters in PIN., 1: Requires the use of at least one uppercase letters in PIN., 2: Does not allow the use of uppercase letters in PIN.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String UppercaseLetters; + [Write, Description("Require Security Device (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String RequireSecurityDevice; + [Write, Description("Use Certificate For On Prem Auth (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String UseCertificateForOnPremAuth; + [Write, Description("Use Windows Hello For Business (Device) (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String UsePassportForWork; +}; + +[ClassVersion("1.0.0.0")] +class MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings +{ + [Write, Description("Enable Pin Recovery (User) (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String EnablePinRecovery; + [Write, Description("Expiration (User)")] SInt32 Expiration; + [Write, Description("PIN History (User)")] SInt32 History; + [Write, Description("Lowercase Letters (User) (0: Allows the use of lowercase letters in PIN., 1: Requires the use of at least one lowercase letters in PIN., 2: Does not allow the use of lowercase letters in PIN.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String LowercaseLetters; + [Write, Description("Maximum PIN Length (User)")] SInt32 MaximumPINLength; + [Write, Description("Minimum PIN Length (User)")] SInt32 MinimumPINLength; + [Write, Description("Special Characters (User) (0: Allows the use of special characters in PIN., 1: Requires the use of at least one special characters in PIN., 2: Does not allow the use of special characters in PIN.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String SpecialCharacters; + [Write, Description("Uppercase Letters (User) (0: Allows the use of uppercase letters in PIN., 1: Requires the use of at least one uppercase letters in PIN., 2: Does not allow the use of uppercase letters in PIN.)"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] String UppercaseLetters; + [Write, Description("Require Security Device (User) (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String RequireSecurityDevice; + [Write, Description("Use Windows Hello For Business (User) (false: Disabled, true: Enabled)"), ValueMap{"false", "true"}, Values{"false", "true"}] String UsePassportForWork; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneAccountProtectionPolicyWindows10")] +class MSFT_IntuneAccountProtectionPolicyWindows10 : OMI_BaseResource +{ + [Write, Description("Policy description")] String Description; + [Key, Description("Policy name")] String DisplayName; + [Write, Description("List of Scope Tags for this Entity instance.")] String RoleScopeTagIds[]; + [Write, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("The policy settings for the device scope."), EmbeddedInstance("MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings")] String DeviceSettings; + [Write, Description("The policy settings for the user scope"), EmbeddedInstance("MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings")] String UserSettings; + [Write, Description("Represents the assignment to the Intune policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the 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; + [Write, Description("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [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_IntuneAccountProtectionPolicyWindows10/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/readme.md new file mode 100644 index 0000000000..893c5522f1 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/readme.md @@ -0,0 +1,6 @@ + +# IntuneAccountProtectionPolicyWindows10 + +## Description + +Intune Account Protection Policy for Windows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/settings.json new file mode 100644 index 0000000000..a20915a6b7 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicyWindows10/settings.json @@ -0,0 +1,32 @@ +{ + "resourceName":"IntuneAccountProtectionPolicyWindows10", + "description":"This resource configures an Intune Account Protection Policy for Windows10.", + "permissions":{ + "graph":{ + "delegated":{ + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + } + ], + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + } + ] + }, + "application":{ + "read":[ + { + "name":"DeviceManagementConfiguration.Read.All" + } + ], + "update":[ + { + "name":"DeviceManagementConfiguration.ReadWrite.All" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index 8d1e1f69d7..39f5223814 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -794,10 +794,20 @@ function Convert-M365DSCDRGComplexTypeToHashtable [OutputType([hashtable], [hashtable[]])] param( [Parameter(Mandatory = $true)] - $ComplexObject + [AllowNull()] + $ComplexObject, + + [Parameter()] + [switch] + $SingleLevel ) - if ($ComplexObject.getType().Fullname -like '*[[\]]') + if ($null -eq $ComplexObject) + { + return @{} + } + + if ($ComplexObject.GetType().Fullname -like '*[[\]]') { $results = @() foreach ($item in $ComplexObject) @@ -816,11 +826,16 @@ function Convert-M365DSCDRGComplexTypeToHashtable if ($null -ne $hashComplexObject) { - $results = $hashComplexObject.clone() + $results = $hashComplexObject.Clone() + if ($SingleLevel) + { + return [hashtable]$results + } + $keys = $hashComplexObject.Keys | Where-Object -FilterScript { $_ -ne 'PSComputerName' } foreach ($key in $keys) { - if ($hashComplexObject[$key] -and $hashComplexObject[$key].getType().Fullname -like '*CimInstance*') + if ($hashComplexObject[$key] -and $hashComplexObject[$key].GetType().Fullname -like '*CimInstance*') { $results[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $hashComplexObject[$key] } @@ -828,11 +843,12 @@ function Convert-M365DSCDRGComplexTypeToHashtable { $propertyName = $key[0].ToString().ToLower() + $key.Substring(1, $key.Length - 1) $propertyValue = $results[$key] - $results.remove($key) | Out-Null + $results.Remove($key) | Out-Null $results.Add($propertyName, $propertyValue) } } } + return [hashtable]$results } @@ -1262,9 +1278,24 @@ function Get-IntuneSettingCatalogPolicySetting [Parameter(Mandatory = 'true')] [System.Collections.Hashtable] $DSCParams, - [Parameter(Mandatory = 'true')] + + [Parameter( + Mandatory = 'true', + ParameterSetName = 'Start' + )] [System.String] - $TemplateId + $TemplateId, + + [Parameter( + Mandatory = 'true', + ParameterSetName = 'DeviceAndUserSettings' + )] + [System.Array] + $SettingTemplates, + + [Parameter(ParameterSetName = 'Start')] + [switch] + $ContainsDeviceAndUserSettings ) $global:excludedDefinitionIds = @() @@ -1273,18 +1304,38 @@ function Get-IntuneSettingCatalogPolicySetting $DSCParams.Remove('DisplayName') | Out-Null $DSCParams.Remove('Description') | Out-Null - # Prepare setting definitions mapping - $settingTemplates = Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate ` - -DeviceManagementConfigurationPolicyTemplateId $TemplateId ` - -ExpandProperty 'SettingDefinitions' ` - -All $settingInstances = @() + if ($PSCmdlet.ParameterSetName -eq 'Start') + { + # Prepare setting definitions mapping + $SettingTemplates = Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate ` + -DeviceManagementConfigurationPolicyTemplateId $TemplateId ` + -ExpandProperty 'SettingDefinitions' ` + -All + + if ($ContainsDeviceAndUserSettings) + { + $deviceSettingTemplates = $SettingTemplates | Where-object -FilterScript { + $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("device_") + } + $userSettingTemplates = $SettingTemplates | Where-object -FilterScript { + $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("user_") + } + $deviceDscParams = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.DeviceSettings -SingleLevel + $userDscParams = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.UserSettings -SingleLevel + $combinedSettingInstances = @() + $combinedSettingInstances += Get-IntuneSettingCatalogPolicySetting -DSCParams $deviceDscParams -SettingTemplates $deviceSettingTemplates + $combinedSettingInstances += Get-IntuneSettingCatalogPolicySetting -DSCParams $userDscParams -SettingTemplates $userSettingTemplates + + return ,$combinedSettingInstances + } + } # Iterate over all setting instance templates in the setting template - foreach ($settingInstanceTemplate in $settingTemplates.SettingInstanceTemplate) + foreach ($settingInstanceTemplate in $SettingTemplates.SettingInstanceTemplate) { $settingInstance = @{} - $settingDefinition = $settingTemplates.SettingDefinitions | Where-Object { + $settingDefinition = $SettingTemplates.SettingDefinitions | Where-Object { $_.Id -eq $settingInstanceTemplate.SettingDefinitionId -and ` ($_.AdditionalProperties.dependentOn.Count -eq 0 -and $_.AdditionalProperties.options.dependentOn.Count -eq 0) } @@ -2088,14 +2139,51 @@ function Export-IntuneSettingCatalogPolicySettings [Parameter( ParameterSetName = 'Setting' )] - [switch]$IsRoot + [switch]$IsRoot, + + [Parameter( + ParameterSetName = 'Start' + )] + [switch]$ContainsDeviceAndUserSettings ) if ($PSCmdlet.ParameterSetName -eq 'Start') { - foreach ($setting in $Settings) + if ($ContainsDeviceAndUserSettings) + { + $deviceSettingsReturnHashtable = @{} + $deviceSettings = $Settings | Where-Object -FilterScript { + $_.SettingInstance.settingDefinitionId.StartsWith("device_") + } + foreach ($setting in $deviceSettings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $setting.SettingInstance -SettingDefinitions $setting.SettingDefinitions -ReturnHashtable $deviceSettingsReturnHashtable -AllSettingDefinitions $deviceSettings.SettingDefinitions -IsRoot + } + + $userSettings = $Settings | Where-Object -FilterScript { + $_.SettingInstance.settingDefinitionId.StartsWith("user_") + } + $userSettingsReturnHashtable = @{} + foreach ($setting in $userSettings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $setting.SettingInstance -SettingDefinitions $setting.SettingDefinitions -ReturnHashtable $userSettingsReturnHashtable -AllSettingDefinitions $userSettings.SettingDefinitions -IsRoot + } + + if ($deviceSettingsReturnHashtable.Keys.Count -gt 0) + { + $ReturnHashtable.Add('DeviceSettings', $deviceSettingsReturnHashtable) + } + if ($userSettingsReturnHashtable.Keys.Count -gt 0) + { + $ReturnHashtable.Add('UserSettings', $userSettingsReturnHashtable) + } + } + else { - Export-IntuneSettingCatalogPolicySettings -SettingInstance $setting.SettingInstance -SettingDefinitions $setting.SettingDefinitions -ReturnHashtable $ReturnHashtable -AllSettingDefinitions $Settings.SettingDefinitions -IsRoot + foreach ($setting in $Settings) + { + Export-IntuneSettingCatalogPolicySettings -SettingInstance $setting.SettingInstance -SettingDefinitions $setting.SettingDefinitions -ReturnHashtable $ReturnHashtable -AllSettingDefinitions $Settings.SettingDefinitions -IsRoot + } } return $ReturnHashtable } diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index ecdccf6a86..fbe1658771 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -245,20 +245,87 @@ function New-M365DSCResource } $templateSettings = @() - $allSettingDefinitions = $SettingsCatalogSettingTemplates.SettingDefinitions - foreach ($settingTemplate in $SettingsCatalogSettingTemplates) + $deviceSettingsCatalogTemplates = $SettingsCatalogSettingTemplates | Where-Object -FilterScript { $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("device_") } + $deviceSettingDefinitions = $deviceSettingsCatalogTemplates.SettingDefinitions + + $userSettingsCatalogTemplates = $SettingsCatalogSettingTemplates | Where-Object -FilterScript { $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("user_") } + $userSettingDefinitions = $userSettingsCatalogTemplates.SettingDefinitions + + $containsDeviceAndUserSettings = $false + if ($deviceSettingDefinitions.Count -gt 0 -and $userSettingDefinitions.Count -gt 0) + { + $containsDeviceAndUserSettings = $true + } + + $deviceTemplateSettings = @() + foreach ($deviceSettingTemplate in $deviceSettingsCatalogTemplates) { - $templateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` + $deviceTemplateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` -FromRoot ` - -SettingTemplate $settingTemplate ` - -AllSettingDefinitions $allSettingDefinitions + -SettingTemplate $deviceSettingTemplate ` + -AllSettingDefinitions $deviceSettingDefinitions + } + + $userTemplateSettings = @() + foreach ($userSettingTemplate in $userSettingsCatalogTemplates) + { + $userTemplateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate ` + -FromRoot ` + -SettingTemplate $userSettingTemplate ` + -AllSettingDefinitions $userSettingDefinitions + } + + $deviceDefinitionSettings = @() + foreach ($deviceTemplateSetting in $deviceTemplateSettings) + { + $deviceDefinitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting ` + -TemplateSetting $deviceTemplateSetting + } + + $userDefinitionSettings = @() + foreach ($userTemplateSetting in $userTemplateSettings) + { + $userDefinitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting ` + -TemplateSetting $userTemplateSetting } - $definitionSettings = @() - foreach ($templateSetting in $templateSettings) + if ($containsDeviceAndUserSettings) + { + $definitionSettings = @{ + PowerShell = @( + +@" + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + `$DeviceSettings +"@, +@" + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + `$UserSettings +"@ + ) + MOFInstance = @( +@" +[ClassVersion("1.0.0.0")] +class MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings +{ +$($deviceDefinitionSettings.MOF -join "`r`n") +}; +"@, +@" +[ClassVersion("1.0.0.0")] +class MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings +{ +$($userDefinitionSettings.MOF -join "`r`n") +}; +"@ + ) + } + } + else { - $definitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting ` - -TemplateSetting $templateSetting + $definitionSettings = $deviceDefinitionSettings + $userDefinitionSettings } $parameterString += $definitionSettings.PowerShell -join ",`r`n`r`n" @@ -475,7 +542,7 @@ function New-M365DSCResource -ErrorAction Stop `$policySettings = @{} - `$policySettings = Export-IntuneSettingCatalogPolicySettings -Settings `$settings -ReturnHashtable `$policySettings `r`n + `$policySettings = Export-IntuneSettingCatalogPolicySettings -Settings `$settings -ReturnHashtable `$policySettings$(if ($containsDeviceAndUserSettings) { ' -ContainsDeviceAndUserSettings' })`r`n "@ $settingsCatalogAddSettings = " `$results += `$policySettings`r`n`r`n" } @@ -595,7 +662,7 @@ function New-M365DSCResource $defaultCreateParameters = @" `$settings = Get-IntuneSettingCatalogPolicySetting `` -DSCParams ([System.Collections.Hashtable]`$BoundParameters) `` - -TemplateId `$templateReferenceId + -TemplateId `$templateReferenceId$(if ($containsDeviceAndUserSettings) { " ```r`n -ContainsDeviceAndUserSettings" })`r`n `$createParameters = @{ Name = `$DisplayName @@ -718,7 +785,7 @@ function New-M365DSCResource $defaultUpdateParameters = @" `$settings = Get-IntuneSettingCatalogPolicySetting `` -DSCParams ([System.Collections.Hashtable]`$BoundParameters) `` - -TemplateId `$templateReferenceId + -TemplateId `$templateReferenceId$(if ($containsDeviceAndUserSettings) { " ```r`n -ContainsDeviceAndUserSettings" })`r`n Update-IntuneDeviceConfigurationPolicy `` -DeviceConfigurationPolicyId `$currentInstance.Id `` diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicyWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicyWindows10.Tests.ps1 new file mode 100644 index 0000000000..b83b974567 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicyWindows10.Tests.ps1 @@ -0,0 +1,390 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath '..\..\Unit' ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Microsoft365.psm1' ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\Stubs\Generic.psm1' ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath '\UnitTestHelper.psm1' ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "IntuneAccountProtectionPolicyWindows10" -GenericStubModule $GenericStubPath +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + BeforeAll { + + $secpasswd = ConvertTo-SecureString (New-Guid | Out-String) -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Update-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '12345-12345-12345-12345-12345' + Description = 'My Test' + Name = 'My Test' + RoleScopeTagIds = @("FakeStringValue") + TemplateReference = @{ + TemplateId = 'fcef01f2-439d-4c3f-9184-823fd6e97646_1' + } + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName Update-IntuneDeviceConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-IntuneSettingCatalogPolicySetting -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @( + @{ + Id = '0' + SettingDefinitions = @( + @{ + Id = 'device_vendor_msft_passportforwork_{tenantid}_policies_pincomplexity_history' + Name = 'History' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'device_vendor_msft_passportforwork_{tenantid}' + parentSettingId = 'device_vendor_msft_passportforwork_{tenantid}' + } + ) + } + }, + @{ + Id = 'device_vendor_msft_passportforwork_{tenantid}' + Name = '{TenantId}' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + childIds = @( + 'device_vendor_msft_passportforwork_{tenantid}_policies_pincomplexity_history' + ) + maximumCount = 1 + minimumCount = 0 + } + } + ) + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_passportforwork_{tenantid}' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = '0ece2bdc-57c1-4be9-93e9-ac9c395a9c94' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'device_vendor_msft_passportforwork_{tenantid}_policies_pincomplexity_history' + simpleSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationIntegerSettingValue' + value = '10' + } + } + ) + } + ) + } + } + }, + @{ + Id = '1' + SettingDefinitions = @( + @{ + Id = 'user_vendor_msft_passportforwork_{tenantid}_policies_pincomplexity_history' + Name = 'History' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingDefinition' + dependentOn = @( + @{ + dependentOn = 'user_vendor_msft_passportforwork_{tenantid}' + parentSettingId = 'user_vendor_msft_passportforwork_{tenantid}' + } + ) + } + }, + @{ + Id = 'user_vendor_msft_passportforwork_{tenantid}' + Name = '{TenantId}' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition' + childIds = @( + 'user_vendor_msft_passportforwork_{tenantid}_policies_pincomplexity_history' + ) + maximumCount = 1 + minimumCount = 0 + } + } + ) + SettingInstance = @{ + SettingDefinitionId = 'user_vendor_msft_passportforwork_{tenantid}' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = '0ece2bdc-57c1-4be9-93e9-ac9c395a9c94' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + settingDefinitionId = 'user_vendor_msft_passportforwork_{tenantid}_policies_pincomplexity_history' + simpleSettingValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationIntegerSettingValue' + value = '20' + } + } + ) + } + ) + } + } + } + ) + } + + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyAssignment -MockWith { + return @(@{ + Id = '12345-12345-12345-12345-12345' + Source = 'direct' + SourceId = '12345-12345-12345-12345-12345' + Target = @{ + DeviceAndAppManagementAssignmentFilterId = '12345-12345-12345-12345-12345' + DeviceAndAppManagementAssignmentFilterType = 'none' + AdditionalProperties = @( + @{ + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } + ) + } + }) + } + + } + # Test contexts + Context -Name "The IntuneAccountProtectionPolicyWindows10 should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + DeviceSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings -Property @{ + History = 10 + } -ClientOnly + ) + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + UserSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings -Property @{ + History = 20 + } -ClientOnly + ) + Ensure = "Present" + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return $null + } + } + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + It 'Should Create the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name "The IntuneAccountProtectionPolicyWindows10 exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + DeviceSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings -Property @{ + History = 10 + } -ClientOnly + ) + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + UserSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings -Property @{ + History = 20 + } -ClientOnly + ) + Ensure = "Absent" + Credential = $Credential + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + Context -Name "The IntuneAccountProtectionPolicyWindows10 Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + DeviceSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings -Property @{ + History = 10 + } -ClientOnly + ) + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + UserSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings -Property @{ + History = 20 + } -ClientOnly + ) + Ensure = "Present" + Credential = $Credential + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The IntuneAccountProtectionPolicyWindows10 exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + deviceAndAppManagementAssignmentFilterType = 'none' + } -ClientOnly) + ) + Description = "My Test" + DeviceSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings -Property @{ + History = 10 + } -ClientOnly + ) + Id = "12345-12345-12345-12345-12345" + DisplayName = "My Test" + RoleScopeTagIds = @("FakeStringValue") + UserSettings = [CimInstance]( + New-CimInstance -ClassName MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings -Property @{ + History = 30 # Drift + } -ClientOnly + ) + Ensure = "Present" + Credential = $Credential + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-IntuneDeviceConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope