首页 > 解决方案 > PowerShell New-ADUser 仍然创建禁用用户

问题描述

这是对Powershell New-ADUser 错误处理密码复杂性(ActiveDirectory 模块)的搭载,因为它涉及在执行此类操作时不满足密码复杂性规则并且无论如何都会创建新(禁用)用户的场景:

New-ADUser test1 -Givenname test -surname test -AccountPassword (ConvertTo-SecureString "abc" -AsPlainText -Force)

如果密码未能通过复杂性检查无济于事,我已经尝试try/catch [Microsoft.ActiveDirectory.Management.ADPasswordComplexityException]以及按照链接帖子中的建议$ErrorAction = Stop使用New-ADUser... -ErrorAction Stop,以防止创建新的(禁用的)用户。

我使用的环境是 Server 2019 和 PS 5.1

我很想知道为什么在过去使用$ErrorAction = "Stop"with显然可以防止创建禁用用户,但今天却没有。New-ADUser... -ErrorAction Stop我已经搜索了高低,无法提出解决方案,或更重要的是,我无法理解为什么ErrorAction在这种特定情况下以任何身份使用都不能按照我期望的方式工作。任何人都可以帮助我这一天的这段时间不要白痴吗?

-更新的问题文本如下-

为了在 prod 环境中应用它,我有动力遵循正式记录的复杂性规则,特别是:

“任何归类为字母字符但不是大写或小写的 Unicode 字符。该组包括来自亚洲语言的 Unicode 字符。”

我遇到了一篇实现相当可靠的正则表达式模式的帖子,但正如用户在底部评论的那样 - 版权符号(其中包括 pi π)应该是有效的,但提供的正则表达式模式不占子集Unicode 字符。追求 2 个解决方案中的 1 个似乎是合理的,以便允许所有接受的字符:

  1. 如 MS 文档中所述,制作完美的正则表达式来解释所有允许的 unicode 字符
  2. 使用 try/catch [Microsoft.ActiveDirectory.Management.ADPasswordComplexityException] ,因为这应该可靠地拒绝不完全符合复杂性规则的密码。

对于 prod 中的密码复杂性规则合规性(以及在密码不被接受时避免创建新的禁用用户),与手动考虑所有已知异常相比,#2 似乎是一种更合理的方法。我会从一个糟糕的角度来解决这个问题吗?

标签: powershellactive-directorypasswords

解决方案


为避免由于密码不符合域密码复杂性规则而创建禁用用户,您可以使用此辅助函数:

function Test-DomainPassword {
    # see: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$Password,

        [string]$SamAccountName = $null,
        [string]$DisplayName = $null
    )
    $PasswordPolicy = Get-ADDefaultDomainPasswordPolicy -ErrorAction SilentlyContinue

    if ($Password.Length -lt $PasswordPolicy.MinPasswordLength) {
        Write-Verbose "Password '$Password' is too short. Minimal length is $($PasswordPolicy.MinPasswordLength)"
        return $false
    }
    if (($SamAccountName) -and ($Password -match [regex]::Escape($SamAccountName))) {
        Write-Verbose "The password '$Password' includes the users SamAccountName"
        return $false
    }
    if ($DisplayName) {
        # The displayName is parsed for delimiters: commas, periods, dashes or hyphens, underscores, spaces, pound signs, and tabs.
        # If any of these delimiters are found, the displayName is split and all parsed sections (tokens) are confirmed not to be
        # included in the password.
        # Tokens that are shorter than three characters are ignored, and substrings of the tokens aren't checked.
        $tokens = $DisplayName.Split(",.-,_ #`t")
        foreach ($token in $tokens) {
            if (($token) -and ($token.Length -ge 3) -and ($Password -match [regex]::Escape($token))) {
                Write-Verbose "The password '$Password' includes (part of) the users DisplayName"
                return $false
            }
        }
    }
    if ($PasswordPolicy.ComplexityEnabled) {
        # see: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb726984(v=technet.10)?redirectedfrom=MSDN
        # chapter 'Passwords Must Meet Complexity Requirements':
        # Passwords must use three of the four available character types:
        # lowercase letters, uppercase letters, numbers, and symbols.

        $failures = @()
        # check for presence of
        # - Uppercase: A through Z, with diacritic marks, Greek and Cyrillic characters
        if ($Password -cnotmatch "[A-Z\p{Lu}\s]") {
            $failures += "- The password is missing Uppercase characters"
        }
        # - Lowercase: a through z, sharp-s, with diacritic marks, Greek and Cyrillic characters
        if ($Password -cnotmatch "[a-z\p{Ll}\s]") {
            $failures += "- The password is missing Lowercase characters"
        }
        # - Base 10 digits (0 through 9)
        if ($Password -notmatch "[\d]") {
            $failures += "- The password is missing digits (0-9)"
        }
        # - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
        if ($Password -notmatch "[^\w]") {
            $failures += "- The password is missing Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;`"'<>,.?/"
        }
        # test if we have more than 1 mismatch (password needs at least 3 out of 4 to be OK)
        if ($failures.Count -gt 1) {
            Write-Verbose "The password '$Password' failed because:`r`n{0}" -f ($failures -join "`r`n")
            return $false
        }
    }

    $true
}

像这样使用它:

# both parameters -SamAccountName and -DisplayName are optional
if (Test-DomainPassword -Password 'abc' -SamAccountName 'test1' -DisplayName 'Paul Test' -Verbose) {
    # the password is OK, create the new user here:
    $userParams = @{
        SamAccountName        = 'test1'
        GivenName             = 'Paul'
        Surname               = 'Test'
        DisplayName           = 'Paul Test'
        AccountPassword       = ConvertTo-SecureString -String 'abc' -AsPlainText -force
        Enabled               = $true
        # etcetera
    }

    New-ADUser @userParams
}
else {
    Write-Warning "User 'test1' NOT created because the password did not pass the test"
}

推荐阅读