UniversalToolbox.psm1

function Export-SecureString {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateScript({if (-not (Test-Path -Path (Split-Path -Path $_ -Parent))) {throw "Cannot find path '$_' because it does not exist."} else {$true}})]
        [string]
        $Path,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $String,

        [Parameter(Mandatory = $false)]
        [switch]
        $UseKey
    )

    DynamicParam {
        if ($PSBoundParameters.ContainsKey('UseKey') -and $PSBoundParameters.UseKey) {
            $mandatory = $false
            $validateSet = 128, 192, 256
            $type = [int]
            $name = 'KeyLength'
            $defaultValue = 256

            $attributeCollection = New-Object -TypeName 'System.Collections.ObjectModel.Collection[System.Attribute]'

            $parameterAttribute = New-Object -TypeName 'System.Management.Automation.ParameterAttribute'
            $parameterAttribute.Mandatory = $mandatory
            $attributeCollection.Add($parameterAttribute)

            $validateSetAttribute = New-Object -TypeName 'System.Management.Automation.ValidateSetAttribute' -ArgumentList $validateSet
            $attributeCollection.Add($validateSetAttribute)

            $runtimeDefinedParameter = New-Object -TypeName 'System.Management.Automation.RuntimeDefinedParameter' -ArgumentList $name, $type, $attributeCollection
            $PSBoundParameters.$name = $defaultValue

            $runtimeDefinedParameterDictionary = New-Object -TypeName 'System.Management.Automation.RuntimeDefinedParameterDictionary'
            $runtimeDefinedParameterDictionary.Add($name, $runtimeDefinedParameter)
            $runtimeDefinedParameterDictionary
        }
    }

    begin {}
    
    process {
        $convertFrom = @{}

        if ($PSBoundParameters.ContainsKey('UseKey') -and $PSBoundParameters.UseKey) {
            $keyPath = Join-Path -Path (Split-Path -Path $Path) -ChildPath ([System.IO.Path]::GetFileNameWithoutExtension($Path) + '.key')
            $encryptionKey = New-Object -TypeName 'System.Byte[]' -ArgumentList ($PSBoundParameters.KeyLength / 8)
            $RNGCryptoServiceProvider = New-Object -TypeName 'System.Security.Cryptography.RNGCryptoServiceProvider'
            $RNGCryptoServiceProvider.GetBytes($encryptionKey)

            $convertFrom += @{Key = $encryptionKey}
            Out-File -FilePath $keyPath -InputObject $encryptionKey -Verbose:$PSBoundParameters.ContainsKey('Verbose')
        }

        $encryptedStandardString = ConvertTo-SecureString -String $String -AsPlainText -Force | ConvertFrom-SecureString @convertFrom
        Out-File -FilePath $Path -InputObject $encryptedStandardString -Verbose:$PSBoundParameters.ContainsKey('Verbose')
    }
    
    end {}
}
function Import-SecureString {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateScript({if (-not (Test-Path -Path $_)) {throw "Cannot find path '$_' because it does not exist."} else {$true}})]
        [string]
        $Path,

        [Parameter(Mandatory = $false)]
        [ValidateScript({if (-not (Test-Path -Path $_)) {throw "Cannot find path '$_' because it does not exist."} else {$true}})]
        [string]
        $KeyPath,

        [Parameter(Mandatory = $false)]
        [switch]
        $AsPlainText
    )
    
    begin {}
    
    process {
        $string = Get-Content -Path $Path
        $convertTo = @{String = $string}

        if ($PSBoundParameters.ContainsKey('KeyPath')) {
            $key = Get-Content -Path $KeyPath
            $convertTo += @{Key = $key}
        }

        $secureString = ConvertTo-SecureString @convertTo

        if ($PSBoundParameters.ContainsKey('AsPlainText') -and $PSBoundParameters.AsPlainText) {
            $credential = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList 'UserName', $secureString
            Write-Output -InputObject $credential.GetNetworkCredential().Password
        }
        else {
            Write-Output -InputObject $secureString
        }
    }
    
    end {}
}
function New-Password {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateRange(1, 128)]
        [int]
        $Length,

        [Parameter(Mandatory = $false)]
        [switch]
        $NoPunctuation
    )
    
    begin {
        Add-Type -AssemblyName 'System.Web'
        
        $punctuation = '!@#$%^&*()_-+=[{]};:<>|./?'.ToCharArray()
        $lettersAndNumbers = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.ToCharArray()
    }
    
    process {
        $password = [System.Web.Security.Membership]::GeneratePassword($Length, 0)

        if ($PSBoundParameters.ContainsKey('NoPunctuation') -and $PSBoundParameters.NoPunctuation) {
            $characters = $password.ToCharArray()

            $characterArray = foreach ($character in $characters) {
                if ($character -in $punctuation) {
                    $character = Get-Random -InputObject $lettersAndNumbers
                }

                Write-Output -InputObject $character
            }

            $password = -join $characterArray
        }

        Write-Output -InputObject $password
    }
    
    end {}
}