How to Update Windows Password Policies Using PowerShell

Key Takeaways

  • Password policies are essential for strengthening IT security in organizations.
  • The provided script automates the process of changing password complexity in Windows.
  • The script supports both domain and non-domain computers.
  • Running the script without administrative privileges will result in termination.
  • Traditional methods to change password policies can be more time-consuming than this script.
  • Always test the script in a controlled environment before deploying.
  • Informing users about changes in password policies can prevent confusion and potential lockouts.
  • Regularly revisiting and adjusting password policies is a best practice.
  • NinjaOne can integrate seamlessly with automation tools to bolster security measures.

In today’s IT landscape, security remains paramount. With data breaches making headlines, setting strong password policies becomes not just an option but a necessity. As organizations look to fortify their defenses, an efficient way to update Windows password policies arises as a crucial topic.

Background

Password policies, especially in Windows environments, help define requirements for creating and maintaining passwords. Ensuring that these are stringent reduces the risk of unauthorized access. The script provided here is tailored for IT professionals and Managed Service Providers (MSPs) to effortlessly change the password complexity for either a domain or a non-domain computer.

Why is such a tool invaluable? Manually changing password policies, especially in large organizations, can be cumbersome. A script like this automates the process, making it quicker and less prone to human error.

The Script

#Requires -Version 5.1

<#
.SYNOPSIS
    Modifies the password complexity settings for a domain or a non-domain computer.
.DESCRIPTION
    This script can be used to enable or disable the password complexity requirement on a domain or a non-domain computer.
    When using -Domain, this script must be run on a Domain Controller with the RSAT feature installed.
.PARAMETER ComplexityEnabled
    Enables the Password Complexity requirement.
.PARAMETER Domain
    Specifies the name of the domain. If specified, it will enable or disable the password complexity requirement on the Active Directory Default Domain Password Policy.
    The computer this script is executed on MUST have the PowerShell RSAT features installed when using the -Domain flag.
.EXAMPLE
     -ComplexityEnabled
    Enables the password complexity requirement on the computer this script runs on.
.EXAMPLE
     No param needed
    Disables the password complexity requirement on the computer this script runs on.
.EXAMPLE
     -ComplexityEnabled -Domain "test.consto.com"
    Enables the password complexity requirement in Active Directory for the Default Domain Password Policy.
    When using -Domain, this script must be run on a Domain Controller with the RSAT feature installed.
.EXAMPLE
     -Domain "test.consto.com"
    Disables the password complexity requirement in Active Directory for the Default Domain Password Policy.
    When using -Domain, this script must be run on a Domain Controller with the RSAT feature installed.
.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Renamed script and added Script Variable support
 By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
.COMPONENT
    ManageUsers
#>

[CmdletBinding()]
param (
    [Parameter(Mandatory = $false)]
    [Switch]
    $ComplexityEnabled,
    [Parameter(Mandatory = $false)]
    [String]
    $Domain
)
begin {
    if ($env:activeDirectoryDomain -and $env:activeDirectoryDomain -notlike "null") {
        $Domain = $env:activeDirectoryDomain
    }

    if ($env:complexity -and $env:complexity -notlike "null") {
        switch ($env:complexity) {
            "Enable" { $ComplexityEnabled = $True }
            "Disable" { $ComplexityEnabled = $False }
        }
    }

    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        if ($p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
        { Write-Output $true }
        else
        { Write-Output $false }
    }
    function Test-DomainJoined {
        # Check if the computer is domain joined
        if ((Get-Command -Name Get-WmiObject -ErrorAction SilentlyContinue)) {
            return $(Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain
        }
        elseif ((Get-Command -Name Get-CIMInstance -ErrorAction SilentlyContinue)) {
            return $(Get-CimInstance -ClassName Win32_ComputerSystem).PartOfDomain
        }
        else {
            Write-Host "[Error] Get-WmiObject and Get-CIMInstance are not available. This script requires at least one of these cmdlets to run."
            exit 1
        }
    }
}
process {
    if (-not (Test-IsElevated)) {
        Write-Host "[Error] Access Denied. Please run with Administrator privileges."
        exit 1
    }
    
    if (-not ([string]::IsNullOrWhiteSpace($Domain))) {
        # Active Directory
    
        # Check if we are running on a Domain Controller, exit if we aren't
        $osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
        if ($osInfo.ProductType -ne 2) {
            Write-Host "[Error] This needs to run on a Domain Controller."
            exit 1
        }
        # Set ComplexityEnabled to what was passed into $ComplexityEnabled
        Set-ADDefaultDomainPasswordPolicy -Identity $Domain -ComplexityEnabled $(if ($ComplexityEnabled) { $true }else { $false }) -Confirm:$false
        # Sleep for a while, just in case Get-ADDefaultDomainPasswordPolicy connects to a different AD server and replication is slow
        Start-Sleep -Seconds 60
        # Check if the ComplexityEnabled policy was applied correctly
        $Results = Get-ADDefaultDomainPasswordPolicy -Identity $Domain
        # Check that the policy matches what was requested
        if ($Results -and $Results.ComplexityEnabled -eq $ComplexityEnabled) {
            Write-Host "[Info] Set Complexity in Default Domain Password Policy to $ComplexityEnabled"
            return
        }
        else {
            # The policy was not set for some reason
            Write-Host "[Error] Failed to set Complexity in Default Domain Password Policy to $ComplexityEnabled"
            exit 1
        }
    }
    else {
        # Localhost
        # Check if the computer is domain joined

        if ($(Test-DomainJoined)) {
            Write-Host "[Error] This Computer is domain joined. Modifying the local policy is not supported for domain joined computers."
            exit 1
        }

        # Set the path for our temp local policy config file
        $Path = "$PSScriptRoot\Set-Password-Complexity-secpol.cfg"
        # Get our local policy
        SecEdit.exe /export /cfg $Path
        if ($LASTEXITCODE -gt 0) {
            Write-Host "[Error] Failed to read local machine Policy"
            exit 1
        }

        # Next make sure that we are not changing something that does not need to be changed
        # if $ComplexityEnabled is True and the temp local policy config file has PasswordComplexity set to 0, then proceed
        if ($ComplexityEnabled -and $(Get-Content -Path $Path) -Match "^PasswordComplexity = 0$") {
            # Change PasswordComplexity from 0 to 1
            $(Get-Content -Path $Path) -Replace "PasswordComplexity = 0", "PasswordComplexity = 1" | Out-File $Path
            # Update the local policy with our changes
            SecEdit.exe /configure /db c:\windows\security\local.sdb /cfg $Path /areas SECURITYPOLICY
            if ($LASTEXITCODE -gt 0) {
                Write-Host "[Error] Failed to set Complexity in local machine Policy to $ComplexityEnabled"
                exit 1
            }
        }# if $ComplexityEnabled is False and the temp local policy config file has PasswordComplexity set to 1, then proceed
        elseif (-not $ComplexityEnabled -and $(Get-Content -Path $Path) -Match "^PasswordComplexity = 1$") {
            # Change PasswordComplexity from 1 to 0
            $(Get-Content -Path $Path) -Replace "PasswordComplexity = 1", "PasswordComplexity = 0" | Out-File $Path
            # Update the local policy with our changes
            SecEdit.exe /configure /db c:\windows\security\local.sdb /cfg $Path /areas SECURITYPOLICY
            if ($LASTEXITCODE -gt 0) {
                Write-Host "[Error] Failed to set Complexity in local machine Policy to $ComplexityEnabled"
                exit 1
            }
        }
        # Remove our temp local policy config file
        Remove-Item $Path -Force
        # Get our local policy
        SecEdit.exe /export /cfg $Path
        # Check if the temp local policy config file has PasswordComplexity set to match our $ComplexityEnabled
        if (
            ($ComplexityEnabled -and $(Get-Content $Path) -Match "^PasswordComplexity = 1$") -or
            (-not $ComplexityEnabled -and $(Get-Content $Path) -Match "^PasswordComplexity = 0$")
        ) {
            # Remove our temp local policy config file again
            Remove-Item $Path -Force
            Write-Host "[Info] Set Complexity in local machine Policy to $ComplexityEnabled"
            return
        }
        else {
            # Remove our temp local policy config file again
            Remove-Item $Path -Force
            Write-Host "[Error] Failed to set Complexity in local machine Policy to $ComplexityEnabled"
            exit 1
        }
    }
}
end {
    
    
    
}

 

Access 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

  • Initial Requirements: The script is designed for Windows 10 or Windows Server 2016. Additionally, if the Active Directory feature is used, RSAT for Active Directory should be installed.
  • Parameters: The script accepts two optional parameters:
  • $ComplexityEnabled: A switch that enables or disables password complexity.
  • $Domain: Specifies the domain name for which the password policy will be changed.
  • Elevation Check: Before any action, the script checks if it has administrator privileges. If not, it terminates, ensuring actions are only executed with the right permissions.
  • Active Directory: If a domain is specified, it:
  • Checks if it’s being run on a Domain Controller.
  • Validates the presence of the ActiveDirectory module.
  • Modifies the Default Domain Password Policy based on the $ComplexityEnabled parameter.
  • Local Policy: If no domain is specified, it:
  • Creates a temporary policy configuration file.
  • Checks the current password complexity setting.
  • Modifies this setting based on the $ComplexityEnabled parameter.

Potential Use Cases

Case Study: Imagine an IT professional, Jane, working in an organization that recently experienced phishing attacks. Her team decides to enforce stricter password policies. Instead of manually going through every system or domain controller, Jane uses this script. By simply running it with the desired parameters, she can swiftly update password policies, thus enhancing the organization’s security posture.

Comparisons

Traditionally, changing password policies in Windows often required navigating through multiple GUI-based interfaces, like Group Policy Management or Local Security Policy. While effective, these methods can be time-consuming. This PowerShell script streamlines the process, providing a quicker and more efficient approach.

FAQs

  • Which versions of Windows does this script support? 
    Windows 10 and Windows Server 2016.
  • Do I always need to specify a domain? 
    No, if you don’t specify a domain, the script will default to the local computer.
  • What happens if the script isn’t run with administrative privileges?
    It will terminate and provide an error message.

Implications

While the automation of password policy changes can expedite processes, it’s vital to notify users about these changes. Sudden password policy changes can lead to confusion and potential lockouts, impacting productivity. Moreover, from an IT security standpoint, regularly updating and enforcing password policies can dramatically reduce the risk of unauthorized access.

Recommendations

  • Always run the script in a test environment before applying it to a live setup.
  • Regularly review and adjust password policies in line with the latest security recommendations.
  • Educate users about the importance of strong passwords and the reason for policy changes.

Final Thoughts

In the context of enhanced IT security, tools like NinjaOne can play a pivotal role. Not only do they provide monitoring solutions, but they seamlessly integrate with scripts like the one discussed. By using NinjaOne alongside such automation tools, IT professionals can efficiently manage and bolster their organization’s security measures.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).