Public/Functions/New-RandomNumber.ps1

function New-RandomNumber {
    <#
    .SYNOPSIS
    Generate a cryptographically secure number
 
    .DESCRIPTION
    Generate a cryptographically secure number based on System.Security.Cryptography.RNGCryptoServiceProvider
 
    .INPUTS
    [int]Minimum
    [int]Maximum
 
    .OUTPUTS
    [int] : Cryptographically secure random number
 
    .EXAMPLE
    # Will generate a random number between 0 and 2147483647
    New-RandomNumber
 
    .EXAMPLE
    # Will generate a random number between 10 and 50
    New-RandomNumber -Minimum 10 -Maximum 50
     
    #>

    [CmdletBinding()]
    
    param (
        <#
        Sets the minimum number that should be returned within a possible range
        #>

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [ValidateRange(0, [int]::MaxValue)]
        [int]$Minimum = 0,

        <#
        Sets the maximum number that should be returned within a possible range
        #>

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [ValidateRange(1, [int]::MaxValue)]
        [int]$Maximum = [int]::MaxValue
    )

    begin {
        try {
            #################################
            # Opening Message
            Write-Verbose -Message "Function Start: ""$($MyInvocation.MyCommand.Name)""" -Verbose:$VerbosePreference
        }
        catch {
            throw $PSItem
        }
    }

    process {
        #################################
        # Variables
        try {
            $DebugAllEnabled = $null
            $DebugAllEnabled = $Global:DebugPreference -eq 'Continue'
            Write-Debug -Message "DebugAllEnabled: ""$($DebugAllEnabled)""" -Debug:$DebugPreference
            
            $VerboseAllEnabled = $null
            $VerboseAllEnabled = $Global:VerbosePreference -eq 'Continue'
            Write-Debug -Message "VerboseAllEnabled: ""$($VerboseAllEnabled)""" -Debug:$DebugPreference
            
            $DebugInternalEnabled = $null
            $DebugInternalEnabled = $PSBoundParameters.Debug.IsPresent -eq $true -or $DebugAllEnabled -eq $true
            Write-Debug -Message "DebugInternalEnabled: ""$($DebugInternalEnabled)""" -Debug:$DebugPreference
            
            $VerboseInternalEnabled = $null
            $VerboseInternalEnabled = $PSBoundParameters.Verbose.IsPresent -eq $true -or $VerboseAllEnabled -eq $true
            Write-Debug -Message "VerboseInternalEnabled: ""$($VerboseInternalEnabled)""" -Debug:$DebugPreference
            
            $ExternalCommandSplat = $null
            $ExternalCommandSplat = @{
                Debug       = $DebugAllEnabled
                ErrorAction = "Stop"
                Verbose     = $VerboseAllEnabled
            }
            If ($DebugInternalEnabled -eq $true) {
                Write-Debug -Message "ExternalCommandSplat: $(ConvertTo-Json @ExternalCommandSplat -InputObject $ExternalCommandSplat)" -Debug:$DebugPreference
            }
            
            $InternalCommandSplat = $null
            $InternalCommandSplat = @{
                Debug       = $DebugInternalEnabled
                ErrorAction = "Stop"
                Verbose     = $VerboseInternalEnabled
            }
            If ($DebugInternalEnabled -eq $true) {
                Write-Debug -Message "InternalCommandSplat: $(ConvertTo-Json @ExternalCommandSplat -InputObject $InternalCommandSplat)" -Debug:$DebugPreference
            }

            $BufferSize = $null
            $BufferSize = 4
            Write-Debug @InternalCommandSplat -Message "BufferSize: ""$($BufferSize)"""

        }
        catch {
            Throw $PSItem
        }


        #################################
        # Validate range
        try {
            
            if ($Minimum -ge $Maximum) {
                Throw  "Invalid range: Minimum ""$($Minimum)"" must be less than Maximum ""$($Maximum)""."
            }
        }
        catch {
            Throw $PSItem
        }

        #################################
        # Generate the random number
        try {
            Write-Verbose @InternalCommandSplat -Message "Creating the RNGCryptoServiceProvider object"
            $RNGCryptoServiceProvider = $null
            $RNGCryptoServiceProvider = New-Object @ExternalCommandSplat -TypeName "System.Security.Cryptography.RNGCryptoServiceProvider"

            Write-Verbose @InternalCommandSplat -Message "Creating a buffer of bytes"
            $Buffer = $null
            $Buffer = New-Object @ExternalCommandSplat -TypeName "byte[]" -ArgumentList $BufferSize

            Write-Verbose @InternalCommandSplat -Message "Getting bytes"
            $RNGCryptoServiceProvider.GetBytes($Buffer)

            Write-Verbose @InternalCommandSplat -Message "Getting random value"
            $RandomValue = $null
            $RandomValue = [BitConverter]::ToUInt32($Buffer, 0)
            
            Write-Verbose @InternalCommandSplat -Message "Setting the range"
            $Range = $null
            $Range = $Maximum - $Minimum

            Write-Verbose @InternalCommandSplat -Message "Generating the random number"
            $RandomNumber = $null
            $RandomNumber = $Minimum + $RandomValue % ($Range + 1)

            Write-Verbose @InternalCommandSplat -Message "Returning the random number"
            Write-Output @ExternalCommandSplat -InputObject $RandomNumber
        }
        catch {
            Throw $PSItem
        }

    }

    end {

        #################################
        # Closing Message
        try {
            Write-Verbose -Message "Function End: ""$($MyInvocation.MyCommand.Name)""" -Verbose:$VerbosePreference
        }
        catch {
            Throw $PSItem
        }
    }

}