Public/New-SecretSharingPassword.ps1

function New-SecretSharingPassword {
    <#
    .SYNOPSIS
        Generates a random, typeable password at a given entropy level.
    .DESCRIPTION
        Returns a cryptographically random password as a SecureString, built with the
        same one-byte-per-character convention as New-SecretSharingSecret's output, so
        it can be split and reconstructed via Split-/Join-SecretSharingSecret exactly
        like any other secret - the value recovered from a quorum of shares is the
        literal original password, not a derived value.

        Unlike New-SecretSharingSecret's raw random bytes (values 0-255, not meant to
        be typed, displayed, or used outside this module), this password is built only
        from characters that are safe to type, paste, or store in a shell command, URL,
        CSV file, JSON document, or SQL statement without extra escaping - see
        Get-SecretSharingPasswordConstant for the exact alphabet and the reasoning
        behind each excluded character.

        Because that alphabet carries fewer than 8 bits of entropy per character
        (~6.23 bits/character for its 75-character alphabet, vs. 8 for a raw byte), the
        password is longer than New-SecretSharingSecret's 16/32 bytes - long enough
        that its total entropy is at least the requested Entropy value, rounded up to
        an even character count (Split-SecretSharingSecret requires an even byte
        count).
    .PARAMETER Entropy
        The minimum entropy of the generated password, in bits. Must be 128 or 256,
        matching New-SecretSharingSecret's supported levels.
    .EXAMPLE
        PS> $password = New-SecretSharingPassword -Entropy 128
        PS> Split-SecretSharingSecret -Secret $password -Group @{ Threshold = 3; Count = 5 }
        Generates a typeable password with at least 128 bits of entropy and splits it
        into 5 shares, any 3 of which reconstruct the exact same password.
    .OUTPUTS
        System.Security.SecureString
    #>

    [CmdletBinding()]
    [OutputType([System.Security.SecureString])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'Pure in-memory computation (random bytes); no external state is changed.')]
    param(
        [Parameter(Mandatory)]
        [ValidateSet(128, 256)]
        [int]$Entropy
    )

    $constant = Get-SecretSharingPasswordConstant
    $bitsPerCharacter = [Math]::Log($constant.Alphabet.Length, 2)
    $characterCount = [int][Math]::Ceiling($Entropy / $bitsPerCharacter)
    if ($characterCount % 2 -ne 0) {
        $characterCount++
    }

    $passwordByte = Get-SecretSharingRandomAlphabetByte -Alphabet $constant.Alphabet -Length $characterCount
    return ConvertTo-SecretSharingSecureString -Byte $passwordByte
}