diff --git a/CHANGELOG.md b/CHANGELOG.md index 958ddb0f81..ab51bfce15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,16 @@ * MISC * Added a QA check to test if all used subclasses actually exist in the MOF schema. +* IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy + * Initial release + FIXES [#3034](https://github.com/microsoft/Microsoft365DSC/issues/3034) 3/3 +* IntuneAccountProtectionLocalUserGroupMembershipPolicy + * Initial release + FIXES [#3034](https://github.com/microsoft/Microsoft365DSC/issues/3034) 2/3 +* IntuneAccountProtectionPolicy + * Initial release + FIXES [#3034](https://github.com/microsoft/Microsoft365DSC/issues/3034) 1/3 + # 1.23.1108.1 * AADExternalIdentityPolicy diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 new file mode 100644 index 0000000000..85d65e10de --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.psm1 @@ -0,0 +1,1244 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 2)] + $BackupDirectory, + + [Parameter()] + [System.Int32] + [ValidateRange(7, 365)] + $PasswordAgeDays_AAD, + + [Parameter()] + [System.Int32] + [ValidateRange(1, 365)] + $PasswordAgeDays, + + [Parameter()] + [System.Boolean] + $PasswordExpirationProtectionEnabled, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 12)] + $AdEncryptedPasswordHistorySize, + + [Parameter()] + [System.Boolean] + $AdPasswordEncryptionEnabled, + + [Parameter()] + [System.String] + $AdPasswordEncryptionPrincipal, + + [Parameter()] + [System.String] + $AdministratorAccountName, + + [Parameter()] + [System.Int32] + [ValidateRange(1, 4)] + $PasswordComplexity, + + [Parameter()] + [System.Int32] + [ValidateRange(8, 64)] + $PasswordLength, + + [Parameter()] + [System.Int32] + [ValidateSet(1, 3, 5)] + $PostAuthenticationActions, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 24)] + $PostAuthenticationResetDelay, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + Write-Verbose -Message "Checking for the Intune Account Protection LAPS Policy {$DisplayName}" + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters ` + -ErrorAction Stop + + #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' + + try + { + #Retrieve policy general settings + $policy = Get-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $Identity -ErrorAction SilentlyContinue + + if ($null -eq $policy) + { + Write-Verbose -Message "No Account Protection LAPS Policy {id: '$Identity'} was found" + $policyTemplateID = 'adc46e5a-f4aa-4ff6-aeff-4f27bc525796_1' + $filter = "name eq '$DisplayName' and templateReference/TemplateId eq '$policyTemplateID'" + $policy = Get-MgBetaDeviceManagementConfigurationPolicy -Filter $filter -ErrorAction SilentlyContinue + if ($null -eq $policy) + { + Write-Verbose -Message "No Account Protection LAPS Policy {displayName: '$DisplayName'} was found" + return $nullResult + } + } + + $Identity = $policy.Id + + Write-Verbose -Message "Found Account Protection LAPS Policy {$($policy.id):$($policy.Name)}" + + #Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementConfigurationPolicySetting ` + -DeviceManagementConfigurationPolicyId $Identity ` + -ErrorAction Stop + + $returnHashtable = @{} + $returnHashtable.Add('Identity', $Identity) + $returnHashtable.Add('DisplayName', $policy.name) + $returnHashtable.Add('Description', $policy.description) + + foreach ($setting in $settings.settingInstance) + { + $addToParameters = $true + $settingName = $setting.settingDefinitionId.Split('_') | Select-Object -Last 1 + $replaceUri = $setting.settingDefinitionId.Replace($settingName, '') + + $settingType = $setting.AdditionalProperties.'@odata.type' + $settingValueName = $settingType.replace('#microsoft.graph.deviceManagementConfiguration', '').replace('Instance', 'Value') + $settingValueName = $settingValueName.Substring(0, 1).ToLower() + $settingValueName.Substring(1, $settingValueName.length - 1 ) + + switch ($settingType) + { + '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance' + { + $settingValue = $setting.AdditionalProperties.simpleSettingValue.value + } + '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + { + $settingValue = $setting.AdditionalProperties.choiceSettingValue.value.split('_') | Select-Object -Last 1 + } + '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + { + $values = @() + foreach ($value in $setting.AdditionalProperties.groupSettingCollectionValue.children) + { + $settingName = $value.settingDefinitionId.split('_') | Select-Object -Last 1 + $settingValue = $value.choiceSettingValue.value.split('_') | Select-Object -Last 1 + $returnHashtable.Add($settingName, $settingValue) + $addToParameters = $false + } + } + '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + { + $values = @() + foreach ($value in $setting.AdditionalProperties.simpleSettingCollectionValue.value) + { + $values += $value + } + $settingValue = $values + } + Default + { + $settingValue = $setting.value + } + } + + foreach ($childSetting in $setting.AdditionalProperties.$settingValueName.children) + { + $childSettingName = $childSetting.settingDefinitionId.Replace($replaceUri, '') + $childSettingType = $childSetting.'@odata.type'.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') + $childSettingType = $childSettingType.Substring(0, 1).ToLower() + $childSettingType.Substring(1, $childSettingType.length - 1 ) + $childSettingValue = $childSetting.$childSettingType.value + + if ($childSettingType -eq 'choiceSettingValue') + { + $childSettingValue = $childSettingValue.split('_') | Select-Object -Last 1 + } + $returnHashtable.Add($childSettingName, $childSettingValue) + } + + if ($addToParameters) + { + $returnHashtable.Add($settingName, $settingValue) + } + + } + $returnAssignments = @() + $returnAssignments += Get-DeviceManagementConfigurationPolicyAssignment -DeviceManagementConfigurationPolicyId $Identity + $returnHashtable.Add('Assignments', $returnAssignments) + + Write-Verbose -Message "Found Account Protection LAPS Policy {$($policy.name)}" + + $returnHashtable.Add('Ensure', 'Present') + $returnHashtable.Add('Credential', $Credential) + $returnHashtable.Add('ApplicationId', $ApplicationId) + $returnHashtable.Add('TenantId', $TenantId) + $returnHashtable.Add('ApplicationSecret', $ApplicationSecret) + $returnHashtable.Add('CertificateThumbprint', $CertificateThumbprint) + $returnHashtable.Add('ManagedIdentity', $ManagedIdentity.IsPresent) + + return $returnHashtable + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 2)] + $BackupDirectory, + + [Parameter()] + [System.Int32] + [ValidateRange(7, 365)] + $PasswordAgeDays_AAD, + + [Parameter()] + [System.Int32] + [ValidateRange(1, 365)] + $PasswordAgeDays, + + [Parameter()] + [System.Boolean] + $PasswordExpirationProtectionEnabled, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 12)] + $AdEncryptedPasswordHistorySize, + + [Parameter()] + [System.Boolean] + $AdPasswordEncryptionEnabled, + + [Parameter()] + [System.String] + $AdPasswordEncryptionPrincipal, + + [Parameter()] + [System.String] + $AdministratorAccountName, + + [Parameter()] + [System.Int32] + [ValidateRange(1, 4)] + $PasswordComplexity, + + [Parameter()] + [System.Int32] + [ValidateRange(8, 64)] + $PasswordLength, + + [Parameter()] + [System.Int32] + [ValidateSet(1, 3, 5)] + $PostAuthenticationActions, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 24)] + $PostAuthenticationResetDelay, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + #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 + + $currentPolicy = 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 + + $templateReferenceId = 'adc46e5a-f4aa-4ff6-aeff-4f27bc525796_1' + $platforms = 'windows10' + $technologies = 'mdm' + + if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating new Account Protection LAPS Policy {$DisplayName}" + + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$PSBoundParameters) ` + -TemplateId $templateReferenceId + + $createParameters = @{ + Name = $DisplayName + Description = $Description + TemplateReference = @{templateId = $templateReferenceId } + Platforms = $platforms + Technologies = $technologies + Settings = $settings + } + $newPolicy = New-MgBetaDeviceManagementConfigurationPolicy -bodyParameter $createParameters + + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $newPolicy.Id ` + -Targets $assignmentsHash + } + elseif ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating existing Account Protection LAPS Policy {$($currentPolicy.DisplayName)}" + + #format settings from PSBoundParameters for update + $settings = Get-IntuneSettingCatalogPolicySetting ` + -DSCParams ([System.Collections.Hashtable]$PSBoundParameters) ` + -TemplateId $templateReferenceId + + Update-DeviceManagementConfigurationPolicy ` + -DeviceManagementConfigurationPolicyId $currentPolicy.Identity ` + -DisplayName $DisplayName ` + -Description $Description ` + -TemplateReference $templateReferenceId ` + -Platforms $platforms ` + -Technologies $technologies ` + -Settings $settings + + #region update policy assignments + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentPolicy.Identity ` + -Targets $assignmentsHash + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentPolicy.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing Account Protection LAPS Policy {$($currentPolicy.DisplayName)}" + Remove-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $currentPolicy.Identity + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 2)] + $BackupDirectory, + + [Parameter()] + [System.Int32] + [ValidateRange(7, 365)] + $PasswordAgeDays_AAD, + + [Parameter()] + [System.Int32] + [ValidateRange(1, 365)] + $PasswordAgeDays, + + [Parameter()] + [System.Boolean] + $PasswordExpirationProtectionEnabled, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 12)] + $AdEncryptedPasswordHistorySize, + + [Parameter()] + [System.Boolean] + $AdPasswordEncryptionEnabled, + + [Parameter()] + [System.String] + $AdPasswordEncryptionPrincipal, + + [Parameter()] + [System.String] + $AdministratorAccountName, + + [Parameter()] + [System.Int32] + [ValidateRange(1, 4)] + $PasswordComplexity, + + [Parameter()] + [System.Int32] + [ValidateRange(8, 64)] + $PasswordLength, + + [Parameter()] + [System.Int32] + [ValidateSet(1, 3, 5)] + $PostAuthenticationActions, + + [Parameter()] + [System.Int32] + [ValidateRange(0, 24)] + $PostAuthenticationResetDelay, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + #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 Account Protection LAPS Policy {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $ValuesToCheck = $PSBoundParameters + $ValuesToCheck.Remove('Identity') | Out-Null + $ValuesToCheck.Remove('Credential') | Out-Null + $ValuesToCheck.Remove('ApplicationId') | Out-Null + $ValuesToCheck.Remove('TenantId') | Out-Null + $ValuesToCheck.Remove('ApplicationSecret') | Out-Null + $ValuesToCheck.Remove('Identity') | Out-Null + + if ($BackupDirectory -eq 0) + { + $ValuesToCheck.Remove('PasswordAgeDays_AAD') | Out-Null + $ValuesToCheck.Remove('PasswordAgeDays') | Out-Null + $ValuesToCheck.Remove('PasswordExpirationProtectionEnabled') | Out-Null + $ValuesToCheck.Remove('AdEncryptedPasswordHistorySize') | Out-Null + $ValuesToCheck.Remove('AdPasswordEncryptionEnabled') | Out-Null + $ValuesToCheck.Remove('AdPasswordEncryptionPrincipal') | Out-Null + } + elseif ($BackupDirectory -eq 1) { + $ValuesToCheck.Remove('PasswordAgeDays') | Out-Null + $ValuesToCheck.Remove('PasswordExpirationProtectionEnabled') | Out-Null + $ValuesToCheck.Remove('AdEncryptedPasswordHistorySize') | Out-Null + $ValuesToCheck.Remove('AdPasswordEncryptionEnabled') | Out-Null + $ValuesToCheck.Remove('AdPasswordEncryptionPrincipal') | Out-Null + } elseif ($BackupDirectory -eq 2) + { + $ValuesToCheck.Remove('PasswordAgeDays_AAD') | Out-Null + } + + $testResult = $true + if ([Array]$Assignments.count -ne $CurrentValues.Assignments.count) + { + Write-Verbose -Message "Configuration drift:Number of assignments does not match: Source=$([Array]$Assignments.count) Target=$($CurrentValues.Assignments.count)" + $testResult = $false + } + if ($testResult) + { + foreach ($assignment in $CurrentValues.Assignments) + { + if ($null -ne $Assignment) + { + #GroupId Assignment + if (-not [String]::IsNullOrEmpty($assignment.groupId)) + { + $source = [Array]$ValuesToCheck.Assignments | Where-Object -FilterScript { $_.groupId -eq $assignment.groupId } + if (-not $source) + { + Write-Verbose -Message "Configuration drift: groupId {$($assignment.groupId)} not found" + $testResult = $false + break + } + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $assignment + } + #AllDevices/AllUsers assignment + else + { + $source = [Array]$ValuesToCheck.Assignments | Where-Object -FilterScript { $_.dataType -eq $assignment.dataType } + if (-not $source) + { + Write-Verbose -Message "Configuration drift: {$($assignment.dataType)} not found" + $testResult = $false + break + } + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $assignment + } + } + + if (-not $testResult) + { + $testResult = $false + break + } + + } + + } + $ValuesToCheck.Remove('Assignments') | Out-Null + + 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 + ) + + $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 + + $dscContent = '' + $i = 1 + + try + { + $policyTemplateID = 'adc46e5a-f4aa-4ff6-aeff-4f27bc525796_1' + [array]$policies = Get-MgBetaDeviceManagementConfigurationPolicy ` + -All:$true ` + -Filter $Filter ` + -ErrorAction Stop | Where-Object -FilterScript { $_.TemplateReference.TemplateId -eq $policyTemplateID } ` + + if ($policies.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($policy in $policies) + { + Write-Host " |---[$i/$($policies.Count)] $($policy.Name)" -NoNewline + + $params = @{ + Identity = $policy.id + DisplayName = $policy.Name + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @params -Verbose + + if ($Results.Ensure -eq 'Present') + { + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject ([Array]$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.Assignments) + { + $isCIMArray = $false + if ($Results.Assignments.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + } + } + return $dscContent + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Unable to perform redirect as Location Header is not set in response*") + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + else + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return '' + } +} + +function Get-IntuneSettingCatalogPolicySetting +{ + [CmdletBinding()] + [OutputType([System.Array])] + param( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $DSCParams, + [Parameter(Mandatory = 'true')] + [System.String] + $TemplateId + ) + + $DSCParams.Remove('Identity') | Out-Null + $DSCParams.Remove('DisplayName') | Out-Null + $DSCParams.Remove('Description') | Out-Null + + #Prepare setting definitions mapping + $settingDefinitions = Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate -DeviceManagementConfigurationPolicyTemplateId $TemplateId -ExpandProperty settingDefinitions + $settingInstances = @() + foreach ($settingDefinition in $settingDefinitions.SettingInstanceTemplate) + { + + $settingInstance = @{} + $settingName = $settingDefinition.SettingDefinitionId.split('_') | Select-Object -Last 1 + $settingType = $settingDefinition.AdditionalProperties.'@odata.type'.replace('InstanceTemplate', 'Instance') + $settingInstance.Add('settingDefinitionId', $settingDefinition.settingDefinitionId) + $settingInstance.Add('@odata.type', $settingType) + if (-Not [string]::IsNullOrEmpty($settingDefinition.settingInstanceTemplateId)) + { + $settingInstance.Add('settingInstanceTemplateReference', @{'settingInstanceTemplateId' = $settingDefinition.settingInstanceTemplateId }) + } + $settingValueName = $settingType.replace('#microsoft.graph.deviceManagementConfiguration', '').replace('Instance', 'Value') + $settingValueName = $settingValueName.Substring(0, 1).ToLower() + $settingValueName.Substring(1, $settingValueName.length - 1 ) + $settingValueType = $settingDefinition.AdditionalProperties."$($settingValueName)Template".'@odata.type' + if ($null -ne $settingValueType) + { + $settingValueType = $settingValueType.replace('ValueTemplate', 'Value') + } + $settingValueTemplateId = $settingDefinition.AdditionalProperties."$($settingValueName)Template".settingValueTemplateId + $settingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` + -DSCParams $DSCParams ` + -SettingDefinition $settingDefinition ` + -SettingName $settingName ` + -SettingType $settingType ` + -SettingValueName $settingValueName ` + -SettingValueType $settingValueType ` + -SettingValueTemplateId $settingValueTemplateId + + if ($null -ne $settingValue) { + + if ($settingType -ne '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance') + { + $settingValue.$settingValueName.Add('children', @()) + + foreach ($childSettingDefinition in ($settingDefinitions.SettingDefinitions | Where-Object { $_.RootDefinitionId -eq $settingInstance.settingDefinitionId })) + { + if ($childSettingDefinition.Id -eq $settingDefinition.SettingDefinitionId) + { + # We have already covered that setting through the settingInstanceTemplate + Continue + } + + $key = $DSCParams.Keys | Where-Object { $_.ToLower() -eq $settingName } + $dscValue = $DSCParams[$key] + + if ($childSettingDefinition.AdditionalProperties.dependentOn.dependentOn -ne ($settingDefinition.SettingDefinitionId + '_' + $dscValue)) + { + if ($childSettingDefinition.AdditionalProperties.options.dependentOn.dependentOn -notContains ($settingDefinition.SettingDefinitionId + '_' + $dscValue)) + { + # This setting is not dependent on the current setting value + Continue + } + } + $childSettingUri = ($childSettingDefinition.BaseUri + $childSettingDefinition.OffsetUri).Replace('/', '_').Replace('._', '').ToLower() + $replaceUri = $childSettingUri.Replace($childSettingUri.Split('_')[-1], '') + + $childSettingInstance = @{} + $childSettingName = $childSettingDefinition.Id.Replace($replaceUri, '') + $childSettingType = $childSettingDefinition.AdditionalProperties.'@odata.type'.replace('Definition', 'Instance') + $childSettingInstance.Add('settingDefinitionId', $childSettingDefinition.Id) + $childSettingInstance.Add('@odata.type', $childSettingType) + $childSettingValueName = $childSettingType.replace('#microsoft.graph.deviceManagementConfiguration', '').replace('Instance', 'Value') + $childSettingValueName = $childSettingValueName.Substring(0, 1).ToLower() + $childSettingValueName.Substring(1, $childSettingValueName.length - 1 ) + if ($null -ne $childSettingDefinition.AdditionalProperties.valueDefinition) + { + $childSettingValueType = $childSettingDefinition.AdditionalProperties.valueDefinition.'@odata.type'.Replace('ValueDefinition', 'Value') + } + else + { + $childSettingValueType = $childSettingType.Replace('Instance', 'Value') + } + $childSettingValue = Get-IntuneSettingCatalogPolicySettingDefinitionValue ` + -DSCParams $DSCParams ` + -SettingDefinition $childSettingDefinition ` + -SettingName $childSettingName ` + -SettingValueName $childSettingValueName ` + -SettingValueType $childSettingValueType ` + + if ($null -ne $childSettingValue) + { + $childSettingInstance += ($childSettingValue) + $settingValue.$settingValueName.children += $childSettingInstance + } + } + } + + $settingInstance += ($settingValue) + $settingInstances += @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + 'settingInstance' = $settingInstance + } + } else { + Continue + } + } + + return $settingInstances +} + +function Get-IntuneSettingCatalogPolicySettingInstanceValue +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $DSCParams, + + [Parameter()] + $SettingDefinition, + + [Parameter()] + [System.String] + $SettingType, + + [Parameter()] + [System.String] + $SettingName, + + [Parameter()] + [System.String] + $SettingValueName, + + [Parameter()] + [System.String] + $SettingValueType, + + [Parameter()] + [System.String] + $SettingValueTemplateId + ) + + $settingValueReturn = @{} + switch ($settingType) + { + '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + { + $groupSettingCollectionValue = @{} + $groupSettingCollectionValueChildren = @() + + $groupSettingCollectionDefinitionChildren = $SettingDefinition.AdditionalProperties.groupSettingCollectionValueTemplate.children + foreach ($childDefinition in $groupSettingCollectionDefinitionChildren) + { + $childSettingName = $childDefinition.settingDefinitionId.split('_') | Select-Object -Last 1 + $childSettingType = $childDefinition.'@odata.type'.replace('InstanceTemplate', 'Instance') + $childSettingValueName = $childSettingType.replace('#microsoft.graph.deviceManagementConfiguration', '').replace('Instance', 'Value') + $childSettingValueType = "#microsoft.graph.deviceManagementConfiguration$($childSettingValueName)" + $childSettingValueName = $childSettingValueName.Substring(0, 1).ToLower() + $childSettingValueName.Substring(1, $childSettingValueName.length - 1 ) + $childSettingValueTemplateId = $childDefinition.$childSettingValueName.settingValueTemplateId + $childSettingValue = Get-IntuneSettingCatalogPolicySettingInstanceValue ` + -DSCParams $DSCParams ` + -SettingDefinition $childDefinition ` + -SettingName $childSettingName ` + -SettingType $childDefinition.'@odata.type' ` + -SettingValueName $childSettingValueName ` + -SettingValueType $childSettingValueType ` + -SettingValueTemplateId $childSettingValueTemplateId + + if ($null -ne $childSettingValue) + { + $childSettingValue.add('settingDefinitionId', $childDefinition.settingDefinitionId) + $childSettingValue.add('@odata.type', $childSettingType ) + $groupSettingCollectionValueChildren += $childSettingValue + } + } + $groupSettingCollectionValue.add('children', $groupSettingCollectionValueChildren) + $settingValueReturn.Add('groupSettingCollectionValue', @($groupSettingCollectionValue)) + } + '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + { + $values = @() + foreach ( $key in $DSCParams.Keys) + { + if ($settingName -eq ($key.ToLower())) + { + $values = $DSCParams[$key] + break + } + } + $settingValueCollection = @() + foreach ($v in $values) + { + $settingValueCollection += @{ + value = $v + '@odata.type' = $settingValueType + } + } + $settingValueReturn.Add($settingValueName, $settingValueCollection) + } + Default + { + $value = $null + foreach ( $key in $DSCParams.Keys) + { + if ($settingName -eq ($key.ToLower())) + { + if ($settingValueType -eq '#microsoft.graph.deviceManagementConfigurationBooleanSettingValue') + { + $value = [bool]::Parse($DSCParams[$key]) + } + elseif ($settingValueType -eq '#microsoft.graph.deviceManagementConfigurationIntegerSettingValue') + { + $value = [int]::Parse($DSCParams[$key]) + } + elseif ($settingValueType -eq '#microsoft.graph.deviceManagementConfigurationStringSettingValue') + { + $value = $DSCParams[$key] + } + else { + $value = "$($SettingDefinition.settingDefinitionId)_$($DSCParams[$key])" + } + break + } + } + $settingValue = @{} + + if (-not [string]::IsNullOrEmpty($settingValueType)) + { + $settingValue.Add('@odata.type', $settingValueType) + } + if (-not [string]::IsNullOrEmpty($settingValueTemplateId)) + { + $settingValue.Add('settingValueTemplateReference', @{'settingValueTemplateId' = $settingValueTemplateId }) + } + + if ($null -eq $value) + { + # Use the default value if exists + $value = $SettingDefinition.$SettingValueName.defaultValue + if ($null -eq $value) + { + return $null + } + } + $settingValue.Add('value', $value) + $settingValueReturn.Add($settingValueName, $settingValue) + } + } + return $settingValueReturn +} + +function Get-IntuneSettingCatalogPolicySettingDefinitionValue +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $DSCParams, + + [Parameter()] + $SettingDefinition, + + [Parameter()] + [System.String] + $SettingName, + + [Parameter()] + [System.String] + $SettingValueName, + + [Parameter()] + [System.String] + $SettingValueType + ) + + $settingValueReturn = @{} + $key = $DSCParams.Keys | Where-Object { $_.ToLower() -eq $SettingName } + if ($null -ne $key) + { + $value = $DSCParams[$key] + } + else + { + # Use default value if exists + if ($null -ne $SettingDefinition.AdditionalProperties.defaultValue) + { + $value = $SettingDefinition.AdditionalProperties.defaultValue.value + } + elseif ($null -ne $SettingDefinition.AdditionalProperties.defaultOptionId) + { + $value = $SettingDefinition.AdditionalProperties.defaultOptionId + } + } + + $settingValue = @{} + if (-Not [string]::IsNullOrEmpty($settingValueType)) + { + $settingValue.add('@odata.type', $settingValueType) + } + if ($null -eq $value) + { + return $null + } + $settingValue.add('value', $value) + $settingValueReturn.Add($settingValueName, $settingValue) + + return $settingValueReturn +} + +function Update-DeviceManagementConfigurationPolicy +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory = 'true')] + [System.String] + $DeviceManagementConfigurationPolicyId, + + [Parameter(Mandatory = 'true')] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + $TemplateReferenceId, + + [Parameter()] + [System.String] + $Platforms, + + [Parameter()] + [System.String] + $Technologies, + + [Parameter()] + [System.Array] + $Settings + ) + + $templateReference = @{ + 'templateId' = $TemplateReferenceId + } + + $Uri = "https://graph.microsoft.com/beta/deviceManagement/ConfigurationPolicies/$DeviceManagementConfigurationPolicyId" + $policy = [ordered]@{ + 'name' = $DisplayName + 'description' = $Description + 'platforms' = $Platforms + 'technologies' = $Technologies + 'templateReference' = $templateReference + 'settings' = $Settings + } + # Write-Verbose ($policy | ConvertTo-Json -Depth 20) -Verbose + Invoke-MgGraphRequest -Method PUT ` + -Uri $Uri ` + -ContentType 'application/json' ` + -Body ($policy | ConvertTo-Json -Depth 20) 4> out-null +} + +function Get-DeviceManagementConfigurationPolicyAssignment +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = 'true')] + [System.String] + $DeviceManagementConfigurationPolicyId + ) + + try + { + $configurationPolicyAssignments = @() + + $Uri = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$DeviceManagementConfigurationPolicyId/assignments" + $results = Invoke-MgGraphRequest -Method GET -Uri $Uri -ErrorAction Stop 4> out-null + foreach ($result in $results.value.target) + { + $configurationPolicyAssignments += @{ + dataType = $result.'@odata.type' + groupId = $result.groupId + collectionId = $result.collectionId + deviceAndAppManagementAssignmentFilterType = $result.deviceAndAppManagementAssignmentFilterType + deviceAndAppManagementAssignmentFilterId = $result.deviceAndAppManagementAssignmentFilterId + } + } + + while ($results.'@odata.nextLink') + { + $Uri = $results.'@odata.nextLink' + $results = Invoke-MgGraphRequest -Method GET -Uri $Uri -ErrorAction Stop 4> out-null + foreach ($result in $results.value.target) + { + $configurationPolicyAssignments += @{ + dataType = $result.'@odata.type' + groupId = $result.groupId + collectionId = $result.collectionId + deviceAndAppManagementAssignmentFilterType = $result.deviceAndAppManagementAssignmentFilterType + deviceAndAppManagementAssignmentFilterId = $result.deviceAndAppManagementAssignmentFilterId + } + } + } + return $configurationPolicyAssignments + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $null + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof new file mode 100644 index 0000000000..e2b37594e8 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.schema.mof @@ -0,0 +1,37 @@ +[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 collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy")] +class MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy : OMI_BaseResource +{ + [Key, Description("Identity of the account protection local administrator password solution policy.")] String Identity; + [Required, Description("Display name of the account protection local administrator password solution policy.")] String DisplayName; + [Write, Description("Description of the account protection local administrator password solution policy.")] String Description; + [Write, Description("Assignments of the account protection local administrator password solution policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [Write, Description("Configures which directory the local admin account password is backed up to. 0 - Disabled, 1 - Azure AD, 2 - AD"), ValueMap{"0", "1", "2"}, Values{"0", "1", "2"}] UInt32 BackupDirectory; + [Write, Description("Configures the maximum password age of the managed local administrator account for Azure AD. Minimum - 7, Maximum - 365")] UInt32 PasswordAgeDays_AAD; + [Write, Description("Configures the maximum password age of the managed local administrator account for Active Directory. Minimum - 1, Maximum - 365")] UInt32 PasswordAgeDays; + [Write, Description("Configures additional enforcement of maximum password age for the managed local administrator account.")] Boolean PasswordExpirationProtectionEnabled; + [Write, Description("Configures how many previous encrypted passwords will be remembered in Active Directory. Minimum - 0, Maximum - 12")] UInt32 AdEncryptedPasswordHistorySize; + [Write, Description("Configures whether the password is encrypted before being stored in Active Directory.")] Boolean AdPasswordEncryptionEnabled; + [Write, Description("Configures the name or SID of a user or group that can decrypt the password stored in Active Directory.")] String AdPasswordEncryptionPrincipal; + [Write, Description("Configures the name of the managed local administrator account.")] String AdministratorAccountName; + [Write, Description("Configures the password complexity of the managed local administrator account. 1 - Large letters, 2 - Large + small letters, 3 - Large + small letters + numbers, 4 - Large + small letters + numbers + special characters"), ValueMap{"1", "2", "3", "4"}, Values{"1", "2", "3", "4"}] UInt32 PasswordComplexity; + [Write, Description("Configures the length of the password of the managed local administrator account. Minimum - 8, Maximum - 64")] UInt32 PasswordLength; + [Write, Description("Specifies the actions to take upon expiration of the configured grace period. 1 - Reset password, 3 - Reset password and log off, 5 - Reset password and restart"), ValueMap{"1", "3", "5"}, Values{"1", "3", "5"}] UInt32 PostAuthenticationActions; + [Write, Description("Specifies the amount of time (in hours) to wait after an authentication before executing the specified post-authentication actions. Minimum - 0, Maximum - 24")] UInt32 PostAuthenticationResetDelay; + [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 Intune Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Name of the Azure Active Directory tenant used for authentication. Format contoso.onmicrosoft.com")] 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; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/readme.md new file mode 100644 index 0000000000..86b2ea2a0e --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/readme.md @@ -0,0 +1,6 @@ + +# IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy + +## Description + +This resource configures an Intune Account Protection Local Administrator Password Solution Policy. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/settings.json new file mode 100644 index 0000000000..76338d2e0a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/settings.json @@ -0,0 +1,32 @@ +{ + "resourceName": "IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy", + "description": "This resource configures an Intune Account Protection Local Administrator Password Solution Policy.", + "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/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy.psm1 new file mode 100644 index 0000000000..d04d3c48ed --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy.psm1 @@ -0,0 +1,848 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $LocalUserGroupCollection, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + Write-Verbose -Message "Checking for the Intune Account Protection Local User Group Membership Policy {$DisplayName}" + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters ` + -ErrorAction Stop + + #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' + + try + { + #Retrieve policy general settings + + $policy = Get-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $Identity -ErrorAction SilentlyContinue + + if ($null -eq $policy) + { + Write-Verbose -Message "No Account Protection Local User Group Membership Policy with identity {$Identity} was found" + if (-not [String]::IsNullOrEmpty($DisplayName)) + { + $policy = Get-MgBetaDeviceManagementConfigurationPolicy -Filter "Name eq '$DisplayName'" -ErrorAction SilentlyContinue + } + } + if ($null -eq $policy) + { + Write-Verbose -Message "No Account Protection Local User Group Membership Policy with displayName {$DisplayName} was found" + return $nullResult + } + + #Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementConfigurationPolicySetting ` + -DeviceManagementConfigurationPolicyId $policy.Id ` + -ErrorAction Stop + + $returnHashtable = @{} + $returnHashtable.Add('Identity', $policy.Id) + $returnHashtable.Add('DisplayName', $policy.Name) + $returnHashtable.Add('Description', $policy.Description) + + $groupCollections = @() + foreach ($setting in $settings) + { + foreach ($group in $setting.settingInstance.AdditionalProperties.groupSettingCollectionValue) + { + $groupSettings = $group.children[0].groupSettingCollectionValue.children + $newGroupCollection = @{} + $userSelectionType = $groupSettings | Where-Object -FilterScript { $_.settingDefinitionId -like '*_userselectiontype*' } + $newGroupCollection.Add('UserSelectionType', $userSelectionType.choiceSettingValue.value.Split('_')[-1]) + + $members = @() + foreach ($member in $userSelectionType.choiceSettingValue.children[0].simpleSettingCollectionValue) + { + $members += $member.value + } + $newGroupCollection.Add('Members', $members) + + $action = $groupSettings | Where-Object -FilterScript { $_.settingDefinitionId -like '*_action*' } + $newGroupCollection.Add('Action', $($action.choiceSettingValue.value.Split('_')[-2, -1] -join '_')) + + $newLocalGroups = @() + $localGroups = $groupSettings | Where-Object -FilterScript { $_.settingDefinitionId -like '*_desc*' } + foreach ($localGroup in $localGroups.choiceSettingCollectionValue) + { + $newLocalGroups += $localGroup.value.Split('_')[-1] + } + $newGroupCollection.Add('LocalGroups', $newLocalGroups) + $groupCollections += $newGroupCollection + } + } + + Write-Verbose -Message "Found Account Protection Local User Group Membership Policy {$DisplayName}" + + $returnHashtable.Add('LocalUserGroupCollection', $groupCollections) + $returnHashtable.Add('Ensure', 'Present') + $returnHashtable.Add('Credential', $Credential) + $returnHashtable.Add('ApplicationId', $ApplicationId) + $returnHashtable.Add('TenantId', $TenantId) + $returnHashtable.Add('ApplicationSecret', $ApplicationSecret) + $returnHashtable.Add('CertificateThumbprint', $CertificateThumbprint) + $returnHashtable.Add('ManagedIdentity', $ManagedIdentity.IsPresent) + + $returnAssignments = @() + $returnAssignments += Get-MgBetaDeviceManagementConfigurationPolicyAssignment -DeviceManagementConfigurationPolicyId $policy.Id + $assignmentResult = @() + foreach ($assignmentEntry in $returnAssignments) + { + $assignmentValue = @{ + dataType = $assignmentEntry.Target.AdditionalProperties.'@odata.type' + deviceAndAppManagementAssignmentFilterType = $assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterType.toString() + deviceAndAppManagementAssignmentFilterId = $assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterId + groupId = $assignmentEntry.Target.AdditionalProperties.groupId + } + $assignmentResult += $assignmentValue + } + $returnHashtable.Add('Assignments', $assignmentResult) + + return $returnHashtable + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Unable to perform redirect as Location Header is not set in response*") + { + if (Assert-M365DSCIsNonInteractiveShell) + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + } + else + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $LocalUserGroupCollection, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + $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 + + $currentPolicy = 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 + + $templateReferenceId = '22968f54-45fa-486c-848e-f8224aa69772_1' + $platforms = 'windows10' + $technologies = 'mdm' + + if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating new Account Protection Local User Group Membership Policy {$DisplayName}" + $PSBoundParameters.Remove('Identity') | Out-Null + $PSBoundParameters.Remove('Assignments') | Out-Null + $PSBoundParameters.Remove('DisplayName') | Out-Null + $PSBoundParameters.Remove('Description') | Out-Null + + $settings = Get-M365DSCIntuneDeviceConfigurationSettings -Properties ([System.Collections.Hashtable]$PSBoundParameters) + + $createParameters = @{} + $createParameters.add('name', $DisplayName) + $createParameters.add('description', $Description) + $createParameters.add('settings', @($settings)) + $createParameters.add('platforms', $platforms) + $createParameters.add('technologies', $technologies) + $createParameters.add('templateReference', @{ + templateId = $templateReferenceId + }) + $policy = New-MgBetaDeviceManagementConfigurationPolicy -BodyParameter $createParameters + + #region Assignments + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $policy.Id ` + -Targets $assignmentsHash + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating existing Account Protection Local User Group Membership Policy {$DisplayName}" + + $PSBoundParameters.Remove('Identity') | Out-Null + $PSBoundParameters.Remove('DisplayName') | Out-Null + $PSBoundParameters.Remove('Description') | Out-Null + $PSBoundParameters.Remove('Assignments') | Out-Null + + $settings = Get-M365DSCIntuneDeviceConfigurationSettings -Properties ([System.Collections.Hashtable]$PSBoundParameters) + + Update-DeviceManagementConfigurationPolicy ` + -DeviceManagementConfigurationPolicyId $currentPolicy.Identity ` + -DisplayName $DisplayName ` + -Description $Description ` + -TemplateReference $templateReferenceId ` + -Platforms $platforms ` + -Technologies $technologies ` + -Settings $settings + + #region Assignments + $assignmentsHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignments + Update-DeviceConfigurationPolicyAssignment ` + -DeviceConfigurationPolicyId $currentPolicy.Identity ` + -Targets $assignmentsHash + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentPolicy.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing Account Protection Local User Group Membership Policy {$DisplayName}" + Remove-MgBetaDeviceManagementConfigurationPolicy -DeviceManagementConfigurationPolicyId $currentPolicy.Identity -Confirm:$false + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $LocalUserGroupCollection, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + #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 Account Protection Local User Group Membership Policy {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $ValuesToCheck.Remove('Credential') | Out-Null + $ValuesToCheck.Remove('ApplicationId') | Out-Null + $ValuesToCheck.Remove('TenantId') | Out-Null + $ValuesToCheck.Remove('ApplicationSecret') | Out-Null + $ValuesToCheck.Remove('Identity') | Out-Null + + if ($CurrentValues.Ensure -ne $PSBoundParameters.Ensure) + { + return $false + } + + #region LocalUserGroupCollection + $testResult = $true + if ((-not $CurrentValues.LocalUserGroupCollection) -xor (-not $ValuesToCheck.LocalUserGroupCollection)) + { + Write-Verbose -Message 'Configuration drift: one the LocalUserGroupCollection is null' + return $false + } + + if ($CurrentValues.LocalUserGroupCollection) + { + if ($CurrentValues.LocalUserGroupCollection.count -ne $ValuesToCheck.LocalUserGroupCollection.count) + { + Write-Verbose -Message "Configuration drift: Number of LocalUserGroupCollection has changed - current {$($CurrentValues.LocalUserGroupCollection.count)} target {$($ValuesToCheck.LocalUserGroupCollection.count)}" + return $false + } + for ($i = 0; $i -lt $CurrentValues.LocalUserGroupCollection.count; $i++) + { + $source = $ValuesToCheck.LocalUserGroupCollection[$i] + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $CurrentValues.LocalUserGroupCollection[$i] + + if (-not $testResult) + { + $testResult = $false + break + } + } + } + if (-not $testResult) + { + return $false + } + $ValuesToCheck.Remove('LocalUserGroupCollection') | Out-Null + #endregion + + #region Assignments + if ((-not $CurrentValues.Assignments) -xor (-not $ValuesToCheck.Assignments)) + { + Write-Verbose -Message 'Configuration drift: one the assignment is null' + return $false + } + + if ($CurrentValues.Assignments) + { + if ($CurrentValues.Assignments.count -ne $ValuesToCheck.Assignments.count) + { + Write-Verbose -Message "Configuration drift: Number of assignment has changed - current {$($CurrentValues.Assignments.count)} target {$($ValuesToCheck.Assignments.count)}" + return $false + } + foreach ($assignment in $CurrentValues.Assignments) + { + #GroupId Assignment + if (-not [String]::IsNullOrEmpty($assignment.groupId)) + { + $source = [Array]$ValuesToCheck.Assignments | Where-Object -FilterScript { $_.groupId -eq $assignment.groupId } + if (-not $source) + { + Write-Verbose -Message "Configuration drift: groupId {$($assignment.groupId)} not found" + $testResult = $false + break + } + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $assignment + } + #AllDevices/AllUsers assignment + else + { + $source = [Array]$ValuesToCheck.Assignments | Where-Object -FilterScript { $_.dataType -eq $assignment.dataType } + if (-not $source) + { + Write-Verbose -Message "Configuration drift: {$($assignment.dataType)} not found" + $testResult = $false + break + } + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $assignment + } + + if (-not $testResult) + { + $testResult = $false + break + } + + } + } + if (-not $testResult) + { + return $false + } + $ValuesToCheck.Remove('Assignments') | Out-Null + #endregion + + $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 + ) + + $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 + + $dscContent = '' + $i = 1 + + try + { + # Local user group membership template, family endpointSecurityAccountProtection + $policyTemplateID = '22968f54-45fa-486c-848e-f8224aa69772_1' + [array]$policies = Get-MgBetaDeviceManagementConfigurationPolicy ` + -Filter "templateReference/TemplateId eq '$policyTemplateID'" ` + -ErrorAction Stop ` + -All:$true + + if ($policies.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($policy in $policies) + { + Write-Host " |---[$i/$($policies.Count)] $($policy.Name)" -NoNewline + + $params = @{ + Identity = $policy.Id + DisplayName = $policy.Name + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @params + + if ($Results.LocalUserGroupCollection) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject ([Array]$Results.LocalUserGroupCollection) -CIMInstanceName IntuneAccountProtectionLocalUserGroupCollection + + if ($complexTypeStringResult) + { + $Results.LocalUserGroupCollection = $complexTypeStringResult + } + else + { + $Results.Remove('LocalUserGroupCollection') | Out-Null + } + } + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject ([Array]$Results.Assignments) -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + + if ($Results.LocalUserGroupCollection) + { + $isCIMArray = $false + if ($Results.LocalUserGroupCollection.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'LocalUserGroupCollection' -IsCIMArray:$isCIMArray + } + + if ($Results.Assignments) + { + $isCIMArray = $false + if ($Results.Assignments.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + + } + return $dscContent + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Unable to perform redirect as Location Header is not set in response*") + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + else + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return '' + } +} + +function Get-M365DSCIntuneDeviceConfigurationSettings +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $Properties + ) + + $settingDefinition = 'device_vendor_msft_policy_config_localusersandgroups_configure' + $defaultValue = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSetting' + 'settingInstance' = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + 'settingDefinitionId' = $settingDefinition + 'groupSettingCollectionValue' = @() + 'settingInstanceTemplateReference' = @{ + 'settingInstanceTemplateId' = 'de06bec1-4852-48a0-9799-cf7b85992d45' + } + } + } + foreach ($groupConfiguration in $Properties.LocalUserGroupCollection) + { + $groupDefaultValue = @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + 'settingDefinitionId' = $settingDefinition + '_groupconfiguration_accessgroup' + 'groupSettingCollectionValue' = @( + @{ + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = $settingDefinition + '_groupconfiguration_accessgroup_userselectiontype' + 'choiceSettingValue' = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + 'value' = $settingDefinition + '_groupconfiguration_accessgroup_userselectiontype_' + $groupConfiguration.UserSelectionType + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + 'settingDefinitionId' = $settingDefinition + '_groupconfiguration_accessgroup_users' + 'simpleSettingCollectionValue' = @() + } + ) + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = $settingDefinition + '_groupconfiguration_accessgroup_action' + 'choiceSettingValue' = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + 'value' = $settingDefinition + '_groupconfiguration_accessgroup_action_' + $groupConfiguration.Action + 'children' = @() + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionInstance' + 'settingDefinitionId' = $settingDefinition + '_groupconfiguration_accessgroup_desc' + 'choiceSettingCollectionValue' = @() + } + ) + } + ) + 'settingInstanceTemplateReference' = @{ + 'settingInstanceTemplateId' = '76fa254e-cbdb-4718-8bdd-cd41e57caa02' + } + } + ) + } + + foreach ($member in $groupConfiguration.Members) + { + $groupDefaultValue.children[0].groupSettingCollectionValue[0].children[0].choiceSettingValue.children[0].simpleSettingCollectionValue += @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + 'value' = $member + } + } + + foreach ($localGroup in $groupConfiguration.LocalGroups) + { + $groupDefaultValue.children[0].groupSettingCollectionValue[0].children[2].choiceSettingCollectionValue += @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue' + 'value' = $settingDefinition + '_groupconfiguration_accessgroup_desc_' + $localGroup + 'children' = @() + } + } + + $defaultValue.settingInstance.groupSettingCollectionValue += $groupDefaultValue + } + return $defaultValue +} + +function Update-DeviceManagementConfigurationPolicy +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory = 'true')] + [System.String] + $DeviceManagementConfigurationPolicyId, + + [Parameter(Mandatory = 'true')] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + $TemplateReferenceId, + + [Parameter()] + [System.String] + $Platforms, + + [Parameter()] + [System.String] + $Technologies, + + [Parameter()] + [System.Array] + $Settings + ) + + $templateReference = @{ + 'templateId' = $TemplateReferenceId + } + + $Uri = "https://graph.microsoft.com/beta/deviceManagement/ConfigurationPolicies/$DeviceManagementConfigurationPolicyId" + $policy = @{ + 'name' = $DisplayName + 'description' = $Description + 'platforms' = $Platforms + 'technologies' = $Technologies + 'settings' = $Settings + 'templateReference' = $templateReference + } + + Invoke-MgGraphRequest -Method PUT ` + -Uri $Uri ` + -ContentType 'application/json' ` + -Body ($policy | ConvertTo-Json -Depth 20) 4> out-null +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy.schema.mof new file mode 100644 index 0000000000..c37093d4a1 Binary files /dev/null and b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy.schema.mof differ diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/readme.md new file mode 100644 index 0000000000..d70f4a8460 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/readme.md @@ -0,0 +1,7 @@ + +# IntuneAccountProtectionLocalUserGroupMembershipPolicy + +## Description + +This resource configures a Intune Account Protection Local User Group Membership policy. + diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/settings.json new file mode 100644 index 0000000000..76dcf45483 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionLocalUserGroupMembershipPolicy/settings.json @@ -0,0 +1,32 @@ +{ + "resourceName": "IntuneAccountProtectionLocalUserGroupMembershipPolicy", + "description": "This resource configures a Intune Account Protection Local User Group Membership policy.", + "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/DSCResources/MSFT_IntuneAccountProtectionPolicy/MSFT_IntuneAccountProtectionPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/MSFT_IntuneAccountProtectionPolicy.psm1 new file mode 100644 index 0000000000..250d5c47f4 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/MSFT_IntuneAccountProtectionPolicy.psm1 @@ -0,0 +1,938 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + [ValidateSet('notConfigured', 'true', 'false')] + $WindowsHelloForBusinessBlocked, + + [Parameter()] + [ValidateRange(4, 127)] + [System.Int32] + $PinMinimumLength, + + [Parameter()] + [ValidateRange(4, 127)] + [System.Int32] + $PinMaximumLength, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinLowercaseCharactersUsage, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinUppercaseCharactersUsage, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinSpecialCharactersUsage, + + [Parameter()] + [ValidateRange(0, 730)] + [System.Int32] + $PinExpirationInDays, + + [Parameter()] + [ValidateRange(0, 50)] + [System.Int32] + $PinPreviousBlockCount, + + [Parameter()] + [System.Boolean] + $PinRecoveryEnabled, + + [Parameter()] + [System.Boolean] + $SecurityDeviceRequired, + + [Parameter()] + [System.Boolean] + $UnlockWithBiometricsEnabled, + + [Parameter()] + [System.Boolean] + $EnhancedAntiSpoofingForFacialFeaturesEnabled, + + [Parameter()] + [System.Boolean] + $UseCertificatesForOnPremisesAuthEnabled, + + [Parameter()] + [System.Boolean] + $UseSecurityKeyForSignin, + + [Parameter()] + [ValidateSet('notConfigured', 'disable', 'enableWithUEFILock', 'enableWithoutUEFILock')] + [System.String] + $DeviceGuardLocalSystemAuthorityCredentialGuardSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + Write-Verbose -Message "Checking for the Intune Account Protection Policy {$DisplayName}" + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters ` + -ErrorAction Stop + + #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' + + try + { + #Retrieve policy general settings + + $policy = Get-MgBetaDeviceManagementIntent -DeviceManagementIntentId $Identity -ErrorAction SilentlyContinue + + if ($null -eq $policy) + { + Write-Verbose -Message "No Account Protection Policy with identity {$Identity} was found" + if (-not [String]::IsNullOrEmpty($DisplayName)) + { + $policy = Get-MgBetaDeviceManagementIntent -Filter "DisplayName eq '$DisplayName'" -ErrorAction SilentlyContinue + } + } + if ($null -eq $policy) + { + Write-Verbose -Message "No Account Protection Policy with displayName {$DisplayName} was found" + return $nullResult + } + + #Retrieve policy specific settings + [array]$settings = Get-MgBetaDeviceManagementIntentSetting ` + -DeviceManagementIntentId $policy.Id ` + -ErrorAction Stop + + $returnHashtable = @{} + $returnHashtable.Add('Identity', $policy.Id) + $returnHashtable.Add('DisplayName', $policy.DisplayName) + $returnHashtable.Add('Description', $policy.Description) + + foreach ($setting in $settings) + { + $settingName = $setting.definitionId.Split("_")[1] + $settingValue = $setting.ValueJson | ConvertFrom-Json + + if ($settingName -eq 'WindowsHelloForBusinessBlocked') + { + if ($null -eq $settingValue) + { + $settingValue = 'notConfigured' + } + else + { + $settingValue = $settingValue.ToString() + } + + } + + $returnHashtable.Add($settingName, $settingValue) + } + + Write-Verbose -Message "Found Account Protection Policy {$DisplayName}" + + $returnHashtable.Add('Ensure', 'Present') + $returnHashtable.Add('Credential', $Credential) + $returnHashtable.Add('ApplicationId', $ApplicationId) + $returnHashtable.Add('TenantId', $TenantId) + $returnHashtable.Add('ApplicationSecret', $ApplicationSecret) + $returnHashtable.Add('CertificateThumbprint', $CertificateThumbprint) + $returnHashtable.Add('ManagedIdentity', $ManagedIdentity.IsPresent) + + $returnAssignments = @() + $returnAssignments += Get-MgBetaDeviceManagementIntentAssignment -DeviceManagementIntentId $policy.Id + $assignmentResult = @() + foreach ($assignmentEntry in $returnAssignments) + { + $assignmentValue = @{ + dataType = $assignmentEntry.Target.AdditionalProperties.'@odata.type' + deviceAndAppManagementAssignmentFilterType = $assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterType.toString() + deviceAndAppManagementAssignmentFilterId = $assignmentEntry.Target.DeviceAndAppManagementAssignmentFilterId + groupId = $assignmentEntry.Target.AdditionalProperties.groupId + } + $assignmentResult += $assignmentValue + } + $returnHashtable.Add('Assignments', $assignmentResult) + + return $returnHashtable + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Unable to perform redirect as Location Header is not set in response*") + { + if (Assert-M365DSCIsNonInteractiveShell) + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + } + else + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + [ValidateSet('notConfigured', 'true', 'false')] + $WindowsHelloForBusinessBlocked, + + [Parameter()] + [ValidateRange(4, 127)] + [System.Int32] + $PinMinimumLength, + + [Parameter()] + [ValidateRange(4, 127)] + [System.Int32] + $PinMaximumLength, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinLowercaseCharactersUsage, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinUppercaseCharactersUsage, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinSpecialCharactersUsage, + + [Parameter()] + [ValidateRange(0, 730)] + [System.Int32] + $PinExpirationInDays, + + [Parameter()] + [ValidateRange(0, 50)] + [System.Int32] + $PinPreviousBlockCount, + + [Parameter()] + [System.Boolean] + $PinRecoveryEnabled, + + [Parameter()] + [System.Boolean] + $SecurityDeviceRequired, + + [Parameter()] + [System.Boolean] + $UnlockWithBiometricsEnabled, + + [Parameter()] + [System.Boolean] + $EnhancedAntiSpoofingForFacialFeaturesEnabled, + + [Parameter()] + [System.Boolean] + $UseCertificatesForOnPremisesAuthEnabled, + + [Parameter()] + [System.Boolean] + $UseSecurityKeyForSignin, + + [Parameter()] + [ValidateSet('notConfigured', 'disable', 'enableWithUEFILock', 'enableWithoutUEFILock')] + [System.String] + $DeviceGuardLocalSystemAuthorityCredentialGuardSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + + $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 + + $currentPolicy = 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 + + $policyTemplateID = '0f2b5d70-d4e9-4156-8c16-1397eb6c54a5' + + if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating new Account Protection Policy {$DisplayName}" + $PSBoundParameters.Remove('Identity') | Out-Null + $PSBoundParameters.Remove('Assignments') | Out-Null + $PSBoundParameters.Remove('DisplayName') | Out-Null + $PSBoundParameters.Remove('Description') | Out-Null + + $settings = Get-M365DSCIntuneDeviceConfigurationSettings ` + -Properties ([System.Collections.Hashtable]$PSBoundParameters) ` + -TemplateId $policyTemplateID + + $createParameters = @{} + $createParameters.add('DisplayName', $DisplayName) + $createParameters.add('Description', $Description) + $createParameters.add('Settings', $settings) + $createParameters.add('TemplateId', $policyTemplateID) + $policy = New-MgBetaDeviceManagementIntent -BodyParameter $createParameters + + #region Assignments + $assignmentsHash = @() + foreach ($assignment in $Assignments) + { + $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignment + } + if ($policy.id) + { + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $policy.id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/intents' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating existing Account Protection Policy {$DisplayName}" + + $PSBoundParameters.Remove('Identity') | Out-Null + $PSBoundParameters.Remove('DisplayName') | Out-Null + $PSBoundParameters.Remove('Description') | Out-Null + $PSBoundParameters.Remove('Assignments') | Out-Null + + $settings = Get-M365DSCIntuneDeviceConfigurationSettings ` + -Properties ([System.Collections.Hashtable]$PSBoundParameters) ` + -TemplateId $policyTemplateID + + $updateParameters = @{} + $updateParameters.add('DisplayName', $DisplayName) + $updateParameters.add('Description', $Description) + Update-MgBetaDeviceManagementIntent -DeviceManagementIntentId $currentPolicy.Identity -BodyParameter $updateParameters + + #Update-MgBetaDeviceManagementIntent does not support updating the property settings + #Update-MgBetaDeviceManagementIntentSetting only support updating a single setting at a time + #Using Rest to reduce the number of calls + $Uri = "https://graph.microsoft.com/beta/deviceManagement/intents/$($currentPolicy.Identity)/updateSettings" + $body = @{'settings' = $settings } + Invoke-MgGraphRequest -Method POST -Uri $Uri -Body ($body | ConvertTo-Json -Depth 20) -ContentType 'application/json' + + #region Assignments + $assignmentsHash = @() + foreach ($assignment in $Assignments) + { + $assignmentsHash += Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $Assignment + } + + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $currentPolicy.Identity ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/intents' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentPolicy.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing Account Protection Policy {$DisplayName}" + Remove-MgBetaDeviceManagementIntent -DeviceManagementIntentId $currentPolicy.Identity -Confirm:$false + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Identity, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.String] + [ValidateSet('notConfigured', 'true', 'false')] + $WindowsHelloForBusinessBlocked, + + [Parameter()] + [ValidateRange(4, 127)] + [System.Int32] + $PinMinimumLength, + + [Parameter()] + [ValidateRange(4, 127)] + [System.Int32] + $PinMaximumLength, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinLowercaseCharactersUsage, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinUppercaseCharactersUsage, + + [Parameter()] + [ValidateSet('notConfigured', 'blocked', 'required', 'allowed')] + [System.String] + $PinSpecialCharactersUsage, + + [Parameter()] + [ValidateRange(0, 730)] + [System.Int32] + $PinExpirationInDays, + + [Parameter()] + [ValidateRange(0, 50)] + [System.Int32] + $PinPreviousBlockCount, + + [Parameter()] + [System.Boolean] + $PinRecoveryEnabled, + + [Parameter()] + [System.Boolean] + $SecurityDeviceRequired, + + [Parameter()] + [System.Boolean] + $UnlockWithBiometricsEnabled, + + [Parameter()] + [System.Boolean] + $EnhancedAntiSpoofingForFacialFeaturesEnabled, + + [Parameter()] + [System.Boolean] + $UseCertificatesForOnPremisesAuthEnabled, + + [Parameter()] + [System.Boolean] + $UseSecurityKeyForSignin, + + [Parameter()] + [ValidateSet('notConfigured', 'disable', 'enableWithUEFILock', 'enableWithoutUEFILock')] + [System.String] + $DeviceGuardLocalSystemAuthorityCredentialGuardSettings, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + [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 + ) + #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 Account Protection Policy {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $ValuesToCheck = ([Hashtable]$PSBoundParameters).clone() + $ValuesToCheck.Remove('Credential') | Out-Null + $ValuesToCheck.Remove('ApplicationId') | Out-Null + $ValuesToCheck.Remove('TenantId') | Out-Null + $ValuesToCheck.Remove('ApplicationSecret') | Out-Null + $ValuesToCheck.Remove('Identity') | Out-Null + $ValuesToCheck.Remove('Verbose') | Out-Null + + foreach ($key in $PSBoundParameters.Keys) { + if ($null -eq $ValuesToCheck.$key) { + $ValuesToCheck.Remove($key) | Out-Null + } + } + + if ($CurrentValues.WindowsHelloForBusinessBlocked -in @('notconfigured', 'True')) + { + $ValuesToCheck.Remove('PinMinimumLength') | Out-Null + $ValuesToCheck.Remove('PinMaximumLength') | Out-Null + $ValuesToCheck.Remove('PinLowercaseCharactersUsage') | Out-Null + $ValuesToCheck.Remove('PinUppercaseCharactersUsage') | Out-Null + $ValuesToCheck.Remove('PinSpecialCharactersUsage') | Out-Null + $ValuesToCheck.Remove('PinExpirationInDays') | Out-Null + $ValuesToCheck.Remove('PinPreviousBlockCount') | Out-Null + $ValuesToCheck.Remove('PinRecoveryEnabled') | Out-Null + $ValuesToCheck.Remove('SecurityDeviceRequired') | Out-Null + $ValuesToCheck.Remove('UnlockWithBiometricsEnabled') | Out-Null + $ValuesToCheck.Remove('EnhancedAntiSpoofingForFacialFeaturesEnabled') | Out-Null + $ValuesToCheck.Remove('UseCertificatesForOnPremisesAuthEnabled') | Out-Null + } + + if ($CurrentValues.Ensure -ne $PSBoundParameters.Ensure) + { + return $false + } + #region Assignments + $testResult = $true + + if ((-not $CurrentValues.Assignments) -xor (-not $ValuesToCheck.Assignments)) + { + Write-Verbose -Message 'Configuration drift: one the assignment is null' + return $false + } + + if ($CurrentValues.Assignments) + { + if ($CurrentValues.Assignments.count -ne $ValuesToCheck.Assignments.count) + { + Write-Verbose -Message "Configuration drift: Number of assignment has changed - current {$($CurrentValues.Assignments.count)} target {$($ValuesToCheck.Assignments.count)}" + return $false + } + foreach ($assignment in $CurrentValues.Assignments) + { + #GroupId Assignment + if (-not [String]::IsNullOrEmpty($assignment.groupId)) + { + $source = [Array]$ValuesToCheck.Assignments | Where-Object -FilterScript { $_.groupId -eq $assignment.groupId } + if (-not $source) + { + Write-Verbose -Message "Configuration drift: groupId {$($assignment.groupId)} not found" + $testResult = $false + break + } + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $assignment + } + #AllDevices/AllUsers assignment + else + { + $source = [Array]$ValuesToCheck.Assignments | Where-Object -FilterScript { $_.dataType -eq $assignment.dataType } + if (-not $source) + { + Write-Verbose -Message "Configuration drift: {$($assignment.dataType)} not found" + $testResult = $false + break + } + $sourceHash = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $source + $testResult = Compare-M365DSCComplexObject -Source $sourceHash -Target $assignment + } + + if (-not $testResult) + { + $testResult = $false + break + } + + } + } + if (-not $testResult) + { + return $false + } + $ValuesToCheck.Remove('Assignments') | Out-Null + #endregion + + $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 + ) + + $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 + + $dscContent = '' + $i = 1 + + try + { + $policyTemplateID = '0f2b5d70-d4e9-4156-8c16-1397eb6c54a5' + [array]$policies = Get-MgBetaDeviceManagementIntent ` + -Filter "TemplateId eq '$policyTemplateID'" ` + -ErrorAction Stop ` + -All:$true + + if ($policies.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($policy in $policies) + { + Write-Host " |---[$i/$($policies.Count)] $($policy.DisplayName)" -NoNewline + + $params = @{ + Identity = $policy.Id + DisplayName = $policy.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + } + + $Results = Get-TargetResource @params + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject ([Array]$Results.Assignments) -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + + if ($Results.Assignments) + { + $isCIMArray = $false + if ($Results.Assignments.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + + } + return $dscContent + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Unable to perform redirect as Location Header is not set in response*") + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + else + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return '' + } +} + +function Get-M365DSCIntuneDeviceConfigurationSettings +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $Properties, + + [Parameter()] + [System.String] + $TemplateId + ) + + $templateCategoryId = (Get-MgBetaDeviceManagementTemplateCategory -DeviceManagementTemplateId $TemplateId).Id + $templateSettings = Get-MgBetaDeviceManagementTemplateCategoryRecommendedSetting ` + -DeviceManagementTemplateId $TemplateId ` + -DeviceManagementTemplateSettingCategoryId $templateCategoryId + + $results = @() + foreach ($setting in $templateSettings) + { + $result = @{} + $settingType = $setting.AdditionalProperties.'@odata.type' + $settingValue = $null + $currentValueKey = $Properties.keys | Where-Object -FilterScript { $_ -eq $setting.DefinitionId.Split("_")[1] } + + if ($null -ne $currentValueKey) + { + $settingValue = $Properties.$currentValueKey + } + + if ($currentValueKey -eq 'WindowsHelloForBusinessBlocked' -and $settingValue -eq 'notConfigured') + { + $settingValue = $null + } + + switch ($settingType) + { + '#microsoft.graph.deviceManagementStringSettingInstance' + { + if ([String]::IsNullOrEmpty($settingValue)) + { + $settingValue = $setting.ValueJson | ConvertFrom-Json + } + } + '#microsoft.graph.deviceManagementCollectionSettingInstance' + { + if ($null -eq $settingValue) + { + $settingValue = @() + } + else + { + [array]$settingValue = [array]$settingValue + } + } + Default + { + if ($null -eq $settingValue) + { + $settingValue = $setting.ValueJson | ConvertFrom-Json + } + } + } + $result.Add('@odata.type', $settingType) + $result.Add('Id', $setting.Id) + $result.Add('definitionId', $setting.DefinitionId) + $result.Add('value', $settingValue) + + $results += $result + } + return $results +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/MSFT_IntuneAccountProtectionPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/MSFT_IntuneAccountProtectionPolicy.schema.mof new file mode 100644 index 0000000000..e3e884d13c Binary files /dev/null and b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/MSFT_IntuneAccountProtectionPolicy.schema.mof differ diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/readme.md new file mode 100644 index 0000000000..c8f7d0bdaa --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/readme.md @@ -0,0 +1,7 @@ + +# IntuneAccountProtectionPolicy + +## Description + +This resource configures a Intune Account Protection policy. + diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/settings.json new file mode 100644 index 0000000000..bdddc7e8c6 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneAccountProtectionPolicy/settings.json @@ -0,0 +1,32 @@ +{ + "resourceName": "IntuneAccountProtectionPolicy", + "description": "This resource configures a Intune Account Protection policy.", + "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/Examples/Resources/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/1-ConfigureIntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/1-ConfigureIntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.ps1 new file mode 100644 index 0000000000..3aba9c7a5d --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy/1-ConfigureIntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.ps1 @@ -0,0 +1,36 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy "My Account Protection LAPS Policy" + { + Identity = "cb0a561b-7677-46fb-a7f8-635cf64660e9"; + DisplayName = "Account Protection LAPS Policy"; + Description = "My revised description"; + Ensure = "Present"; + Credential = $credsGlobalAdmin + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.allLicensedUsersAssignmentTarget' + } + ); + BackupDirectory = "1"; + PasswordAgeDays_AAD = 10; + AdministratorAccountName = "Administrator"; + PasswordAgeDays = 20; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionLocalUserGroupMembershipPolicy/1-ConfigureIntuneAccountProtectionLocalUserGroupMembershipPolicy.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionLocalUserGroupMembershipPolicy/1-ConfigureIntuneAccountProtectionLocalUserGroupMembershipPolicy.ps1 new file mode 100644 index 0000000000..9a7fd56a0a --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionLocalUserGroupMembershipPolicy/1-ConfigureIntuneAccountProtectionLocalUserGroupMembershipPolicy.ps1 @@ -0,0 +1,40 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneAccountProtectionLocalUserGroupMembershipPolicy "My Account Protection Local User Group Membership Policy" + { + Identity = "cb0a561b-7677-46fb-a7f8-635cf64660e9"; + DisplayName = "Account Protection LUGM Policy"; + Description = "My revised description"; + Ensure = "Present"; + Credential = $credsGlobalAdmin + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.allLicensedUsersAssignmentTarget' + } + ); + LocalUserGroupCollection = @( + MSFT_IntuneAccountProtectionLocalUserGroupCollection{ + LocalGroups = @('administrators', 'users') + Members = @('S-1-12-1-1167842105-1150511762-402702254-1917434032') + Action = 'add_update' + UserSelectionType = 'users' + } + ); + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionPolicy/1-ConfigureIntuneAccountProtectionPolicy.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionPolicy/1-ConfigureIntuneAccountProtectionPolicy.ps1 new file mode 100644 index 0000000000..772aa6636a --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneAccountProtectionPolicy/1-ConfigureIntuneAccountProtectionPolicy.ps1 @@ -0,0 +1,29 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneAccountProtectionPolicy 'myAccountProtectionPolicy' + { + Identity = '355e88e2-dd1f-4956-bafe-9000d8267ad5' + DisplayName = 'test' + deviceGuardLocalSystemAuthorityCredentialGuardSettings = "notConfigured" + WindowsHelloForBusinessBlocked = $true + PinMinimumLength = 5 + PinSpecialCharactersUsage = 'required' + Ensure = 'Present' + Credential = $credsGlobalAdmin + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 new file mode 100644 index 0000000000..4c725552f2 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.Tests.ps1 @@ -0,0 +1,343 @@ +[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 'IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy' -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 'Pass@word1' -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return 'Credentials' + } + + Mock -CommandName Update-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyTemplate -MockWith { + return @{ + TemplateId = 'adc46e5a-f4aa-4ff6-aeff-4f27bc525796_1' + } + } + + Mock -CommandName Get-DeviceManagementConfigurationPolicyAssignment -MockWith { + return @(@{ + dataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + collectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + }) + } + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyTemplateSettingTemplate -MockWith { + return @({ + Id = '1' + SettingDefinitions = @( + Id = 'device_vendor_msft_laps_policies_backupdirectory' + ) + SettingInstanceTemplate = @{ + settingDefinitionId = 'device_vendor_msft_laps_policies_backupdirectory' + settingInstanceTemplateId = 'a3270f64-e493-499d-8900-90290f61ed8a' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstanceTemplate' + } + } + }) + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + + } + + # Test contexts + Context -Name "When the instance doesn't already exist" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = @( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + BackupDirectory = '1' + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return $null + } + } + + It 'Should return absent 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 instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'New-MgBetaDeviceManagementConfigurationPolicy' -Exactly 1 + } + } + + Context -Name 'When the instance already exists and is NOT in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + BackupDirectory = '0' + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_laps_policies_backupdirectory' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'a3270f64-e493-499d-8900-90290f61ed8a' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + choiceSettingValue = @{ + children = @() + value = "device_vendor_msft_laps_policies_backupdirectory_1" + } + } + } + AdditionalProperties = $null + } + } + Mock -CommandName Update-DeviceManagementConfigurationPolicy -MockWith { + } + } + + It 'Should return Present 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 update the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-DeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'When the instance already exists and IS in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + BackupDirectory = '1' + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_laps_policies_backupdirectory' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'a3270f64-e493-499d-8900-90290f61ed8a' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + choiceSettingValue = @{ + children = @() + value = "device_vendor_msft_laps_policies_backupdirectory_1" + } + } + } + AdditionalProperties = $null + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'When the instance exists and it SHOULD NOT' -Fixture { + BeforeAll { + $testParams = @{ + Assignments = @( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + CollectionId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Absent' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_laps_policies_backupdirectory' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'a3270f64-e493-499d-8900-90290f61ed8a' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + choiceSettingValue = @{ + children = @() + value = "device_vendor_msft_laps_policies_backupdirectory_1" + } + } + } + AdditionalProperties = $null + } + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should remove the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + TemplateReference = @{ + TemplateId = 'adc46e5a-f4aa-4ff6-aeff-4f27bc525796_1' + } + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_laps_policies_backupdirectory' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'a3270f64-e493-499d-8900-90290f61ed8a' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + choiceSettingValue = @{ + children = @() + value = "device_vendor_msft_laps_policies_backupdirectory_1" + } + } + } + AdditionalProperties = $null + } + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalUserGroupMembershipPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalUserGroupMembershipPolicy.Tests.ps1 new file mode 100644 index 0000000000..f25796d01b --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionLocalUserGroupMembershipPolicy.Tests.ps1 @@ -0,0 +1,560 @@ +[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 'IntuneAccountProtectionLocalUserGroupMembershipPolicy' -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 'Pass@word1' -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return 'Credentials' + } + + Mock -CommandName Update-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicyAssignment -MockWith { + return @(@{ + target = @{ + deviceAndAppManagementAssignmentFilterType = 'none' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } + } + }) + } + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + + } + + # Test contexts + Context -Name "When the instance doesn't already exist" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = @( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + DeviceAndAppManagementAssignmentFilterType = 'none' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + LocalUserGroupCollection = @( + (New-CimInstance -ClassName MSFT_IntuneAccountProtectionLocalUserGroupCollection -Property @{ + LocalGroups = @('administrators', 'users') + Members = @('S-1-12-1-1167842105-1150511762-402702254-1917434032') + Action = 'add_update' + UserSelectionType = 'users' + } -ClientOnly) + ) + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return $null + } + } + + It 'Should return absent 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 instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'New-MgBetaDeviceManagementConfigurationPolicy' -Exactly 1 + } + } + + Context -Name 'When the instance already exists and is NOT in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + DeviceAndAppManagementAssignmentFilterType = 'none' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + LocalUserGroupCollection = @( + (New-CimInstance -ClassName MSFT_IntuneAccountProtectionLocalUserGroupCollection -Property @{ + LocalGroups = @('administrators') + Members = @('S-1-12-1-1167842105-1150511762-402702254-1917434032') + Action = 'add_update' + UserSelectionType = 'users' + } -ClientOnly) + ) + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_policy_config_localusersandgroups_configure' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'de06bec1-4852-48a0-9799-cf7b85992d45' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup' + 'groupSettingCollectionValue' = @( + @{ + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype_users' + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_users' + 'simpleSettingCollectionValue' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + 'value' = 'Non-existant value' + } + ) + } + ) + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action_remove_update' + 'children' = @() + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc' + 'choiceSettingCollectionValue' = @( + @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc_users' + 'children' = @() + } + ) + } + ) + } + ) + } + ) + } + ) + } + } + AdditionalProperties = $null + } + } + Mock -CommandName Update-DeviceManagementConfigurationPolicy -MockWith { + } + } + + It 'Should return Present 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 update the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-DeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'When the instance already exists and IS in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + DeviceAndAppManagementAssignmentFilterType = 'none' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + LocalUserGroupCollection = @( + (New-CimInstance -ClassName MSFT_IntuneAccountProtectionLocalUserGroupCollection -Property @{ + LocalGroups = @('administrators') + Members = @('S-1-12-1-1167842105-1150511762-402702254-1917434032') + Action = 'add_update' + UserSelectionType = 'users' + } -ClientOnly) + ) + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_policy_config_localusersandgroups_configure' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'de06bec1-4852-48a0-9799-cf7b85992d45' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup' + 'groupSettingCollectionValue' = @( + @{ + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype_users' + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_users' + 'simpleSettingCollectionValue' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + 'value' = 'S-1-12-1-1167842105-1150511762-402702254-1917434032' + } + ) + } + ) + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action_add_update' + 'children' = @() + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc' + 'choiceSettingCollectionValue' = @( + @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc_administrators' + 'children' = @() + } + ) + } + ) + } + ) + } + ) + } + ) + } + } + AdditionalProperties = $null + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'When the instance exists and it SHOULD NOT' -Fixture { + BeforeAll { + $testParams = @{ + Assignments = @( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + DeviceAndAppManagementAssignmentFilterType = 'none' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + LocalUserGroupCollection = @( + (New-CimInstance -ClassName MSFT_IntuneAccountProtectionLocalUserGroupCollection -Property @{ + LocalGroups = @('administrators') + Members = @('S-1-12-1-1167842105-1150511762-402702254-1917434032') + Action = 'add_update' + UserSelectionType = 'users' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Absent' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_policy_config_localusersandgroups_configure' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'de06bec1-4852-48a0-9799-cf7b85992d45' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup' + 'groupSettingCollectionValue' = @( + @{ + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype_users' + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_users' + 'simpleSettingCollectionValue' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + 'value' = 'S-1-12-1-1167842105-1150511762-402702254-1917434032' + } + ) + } + ) + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action_add_update' + 'children' = @() + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc' + 'choiceSettingCollectionValue' = @( + @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc_administrators' + 'children' = @() + } + ) + } + ) + } + ) + } + ) + } + ) + } + } + AdditionalProperties = $null + } + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should remove the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceManagementConfigurationPolicy -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicy -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + Name = 'My Test' + TemplateReference = @{ + TemplateId = '5dd36540-eb22-4e7e-b19c-2a07772ba627_1' + } + } + } + + Mock -CommandName Get-MgBetaDeviceManagementConfigurationPolicySetting -MockWith { + return @{ + Id = 0 + SettingDefinitions = $null + SettingInstance = @{ + SettingDefinitionId = 'device_vendor_msft_policy_config_localusersandgroups_configure' + SettingInstanceTemplateReference = @{ + SettingInstanceTemplateId = 'de06bec1-4852-48a0-9799-cf7b85992d45' + } + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + groupSettingCollectionValue = @( + @{ + children = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup' + 'groupSettingCollectionValue' = @( + @{ + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_userselectiontype_users' + 'children' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingCollectionInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_users' + 'simpleSettingCollectionValue' = @( + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue' + 'value' = 'S-1-12-1-1167842105-1150511762-402702254-1917434032' + } + ) + } + ) + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action' + 'choiceSettingValue' = @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_action_add_update' + 'children' = @() + } + }, + @{ + '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance' + 'settingDefinitionId' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc' + 'choiceSettingCollectionValue' = @( + @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc_administrators' + 'children' = @() + }, + @{ + 'value' = 'device_vendor_msft_policy_config_localusersandgroups_configure_groupconfiguration_accessgroup_desc_users' + 'children' = @() + } + ) + } + ) + } + ) + } + ) + } + ) + } + } + AdditionalProperties = $null + } + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicy.Tests.ps1 new file mode 100644 index 0000000000..9f79fe6d48 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneAccountProtectionPolicy.Tests.ps1 @@ -0,0 +1,319 @@ +[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 'IntuneAccountProtectionPolicy' -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 'Pass@word1' -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return 'Credentials' + } + + Mock -CommandName Get-MgBetaDeviceManagementIntent -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementIntentSetting -MockWith { + } + + Mock -CommandName Update-MgBetaDeviceManagementIntent -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementIntent -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + } + + Mock -CommandName Remove-MgBetaDeviceManagementIntent -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementTemplateCategory -MockWith { + return @{ + Id = '9d151a3d-a0c6-4a5e-8d9f-f379369f7ef0' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementTemplateCategoryRecommendedSetting -MockWith { + return @{ + DefinitionId = 'deviceConfiguration--windowsIdentityProtectionConfiguration_useSecurityKeyForSignin' + Id = '516bbd8e-dc08-4870-85d5-03d0cd7266ae' + ValueJson = 'false' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementBooleanSettingInstance' + value = $false + } + } + } + + Mock -CommandName Get-MgBetaDeviceManagementIntentAssignment -MockWith { + return @(@{ + target = @{ + deviceAndAppManagementAssignmentFilterType = 'none' + deviceAndAppManagementAssignmentFilterId = $null + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.exclusionGroupAssignmentTarget' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } + } + }) + } + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -MockWith { + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + + } + + # Test contexts + Context -Name "When the instance doesn't already exist" -Fixture { + BeforeAll { + $testParams = @{ + Assignments = @( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + deviceAndAppManagementAssignmentFilterType = 'none' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + UseSecurityKeyForSignin = $true + } + + Mock -CommandName Get-MgBetaDeviceManagementIntent -MockWith { + return $null + } + } + + It 'Should return absent 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 instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'New-MgBetaDeviceManagementIntent' -Exactly 1 + } + } + + Context -Name 'When the instance already exists and is NOT in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + deviceAndAppManagementAssignmentFilterType = 'none' + groupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + UseSecurityKeyForSignin = $true + } + + Mock -CommandName Get-MgBetaDeviceManagementIntent -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + DisplayName = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementIntentSetting -MockWith { + return @(@{ + Id = 0 + DefinitionId = 'deviceConfiguration--windowsIdentityProtectionConfiguration_useSecurityKeyForSignin' + ValueJson = 'false' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementBooleanSettingInstance' + value = $false + } + }) + } + Mock -CommandName Update-MgBetaDeviceManagementIntent -MockWith { + } + Mock -CommandName Invoke-MgGraphRequest -MockWith { + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams -Verbose).Ensure | Should -Be 'Present' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should update the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaDeviceManagementIntent -Exactly 1 + Should -Invoke -CommandName Invoke-MgGraphRequest -Exactly 1 + } + } + + Context -Name 'When the instance already exists and IS in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Present' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Assignments = [CimInstance[]]@( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + deviceAndAppManagementAssignmentFilterType = 'none' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + } + + Mock -CommandName Get-MgBetaDeviceManagementIntent -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + DisplayName = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementIntentSetting -MockWith { + return @(@{ + Id = 0 + DefinitionId = 'deviceConfiguration--windowsIdentityProtectionConfiguration_useSecurityKeyForSignin' + ValueJson = 'true' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementBooleanSettingInstance' + value = $true + } + }) + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'When the instance exists and it SHOULD NOT' -Fixture { + BeforeAll { + $testParams = @{ + Assignments = @( + (New-CimInstance -ClassName MSFT_DeviceManagementConfigurationPolicyAssignments -Property @{ + DataType = '#microsoft.graph.exclusionGroupAssignmentTarget' + deviceAndAppManagementAssignmentFilterType = 'none' + GroupId = '26d60dd1-fab6-47bf-8656-358194c1a49d' + } -ClientOnly) + ) + Credential = $Credential + Description = 'My Test Description' + DisplayName = 'My Test' + Ensure = 'Absent' + Identity = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + } + + Mock -CommandName Get-MgBetaDeviceManagementIntent -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + DisplayName = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementIntentSetting -MockWith { + return @(@{ + Id = 0 + DefinitionId = 'deviceConfiguration--windowsIdentityProtectionConfiguration_useSecurityKeyForSignin' + ValueJson = 'false' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementBooleanSettingInstance' + value = $false + } + }) + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams -Verbose).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should remove the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceManagementIntent -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementIntent -MockWith { + return @{ + Id = '619bd4a4-3b3b-4441-bd6f-3f4c0c444870' + Description = 'My Test Description' + DisplayName = 'My Test' + } + } + + Mock -CommandName Get-MgBetaDeviceManagementIntentSetting -MockWith { + return @(@{ + Id = 0 + DefinitionId = 'deviceConfiguration--windowsIdentityProtectionConfiguration_useSecurityKeyForSignin' + ValueJson = 'false' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.deviceManagementBooleanSettingInstance' + value = $false + } + }) + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md b/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md new file mode 100644 index 0000000000..2b3da850d8 --- /dev/null +++ b/docs/docs/resources/intune/IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy.md @@ -0,0 +1,115 @@ +# IntuneAccountProtectionPolicyLocalAdministratorPasswordSolutionPolicy + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Identity** | Key | String | Identity of the account protection LAPS policy. | | +| **DisplayName** | Required | String | Display name of the account protection LAPS policy. | | +| **Description** | Write | String | Description of the account protection LAPS policy. | | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Assignments of the Intune Policy. | | +| **BackupDirectory** | Write | UInt32 | Which directory the local admin account password is backed up to. | `0` = Disabled, `1` = Azure AD, `2` = Active Directory | +| **PasswordAgeDays_AAD** | Write | UInt32 | Maximum password age of the managed local administrator account for Azure AD. Only applicable if the BackupDirectory value is equal to `1`. (7, 365) | `7-365` | +| **PasswordAgeDays** | Write | UInt32 | Maximum password age of the managed local administrator account for Active Directory. Only applicable if the BackupDirectory value is equal to `2`. (1, 365) | `1-365` | +| **PasswordExpirationProtectionEnabled** | Write | Boolean | Whether or not the password expiration protection is enabled. Only applicable if the BackupDirectory value is equal to `2`. | `True`, `False`| +| **AdEncryptedPasswordHistorySize** | Write | UInt32 | How many previous encrypted passwords will be remembered in Active Directory. Only applicable if the BackupDirectory value is equal to `2`. (0, 12) | `0-12` | +| **AdPasswordEncryptionEnabled** | Write | Boolean | Whether or not the password is encrypted before being stored in Active Directory. Only applicable if the BackupDirectory value is equal to `2`. | `True`, `False` | +| **AdPasswordEncryptionPrincipal** | Write | String | Name or SID of a user or group that can decrypt the password stored in Active Directory. Only applicable if the BackupDirectory value is equal to `2`. | | +| **AdministratorAccountName** | Write | String | Name of the local administrator account. | | +| **PasswordComplexity** | Write | UInt32 | Password complexity of the local administrator account. | `1` = Large letters, `2` = Large + small letters, `3` = Large + small letters + numbers, `4` = Large + small letters + numbers + special characters | +| **PasswordLength** | Write | UInt32 | Password length of the local administrator account. (8, 64) | `8-64` | +| **PostAuthenticationActions** | Write | UInt32 | actions to take upon expiration of the configured grace period. | `1` = Reset password, `3` = Reset password + log off, `5` = Reset password + reboot | +| **PostAuthenticationResetDelay** | Write | UInt32 | Delay in hours before the post-authentication action is executed. (0, 24) | `1-24` | +| **Ensure** | Write | String | Present ensures the site collection exists, absent ensures it is removed | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Intune Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Name of the Azure Active Directory tenant used for authentication. Format contoso.onmicrosoft.com | | +| **ApplicationSecret** | Write | PSCredential | Secret of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + + +## Description + +This resource configures an Intune Account Protection Local Administrator Password Solution Policy. + + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All + +#### Application permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneAccountProtectionLocalAdministratorPasswordSolutionPolicy "My Account Protection LAPS Policy" + { + Identity = "cb0a561b-7677-46fb-a7f8-635cf64660e9"; + DisplayName = "Account Protection LAPS Policy"; + Description = "My revised description"; + Ensure = "Present"; + Credential = $credsGlobalAdmin + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.allLicensedUsersAssignmentTarget' + } + ); + BackupDirectory = "1"; + PasswordAgeDays_AAD = 10; + AdministratorAccountName = "Administrator"; + PasswordAgeDays = 20; + } + } +} +``` + diff --git a/docs/docs/resources/intune/IntuneAccountProtectionLocalUserGroupMembershipPolicy.md b/docs/docs/resources/intune/IntuneAccountProtectionLocalUserGroupMembershipPolicy.md new file mode 100644 index 0000000000..4e7a54a71b --- /dev/null +++ b/docs/docs/resources/intune/IntuneAccountProtectionLocalUserGroupMembershipPolicy.md @@ -0,0 +1,115 @@ +# IntuneAccountProtectionPolicyLocalUserGroupMembership + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Identity** | Key | String | Identity of the account protection policy. | | +| **DisplayName** | Required | String | Display name of the account protection policy. | | +| **Description** | Write | String | Description of the account protection policy. | | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Assignments of the Intune Policy. | | +| **LocalUserGroupCollection** | Write | MSFT_IntuneAccountProtectionLocalUserGroupCollection[] | Local User Group Collections of the Intune Policy. | | +| **Ensure** | Write | String | Present ensures the site collection exists, absent ensures it is removed | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Intune Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Name of the Azure Active Directory tenant used for authentication. Format contoso.onmicrosoft.com | | +| **ApplicationSecret** | Write | PSCredential | Secret of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + +### MSFT_IntuneAccountProtectionLocalUserGroupCollection +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **UserSelectionType** | Write | String | The type of the selection. Either users / groups from AzureAD, or by manual identifier. | `users`, `manual` | +| **Action** | Write | String | The action to use for adding / removing members. | `add_update`, `remove_update`, `add_replace` | +| **LocalGroups** | Write | String[] | The local groups to add / remove the members to / from. | List of the following values: `administrators`, `users`, `guests`, `powerusers`, `remotedesktopusers`, `remotemanagementusers` | +| **Members** | Write | String[] | The members to add / remove to / from the group. For AzureAD Users, use the format `AzureAD\`. For groups, use the security identifier (SID). | | + +## Description + +This resource configures a Intune Account Protection Local User Group Membership policy. + + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All + +#### Application permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneAccountProtectionLocalUserGroupMembershipPolicy "My Account Protection Local User Group Membership Policy" + { + Identity = "cb0a561b-7677-46fb-a7f8-635cf64660e9"; + DisplayName = "Account Protection LUGM Policy"; + Description = "My revised description"; + Ensure = "Present"; + Credential = $credsGlobalAdmin + Assignments = @( + MSFT_DeviceManagementConfigurationPolicyAssignments{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.allLicensedUsersAssignmentTarget' + } + ); + LocalUserGroupCollection = @( + MSFT_IntuneAccountProtectionLocalUserGroupCollection{ + LocalGroups = @('administrators', 'users') + Members = @('S-1-12-1-1167842105-1150511762-402702254-1917434032') + Action = 'add_update' + UserSelectionType = 'users' + } + ); + } + } +} +``` + diff --git a/docs/docs/resources/intune/IntuneAccountProtectionPolicy.md b/docs/docs/resources/intune/IntuneAccountProtectionPolicy.md new file mode 100644 index 0000000000..c7d3eab705 --- /dev/null +++ b/docs/docs/resources/intune/IntuneAccountProtectionPolicy.md @@ -0,0 +1,111 @@ +# IntuneAccountProtectionPolicy + +## Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **Identity** | Key | String | Identity of the account protection policy. | | +| **DisplayName** | Required | String | Display name of the account protection policy. | | +| **Description** | Write | String | Description of the account protection policy. | | +| **Assignments** | Write | MSFT_DeviceManagementConfigurationPolicyAssignments[] | Assignments of the Intune Policy. | | +| **WindowsHelloForBusinessBlocked** | Write | Boolean | Block Windows Hello for Business. | `True`, `False` | +| **PinMinimumLength** | Write | UInt32 | Minimum PIN length must be between 4 and 127. (4-127) | `4-127` | +| **PinMaximumLength** | Write | UInt32 | Maximum PIN length must be between 4 and 127. (4-127) | `4-127` | +| **PinLowercaseCharactersUsage** | Write | String | If required, user PIN must include at least one lowercase letter. | `notConfigured`, `blocked`, `required`, `allowed` | +| **PinUppercaseCharactersUsage** | Write | String | If required, user PIN must include at least one uppercase letter. | `notConfigured`, `blocked`, `required`, `allowed` | +| **PinSpecialCharactersUsage** | Write | String | If required, user PIN must include at least one special character. | `notConfigured`, `blocked`, `required`, `allowed` | +| **PinExpirationInDays** | Write | UInt32 | If configured, the user will be forced to change their PIN after the set number of days. (0, 730), 0 = Never | `0-730` | +| **PinPreviousBlockCount** | Write | UInt32 | If configured, the user will not be able to reuse this number of previous PINs. (0, 50), 0 = Do not remember. | `0-50` | +| **PinRecoveryEnabled** | Write | Boolean | If enabled, the PIN recovery secret will be stored on the device and the user can change their PIN if needed. If disabled or not configured, the recovery secret will not be created or stored. | `True`, `False` | +| **SecurityDeviceRequired** | Write | Boolean | If you enable this policy setting, only devices with a usable TPM provision Windows Hello for Business. If you disable or do not configure this policy setting, the TPM is still preferred, but all devices provision Windows Hello for Business. | `True`, `False` | +| **UnlockWithBiometricsEnabled** | Write | Boolean | If allowed, Windows Hello for Business can authenticate using gestures, such as face and fingerprint. Users must still configure a PIN in case of failure. | `True`, `False` | +| **EnhancedAntiSpoofingForFacialFeaturesEnabled** | Write | Boolean | If enabled, devices will use enhanced anti-spoofing, when available. If not configured, the client configuration for anti-spoofing will be honored. | `True`, `False` | +| **UseCertificatesForOnPremisesAuthEnabled** | Write | Boolean | If configured, Windows Hello for Business can use certificates to authenticate to on-premise resources. | `True`, `False` | +| **UseSecurityKeyForSignin** | Write | Boolean | Enable Windows Hello security key as a logon credential for all PCs in the tenant. | `True`, `False` | +| **DeviceGuardLocalSystemAuthorityCredentialGuardSettings** | Write | String | Setting this Disable will disable the use of Credential Guard, which is the Windows default. Setting this to Enable with UEFI lock will enable Credential Guard and not allow it to be disabled remotely, as the UEFI persisted configuration must be manually cleared. Setting this to Enable without UEFI lock will enable Credential Guard and allow it to be turned off without physical access to the machine. | `notConfigured`, `disable`, `enableWithUEFILock`, `enableWithoutUEFILock` | +| **Ensure** | Write | String | Present ensures the site collection exists, absent ensures it is removed | `Present`, `Absent` | +| **Credential** | Write | PSCredential | Credentials of the Intune Admin | | +| **ApplicationId** | Write | String | Id of the Azure Active Directory application to authenticate with. | | +| **TenantId** | Write | String | Name of the Azure Active Directory tenant used for authentication. Format contoso.onmicrosoft.com | | +| **ApplicationSecret** | Write | PSCredential | Secret of the Azure Active Directory tenant used for authentication. | | +| **CertificateThumbprint** | Write | String | Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication. | | +| **ManagedIdentity** | Write | Boolean | Managed ID being used for authentication. | | + +### MSFT_DeviceManagementConfigurationPolicyAssignments + +#### Parameters + +| Parameter | Attribute | DataType | Description | Allowed Values | +| --- | --- | --- | --- | --- | +| **dataType** | Write | String | The type of the target assignment. | `#microsoft.graph.groupAssignmentTarget`, `#microsoft.graph.allLicensedUsersAssignmentTarget`, `#microsoft.graph.allDevicesAssignmentTarget`, `#microsoft.graph.exclusionGroupAssignmentTarget`, `#microsoft.graph.configurationManagerCollectionAssignmentTarget` | +| **deviceAndAppManagementAssignmentFilterType** | Write | String | The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude. | `none`, `include`, `exclude` | +| **deviceAndAppManagementAssignmentFilterId** | Write | String | The Id of the filter for the target assignment. | | +| **groupId** | Write | String | The group Id that is the target of the assignment. | | +| **collectionId** | Write | String | The collection Id that is the target of the assignment.(ConfigMgr) | | + + +## Description + +This resource configures a Intune Account Protection policy. + + +## Permissions + +### Microsoft Graph + +To authenticate with the Microsoft Graph API, this resource required the following permissions: + +#### Delegated permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All + +#### Application permissions + +- **Read** + + - DeviceManagementConfiguration.Read.All + +- **Update** + + - DeviceManagementConfiguration.ReadWrite.All + +## Examples + +### Example 1 + +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. + +```powershell +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + IntuneAccountProtectionPolicy 'myAccountProtectionPolicy' + { + Identity = '355e88e2-dd1f-4956-bafe-9000d8267ad5' + DisplayName = 'test' + deviceGuardLocalSystemAuthorityCredentialGuardSettings = "notConfigured" + WindowsHelloForBusinessBlocked = $true + PinMinimumLength = 5 + PinSpecialCharactersUsage = 'required' + Ensure = 'Present' + Credential = $credsGlobalAdmin + } + } +} +``` +