Public/New-RandomPassword.ps1

function New-RandomPassword {
    <#
    .SYNOPSIS
        Generates a random password.
    .DESCRIPTION
        This function uses the RNGCryptoServiceProvider to genereate a random password of the
        provided length.
    .PARAMETER Length
        How many characters long the random password should be.
    .PARAMETER AsPlainText
        When specified, the generated random password will be emitted as plaint text instead of
        as a secure string.
    .INPUTS
        System.Int32
    .OUTPUTS
        System.String
        System.Security.SecureString
    .EXAMPLE
        New-RandomPassword

        Generates a random password that is 16 characters long, with 4 levels of complexity,
        and emits it as a secure string.
    .EXAMPLE
        New-RandomPassword -Length 20

        Generates a random password that is 20 charactres long, with 4 levels of complexity,
        and emits it as a secure string.
    .EXAMPLE
        New-RandomPassword -AsPlainText

        Generates a random password that is 16 characters long, with 4 levels of complexity,
        and emits it as a plaintext string.
    #>

    param (
        [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)]
        [ValidateRange(2, [int]::MaxValue)]
        [int]$Length = 16,
        [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 1)]
        [switch]$AsPlainText
    )

    $lower = 'abcdefghijklmnopqrstuvwxyz'
    $upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    $digits = '0123456789'
    $symbols = '!@#$%^&*()'
    $allChars = @($lower, $upper, $digits, $symbols) -join ''

    do {
        $bytes = New-Object byte[] $Length
        [System.Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($bytes)
        $rawPassword = -join ($bytes | ForEach-Object { $allChars[$_ % $allChars.Length] })
        $hasLower = $rawPassword -match '[a-z]'
        $hasUpper = $rawPassword -match '[A-Z]'
        $hasDigit = $rawPassword -match '\d'
        $hasSymbol = $rawPassword -match '[!@#$%^&*()]'
        $complexityCount = ($hasLower + $hasUpper + $hasDigit + $hasSymbol)
    } while ($complexityCount -lt 3)

    switch ( $PSBoundParameters.ContainsKey('AsPlainText') ) {
        $true {
            $rawPassword | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString -AsPlainText
        }
        $false {
            
            $rawPassword | ConvertTo-SecureString -AsPlainText -Force
        }
    }
}