TM-RandomUtility.psm1

using namespace System
using namespace System.IO
using namespace System.Collections.Generic
using module TM-ValidationUtility


function Get-ExceptionTypeName {
<#
    .SYNOPSIS
    Returns the exception type name that occurred when executing a script block or command.
 
    .DESCRIPTION
    This function executes the provided command or script block and returns the full name of the exception type
    that occurred during execution.
    Only use this function if you know the exception will not cause further damage by running again.
 
    .PARAMETER Command
    The command to execute
 
    .PARAMETER ScriptBlock
    The script block to execute
 
    .EXAMPLE
    Get-HelpFromType -TypeNames (Get-ExceptionTypeName -Command 'Write-Error "test"')
 
    .OUTPUTS
    If the provided command causes an exception then the exception's typename will be returned.
    If the provided command does NOT cause an exception then nothing is returned.
#>

    [CmdletBinding(DefaultParameterSetName = 'string')]
    [OutputType([Void], [string])]
    param (
        [Parameter(
            Mandatory,
            ValueFromPipeline,
            ValueFromRemainingArguments,
            ParameterSetName = 'string'
        )]
        [ValidateNotNullOrEmpty()]
        [string]$Command,

        [Parameter(
            Mandatory,
            ValueFromPipeline,
            ValueFromRemainingArguments,
            ParameterSetName = 'ScriptBlock'
        )]
        [scriptblock]$ScriptBlock
    )

    [ScriptBlock]$SB = switch ($PSCmdlet.ParameterSetName) {
        'string' { [ScriptBlock]::Create($Command) }
        'ScriptBlock' { $ScriptBlock }
    }
    $ErrorActionPreference = 'Stop'
    try {
        $SB.Invoke() | Out-Null
    } catch {
        return $_.Exception.GetType().FullName
    }
}


function Get-HelpFromType {
<#
    .SYNOPSIS
    Opens the documentation for .NET types in a web browser.
 
    .DESCRIPTION
    This function opens the official Microsoft documentation for .NET types in the default web browser.
 
    .PARAMETER Objects
    Array of objects to determine the type of and fetch the documentation for.
 
    .EXAMPLE
    Get-HelpFromType -TypeNames @($Object1.GetType().FullName, ($Error[-1].Exception.GetType().FullName))
 
    .EXAMPLE
    Get-HelpFromType -Types $Error[-1].Exception.GetType()
#>

    [CmdletBinding(DefaultParameterSetName = 'TypeNames')]
    [OutputType([Void])]
    param (
        [Parameter(
            Mandatory,
            ValueFromPipeline,
            ValueFromRemainingArguments,
            ParameterSetName = 'TypeNames'
        )]
        [string[]]$TypeNames,

        [Parameter(
            Mandatory,
            ValueFromPipeline,
            ValueFromRemainingArguments,
            ParameterSetName = 'Types'
        )]
        [Type[]]$Types
    )
    process {
        [string[]]$InputTypes = switch ($PSCmdlet.ParameterSetName) {
            'Types' {
                [List[string]]$typeList = [List[string]]::new()
                foreach ($Type in $Types) {
                    $typeList.Add($Type.FullName)
                }
                $typeList.ToArray()
            }
            'TypeNames' { $TypeNames }
        }
        foreach ($typeName in $InputTypes) {
            Start-Process -FilePath "https://docs.microsoft.com/en-us/dotnet/api/$typeName"
        }
    }
}


function New-Timer {
<#
    .SYNOPSIS
    Starts a new timer.
 
    .DESCRIPTION
    This function creates and starts a new stopwatch timer.
#>

    [CmdletBinding()]
    [OutputType([Diagnostics.Stopwatch])]
    param ()
    return [Diagnostics.Stopwatch]::StartNew()
}


function Test-ApplicationExistsInPath {
<#
    .SYNOPSIS
    Uses Get-Command to see whether the $ApplicationName exists in the path.
#>

    [CmdletBinding()]
    [OutputType([boolean])]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$ApplicationName
    )

    return ($null -ne (Get-Command $ApplicationName -CommandType Application -ErrorAction Ignore))
}


function Write-RandomBytesToFile {
<#
    .SYNOPSIS
    Writes random bytes to a file.
 
    .DESCRIPTION
    This function writes random bytes to a file until that file has reached the specified fileByteSize.
    If the file is already greater than fileByteSize then the function exits early.
 
    .PARAMETER fileByteSize
    The desired file size in bytes
 
    .PARAMETER fileName
    The name of the file to write to, default is 'temp.rnd'
 
    .PARAMETER directoryPath
    The directory path where the file will be created or updated, default is the current directory
#>

    [CmdletBinding()]
    [OutputType([Void])]
    param (
        [Parameter(Mandatory)]
        [long]$fileByteSize,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$fileName = 'temp.rnd',

        [Parameter(Mandatory = $false)]
        [ValidatePathExists([PathType]::Folder)]
        [string]$directoryPath = [Environment]::CurrentDirectory
    )

    [string]$filePath = Join-Path -Path $directoryPath -ChildPath $fileName
    [Random]$rnd = [Random]::New()
    [IO.FileInfo]$file = [IO.FileInfo]::New($filePath);
    if ($file.Length -ge $fileByteSize) {
        Write-Host "File size for '$($file.FullName)' already meets or exceeds $fileByteSize"
        return
    }
    [IO.FileStream]$outputStream
    try {
        $outputStream = [IO.File]::Open($file.FullName, [IO.FileMode]::OpenOrCreate)
        $outputStream.Seek(0, [IO.SeekOrigin]::End) | Out-Null
        [long]$bytesWritten = $file.Length
        do {
            [byte[]]$bytes = [byte[]]::New(
                (. {
                    if ($fileByteSize -gt ($bytesWritten + 1024)) {
                        1024
                    } else {
                        [int]($fileByteSize - $bytesWritten)
                    }
                })
            )
            $rnd.NextBytes($bytes)

            $outputStream.Write($bytes, 0, $bytes.Length)
            $bytesWritten += $bytes.Length
        } while ($bytesWritten -lt $fileByteSize)

        Write-Host "Wrote $bytesWritten bytes to '$($file.FullName)'. FileSize: $fileByteSize"
    } finally {
        if ($null -ne $outputStream) { $outputStream.Dispose() }
    }
}