【问题标题】:PowerShell - Password Generator - How to always include number in string?PowerShell - 密码生成器 - 如何始终在字符串中包含数字?
【发布时间】:2016-09-12 08:59:53
【问题描述】:

我有以下 PowerShell 脚本,它创建一个 15 位的随机字符串,用作 Active Directory 密码。

问题是,这在大多数情况下都很好用,但在某些情况下它不使用数字或符号。我只收到15封信。这不能用作 Active Directory 密码,因为它必须至少包含一个数字或符号。

$punc = 46..46
$digits = 48..57
$letters = 65..90 + 97..122
$YouShallNotPass = get-random -count 15 `
-input ($punc + $digits + $letters) |
% -begin { $aa = $null } `
-process {$aa += [char]$_} `
-end {$aa}

Write-Host "Password is $YouShallNotPass"

如何修改脚本以使其始终包含至少一个随机数或符号?

谢谢。

【问题讨论】:

    标签: powershell passwords generator


    【解决方案1】:

    您可以调用Get-Random cmdlet 三次,每次使用不同的input 参数(双引号、数字和字母),连接结果字符串并使用另一个Get-Random 调用将它们打乱:

     (Get-Random -Count 15 -InputObject ([char[]]$yourPassword)) -join ''
    

    但是,您为什么要重新发明轮子?考虑使用以下GeneratePassword 函数:

    [Reflection.Assembly]::LoadWithPartialName("System.Web")
    [System.Web.Security.Membership]::GeneratePassword(15,2)
    

    并确保它至少包含一个随机数(您已经指定了符号的数量):

    do {
       $pwd = [System.Web.Security.Membership]::GeneratePassword(15,2)
    } until ($pwd -match '\d')
    

    【讨论】:

    • [System.Web.Security] 不在我的机器上。我该怎么办?此外,LoadWithPartialName 已被弃用。请改用[System.Reflection.Assembly]::Load()
    • (Get-Random -Count 15 -InputObject ([char[]]$yourPassword)) -join '' 变体从输入中选择随机值,但它永远不会重复选择,例如从数字集(10 位)中请求 15 个随机值将按随机顺序返回这 10 个数字,而不是 15。
    【解决方案2】:

    按照 jisaak 的建议,不能 100% 保证 Membership.GeneratePassword Method 生成符合 AD complexity requirements 的密码。

    这就是我重新发明轮子的原因:

    Function Create-String([Int]$Size = 8, [Char[]]$CharSets = "ULNS", [Char[]]$Exclude) {
        $Chars = @(); $TokenSet = @()
        If (!$TokenSets) {$Global:TokenSets = @{
            U = [Char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ'                                #Upper case
            L = [Char[]]'abcdefghijklmnopqrstuvwxyz'                                #Lower case
            N = [Char[]]'0123456789'                                                #Numerals
            S = [Char[]]'!"#$%&''()*+,-./:;<=>?@[\]^_`{|}~'                         #Symbols
        }}
        $CharSets | ForEach {
            $Tokens = $TokenSets."$_" | ForEach {If ($Exclude -cNotContains $_) {$_}}
            If ($Tokens) {
                $TokensSet += $Tokens
                If ($_ -cle [Char]"Z") {$Chars += $Tokens | Get-Random}             #Character sets defined in upper case are mandatory
            }
        }
        While ($Chars.Count -lt $Size) {$Chars += $TokensSet | Get-Random}
        ($Chars | Sort-Object {Get-Random}) -Join ""                                #Mix the (mandatory) characters and output string
    }; Set-Alias Create-Password Create-String -Description "Generate a random string (password)"
    

    用法:

    • Size 参数定义密码的长度。
    • CharSets 参数定义字符U 所在的复杂度, LNS 代表大写、小写、数字和符号。 如果以小写形式提供(ulns),则返回字符串 可能包含相关字符集中的任何字符,如果 以大写形式提供(ULNS)返回的字符串 至少包含相关字符中的一个字符 设置。
    • Exclude 参数允许您排除特定字符,例如 会导致混淆,例如字母数字 O 和数字 0(零)。

    示例:

    要创建一个长度为 8 个字符的密码,其中可能包含任何大写字符、小写字符和数字:

    Create-Password 8 uln
    

    创建一个长度为 12 个字符的密码,其中至少包含一个大写字符、一个小写字符、一个数字和一个符号,并且不包含字符 OLIoli01:

    Create-Password 12 ULNS "OLIoli01"
    

    最新的Create-String版本见:https://powersnippets.com/create-string/

    【讨论】:

    • 为什么要静态定义A-Z?只需做一个遍历 ASCII 范围的循环
    • 我同意,我本可以做类似U = 65..90 | % {[Char]$_} 的事情,但我想我没有这样做,因为符号不按顺序排列,我希望它保持一致。
    【解决方案3】:

    另一种解决方案:

    function New-Password() {
        param(
            [int] $Length = 10,
            [bool] $Upper = $true,
            [bool] $Lower = $true,
            [bool] $Numeric = $true,
            [string] $Special
        )
    
        $upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        $lowerChars = "abcdefghijklmnopqrstuvwxyz"
        $numericChars = "0123456789"
    
        $all = ""
        if ($Upper) { $all = "$all$upperChars" }
        if ($Lower) { $all = "$all$lowerChars" }
        if ($Numeric) { $all = "$all$numericChars" }
        if ($Special -and ($special.Length -gt 0)) { $all = "$all$Special" }
    
        $password = ""
        for ($i = 0; $i -lt $Length; $i++) {
            Write-Host "password: [$password]"
            $password = $password + $all[$(Get-Random -Minimum 0 -Maximum $all.Length)]
        }
    
        $valid = $true
        if ($Upper -and ($password.IndexOfAny($upperChars.ToCharArray()) -eq -1)) { $valid = $false }
        if ($Lower -and ($password.IndexOfAny($lowerChars.ToCharArray()) -eq -1)) { $valid = $false }
        if ($Numeric -and ($password.IndexOfAny($numericChars.ToCharArray()) -eq -1)) { $valid = $false }
        if ($Special -and $Special.Length -gt 1 -and ($password.IndexOfAny($Special.ToCharArray()) -eq -1)) { $valid = $false }
    
        if (-not $valid) {
            $password = New-Password `
                -Length $Length `
                -Upper $Upper `
                -Lower $Lower `
                -Numeric $Numeric `
                -Special $Special
        }
    
        return $password
    }
    

    足够灵活地设置长度,打开/打开/关闭大写、小写和数字,以及设置特价列表。

    【讨论】:

      【解决方案4】:

      使用现有功能生成随机密码的命令:

      [system.web.security.membership]::GeneratePassword(x,y)
      

      x = 密码长度
      y = 复杂度

      一般错误:

      找不到类型 [system.web.security.membership]。确保已加载包含此类型的程序集。

      解决方案:

      运行以下命令:

      Add-Type -AssemblyName System.web;
      

      【讨论】:

      【解决方案5】:

      我在这里遇到了同样的问题,我用来创建字母数字密码的 sn-p 很简单,我所做的只是使用 ASCII 正则表达式替换来使它变得更好。

      Function Password-Generator ([int]$Length)
      {
          # Generate passwords just call password-generator(lenght of password)
          $Assembly = Add-Type -AssemblyName System.Web
          $RandomComplexPassword = [System.Web.Security.Membership]::GeneratePassword($Length,2)
          $AlphaNumericalPassword = $RandomComplexPassword -replace '[^\x30-\x39\x41-\x5A\x61-\x7A]+'
          Write-Output $AlphaNumericalPassword
      }
      

      【讨论】:

      • 这个方法的问题是输出的“长度”永远不是输入的值,因为“替换”步骤。
      【解决方案6】:

      根据我在这里和互联网上的发现,我对在 PowerShell 中生成密码的看法:

      #Requires -Version 4.0
      [CmdletBinding(PositionalBinding=$false)]
      param (
          [Parameter(
              Mandatory = $false,
              HelpMessage = "Minimum password length"
          )]
          [ValidateRange(1,[int]::MaxValue)]
          [int]$MinimumLength = 24,
      
          [Parameter(
              Mandatory = $false,
              HelpMessage = "Maximum password length"
          )]
          [ValidateRange(1,[int]::MaxValue)]
          [int]$MaximumLength = 42,
      
          [Parameter(
              Mandatory = $false,
              HelpMessage = "Characters which can be used in the password"
          )]
          [ValidateNotNullOrEmpty()]
          [string]$Characters = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM@#%*-_+:,.'
      )
      
      (1..(Get-Random -Minimum $MinimumLength -Maximum $MaximumLength) `
      | %{ `
          $Characters.GetEnumerator() | Get-Random `
      }) -join ''
      

      我更喜欢使用 System.Web,而不是引入依赖项,这可能会随着 .Net / .Net Core 版本而改变。
      我的变体还允许随机密码长度(在指定范围内),相当简洁(除了非常冗长的参数部分,以强制执行一些验证并提供默认值)并允许字符重复(与问题中的代码相反,它从不重复相同的字符)。

      我了解,这并不能保证密码中有数字。然而,这可以通过不同的方式来解决。例如。正如建议的那样,重复生成直到密码符合要求(包含一个数字)。我的看法是:

      • 生成随机密码。
      • 如果它不包含数字(或总是):
        • 使用随机函数获取 1 个随机数字。
        • 将其添加到随机密码中。
        • 随机化结果的顺序(因此数字不一定总是在末尾)。

      假设上述脚本将被命名为“Get-RandomPassword.ps1”,它可能如下所示:

      $pass = .\Get-RandomPassword.ps1
      $pass += (0..9 | Get-Random)
      $pass = (($pass.GetEnumerator() | Get-Random -Count $pass.Length) -join '')
      Write-Output $pass
      

      这可以推广,使用任何字符类别强制执行:

      $sets = @('abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789', '()-_=+[{]};:''",<.>/?`~')
      $pass = .\Get-RandomPassword.ps1 -Characters ($sets -join '')
      foreach ($set in $sets) {
          $pass += ($set.GetEnumerator() | Get-Random)
      }
      $pass = (($pass.GetEnumerator() | Get-Random -Count $pass.Length) -join '')
      Write-Output $pass
      

      【讨论】:

        【解决方案7】:

        我在 PowerShell 中编写了一个安全密码生成器函数,也许这对某人有用。

        与接受的答案类似,此脚本也使用Get-Random(两次),以及正则表达式匹配以确保输出安全。 此脚本的不同之处在于密码长度也可以随机化。

        (要硬设置密码长度,只需将 MinimumPasswordLength 和 MaximumPasswordLength 值设置为相同长度即可。)

        它还允许一个易于编辑的字符集,并且还具有一个正则表达式,以确保已生成具有以下所有特征的体面的密码:

        (?=.*\d) 必须包含至少一个数字字符

        (?=.*[a-z]) 必须至少包含一个小写字符

        (?=.*[A-Z]) 必须至少包含一个大写字符

        (?=.*\W) 必须至少包含一个非单词字符

        关于始终在生成的输出中包含数字的问题的答案可以通过使用正则表达式匹配检查输出来解决(只需使用您需要的正则表达式部分,根据上面的解释),这里的例子检查大写、小写和数字:

        $Regex = "(?=.*\d)(?=.*[a-z])(?=.*[A-Z])"
        
        do {
                $Password = ([string]($AllowedPasswordCharacters |
                Get-Random -Count $PasswordLength) -replace ' ')
            }    until ($Password -cmatch $Regex)
        
        $Password
        

        这是完整的脚本:

        Function GeneratePassword
        {
            cls
            $MinimumPasswordLength = 12
            $MaximumPasswordLength = 16
            $PasswordLength = Get-Random -InputObject ($MinimumPasswordLength..$MaximumPasswordLength)
            $AllowedPasswordCharacters = [char[]]'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?@#£$%^&'
            $Regex = "(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W)"
        
            do {
                    $Password = ([string]($AllowedPasswordCharacters |
                    Get-Random -Count $PasswordLength) -replace ' ')
               }    until ($Password -cmatch $Regex)
        
            $Password
        
        }
        
        GeneratePassword
        

        【讨论】:

          【解决方案8】:

          我已经创建了这个。您可以选择创建多少个密码

          $howoften = Read-Host "How many would you like to create: "
          $i = 0
          do{
              (-join(1..42 | ForEach {((65..90)+(97..122)+(".") | % {[char]$_})+(0..9)+(".") | Get-Random}))
              $i++
          } until ($i -match $howoften)
          

          要更改密码的长度,只需编辑第 4 行中的“42”

          (-join(1..**42** | ForEach ...
          

          【讨论】:

            猜你喜欢
            • 2018-09-26
            • 2017-12-11
            • 2020-12-16
            • 2013-07-26
            • 2020-12-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多