DSCResources/MSFT_AccountPolicy/MSFT_AccountPolicy.psm1
$resourceModuleRootPath = Split-Path -Path (Split-Path $PSScriptRoot -Parent) -Parent $modulesRootPath = Join-Path -Path $resourceModuleRootPath -ChildPath 'Modules' Import-Module -Name (Join-Path -Path $modulesRootPath ` -ChildPath 'SecurityPolicyResourceHelper\SecurityPolicyResourceHelper.psm1') ` -Force $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_AccountPolicy' <# .SYNOPSIS Retreives the current account policy configuration #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [System.String] $Name ) $returnValue = @{ Name = $Name } $currentSecurityPolicy = Get-SecurityPolicy -Area SECURITYPOLICY $policyDataFilePath = Join-Path -Path $PSScriptRoot -ChildPath 'AccountPolicyData.psd1' $accountPolicyData = Import-PowerShellDataFile -Path $policyDataFilePath foreach ($accountPolicy in $accountPolicyData.Keys) { Write-Verbose -Message $accountPolicy $section = $accountPolicyData[$accountPolicy].Section Write-Verbose -Message ($script:localizedData.Section -f $section) $valueName = $accountPolicyData[$accountPolicy].Value Write-Verbose -Message ($script:localizedData.Value -f $valueName) $options = $accountPolicyData[$accountPolicy].Option Write-Verbose -Message ($script:localizedData.Option -f $($options -join ',')) $currentValue = $currentSecurityPolicy.$section.$valueName Write-Verbose -Message ($script:localizedData.RawValue -f $($currentValue -join ',')) if ($options.keys -eq 'String') { $stringValue = ($currentValue -split ',')[-1] $resultValue = ($stringValue -replace '"').Trim() if ($resultValue -eq -1 -and $accountPolicy -in 'Maximum_Password_Age','Account_Lockout_Duration') { $resultValue = 0 } } else { Write-Verbose -Message ($script:localizedData.RetrievingValue -f $valueName) if ($currentSecurityPolicy.$section.keys -contains $valueName) { $resultValue = ($accountPolicyData.$accountPolicy.Option.GetEnumerator() | Where-Object -Property Value -eq $currentValue.Trim()).Name } else { $resultValue = $null } } $returnValue.Add($accountPolicy, $resultValue) } return $returnValue } <# .SYNOPSIS Sets the specified account policy #> function Set-TargetResource { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $Name, [Parameter()] [ValidateRange(0, 24)] [System.UInt32] $Enforce_password_history, [Parameter()] [ValidateRange(0, 999)] [System.UInt32] $Maximum_Password_Age, [Parameter()] [ValidateRange(0, 998)] [System.UInt32] $Minimum_Password_Age, [Parameter()] [ValidateRange(0, 14)] [System.UInt32] $Minimum_Password_Length, [Parameter()] [ValidateSet("Enabled", "Disabled")] [System.String] $Password_must_meet_complexity_requirements, [Parameter()] [ValidateSet("Enabled", "Disabled")] [System.String] $Store_passwords_using_reversible_encryption, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Account_lockout_duration, [Parameter()] [ValidateRange(0, 999)] [System.UInt32] $Account_lockout_threshold, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Reset_account_lockout_counter_after, [Parameter()] [ValidateSet("Enabled", "Disabled")] [System.String] $Enforce_user_logon_restrictions, [Parameter()] [ValidateRange(10, 99999)] [System.UInt32] $Maximum_lifetime_for_service_ticket, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Maximum_lifetime_for_user_ticket, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Maximum_lifetime_for_user_ticket_renewal, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Maximum_tolerance_for_computer_clock_synchronization ) $kerberosPolicies = @() $systemAccessPolicies = @() $nonComplaintPolicies = @() $policyDataFilePath = Join-Path -Path $PSScriptRoot -ChildPath 'AccountPolicyData.psd1' $accountPolicyData = Import-PowerShellDataFile -Path $policyDataFilePath $script:seceditOutput = "$env:TEMP\Secedit-OutPut.txt" $accountPolicyToAddInf = "$env:TEMP\accountPolicyToAdd.inf" $desiredPolicies = $PSBoundParameters.GetEnumerator() | Where-Object -FilterScript {$PSItem.key -in $accountPolicyData.Keys} foreach ($policy in $desiredPolicies) { $testParameters = @{ Name = 'Test' $policy.Key = $policy.Value Verbose = $false } <# Define what policies are not in a desired state so we only add those policies that need to be changed to the INF. #> $isInDesiredState = Test-TargetResource @testParameters if (-not ($isInDesiredState)) { $policyKey = $policy.Key $policyData = $accountPolicyData.$policyKey $nonComplaintPolicies += $policyKey if ($policyData.Option.GetEnumerator().Name -eq 'String') { if ([String]::IsNullOrWhiteSpace($policyData.Option.String)) { if ($policy.Key -in 'Maximum_Password_Age','Account_Lockout_Duration' -and $policy.Value -eq 0) { <# This addresses the scenario when the desired value of Maximum_Password_Age or Account_Lockout_Duration is 0. The INF file consumed by secedit.exe requires the value to be -1. #> $newValue = -1 } else { $newValue = $policy.value } } else { $newValue = "$($policyData.Option.String)" + "$($policy.Value)" } } else { $newValue = $($policyData.Option[$policy.value]) } if ($policyData.Section -eq 'System Access') { $systemAccessPolicies += "$($policyData.Value)=$newValue" } else { $kerberosPolicies += "$($policyData.Value)=$newValue" } } } $infTemplate = Add-PolicyOption -SystemAccessPolicies $systemAccessPolicies -KerberosPolicies $kerberosPolicies Out-File -InputObject $infTemplate -FilePath $accountPolicyToAddInf -Encoding unicode -Force Invoke-Secedit -InfPath $accountPolicyToAddInf -SecEditOutput $script:seceditOutput Remove-Item -Path $accountPolicyToAddInf $successResult = Test-TargetResource @PSBoundParameters if ($successResult -eq $false) { $nonComplaintPolicies = $nonComplaintPolicies | Sort-Object throw ($script:localizedData.SetFailed -f ($nonComplaintPolicies -join ',')) } else { Write-Verbose -Message ($script:localizedData.SetSuccess) } } <# .SYNOPSIS Tests the desired account policy configuration against the current configuration #> function Test-TargetResource { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "")] [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $Name, [Parameter()] [ValidateRange(0, 24)] [System.UInt32] $Enforce_password_history, [Parameter()] [ValidateRange(0, 999)] [System.UInt32] $Maximum_Password_Age, [Parameter()] [ValidateRange(0, 998)] [System.UInt32] $Minimum_Password_Age, [Parameter()] [ValidateRange(0, 14)] [System.UInt32] $Minimum_Password_Length, [Parameter()] [ValidateSet("Enabled", "Disabled")] [System.String] $Password_must_meet_complexity_requirements, [Parameter()] [ValidateSet("Enabled", "Disabled")] [System.String] $Store_passwords_using_reversible_encryption, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Account_lockout_duration, [Parameter()] [ValidateRange(0, 999)] [System.UInt32] $Account_lockout_threshold, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Reset_account_lockout_counter_after, [Parameter()] [ValidateSet("Enabled", "Disabled")] [System.String] $Enforce_user_logon_restrictions, [Parameter()] [ValidateRange(10, 99999)] [System.UInt32] $Maximum_lifetime_for_service_ticket, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Maximum_lifetime_for_user_ticket, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Maximum_lifetime_for_user_ticket_renewal, [Parameter()] [ValidateRange(0, 99999)] [System.UInt32] $Maximum_tolerance_for_computer_clock_synchronization ) $currentAccountPolicies = Get-TargetResource -Name $Name -Verbose:0 $desiredAccountPolicies = $PSBoundParameters foreach ($policy in $desiredAccountPolicies.Keys) { if ($currentAccountPolicies.ContainsKey($policy)) { Write-Verbose -Message ($script:localizedData.TestingPolicy -f $policy) Write-Verbose -Message ($script:localizedData.PoliciesBeingCompared -f $($currentAccountPolicies[$policy] -join ','), $($desiredAccountPolicies[$policy] -join ',')) if ($currentAccountPolicies[$policy] -ne $desiredAccountPolicies[$policy]) { return $false } } } # if the code made it this far we must be in a desired state return $true } Export-ModuleMember -Function *-TargetResource |