CurrencyConverter.psm1

function Convert-CryptoCurrency {
    <#
    .SYNOPSIS
        Converts a decimal value between specified crypto and/or non-crypto currencies
 
    .DESCRIPTION
        Uses the Coin Base API (https://api.coinbase.com/v2/exchange-rates) to perform currency conversions.
        Caches the conversion rates for the specified currency for a number of seconds if -CacheSeconds is specified.
 
    .PARAMETER Value
        The amount you want to convert between currencies.
 
    .PARAMETER From
        The currency to convert from.
 
    .PARAMETER To
        The currency to convert to.
 
    .PARAMETER CacheSeconds
        Number of seconds to cache the result. Default: 0.
 
    .INPUTS
        A numerical value, can be provided via the pipeline.
 
    .EXAMPLE
        100 | Convert-CryptoCurrency -From BTC -To ETH
 
        Description
        -----------
        Converts the value 100 (provided via the pipeline) from BTC (Bitcount) to ETH (Ether), example result: 2149.6130696474600
 
    .EXAMPLE
        Convert-CryptoCurrency -Value 100 -From ETH -To GBP
 
        Description
        -----------
        Converts the value 100 from ETH (Ether) to GBP (British Pound), example result: 245122.500
 
    .EXAMPLE
        Convert-CryptoCurrency -Value 1 -From BTC -To ETH | Format-Currency
 
        Description
        -----------
        Converts 1 BTC to ETH and pipes the result to Format-Currency, which picks up the destination currency (ETH) from the pipeline, example result: Ξ21.4961307
    #>

    [cmdletbinding()]
    [OutputType([decimal])]
    param(
        [parameter(ValueFromPipeline, Mandatory, Position = 0)]
        [decimal]
        $Value,

        [validateset('00', '1INCH', 'AAVE', 'ABT', 'ACH', 'ACS', 'ADA', 'AERGO', 'AERO', 'AGLD', 'AIOZ', 'AKT', 'ALCX', 'ALEPH', 'ALGO', 'ALICE', 'AMP', 'ANKR', 'ANT', 'APE', 'API3', 'APT', 'ARB', 'ARKM', 'ARPA', 'ASM', 'AST', 'ATA', 'ATOM', 'AUCTION', 'AUDIO', 'AURORA', 'AVAX', 'AVT', 'AXL', 'AXS', 'BADGER', 'BAL', 'BAND', 'BAT', 'BCH', 'BICO', 'BIGTIME', 'BIT', 'BLUR', 'BLZ', 'BNT', 'BOBA', 'BOND', 'BONK', 'BTC', 'BTRST', 'BUSD', 'C98', 'CBETH', 'CELR', 'CGLD', 'CHZ', 'CLV', 'COMP', 'COTI', 'COVAL', 'CRO', 'CRPT', 'CRV', 'CTSI', 'CTX', 'CVC', 'CVX', 'DAI', 'DAR', 'DASH', 'DDX', 'DESO', 'DEXT', 'DIA', 'DIMO', 'DNT', 'DOGE', 'DOT', 'DREP', 'DRIFT', 'DYP', 'EGLD', 'ELA', 'ENJ', 'ENS', 'EOS', 'ERN', 'ETC', 'ETH', 'EUR', 'EUROC', 'FARM', 'FET', 'FIDA', 'FIL', 'FIS', 'FLOW', 'FLR', 'FORT', 'FORTH', 'FOX', 'FX', 'GAL', 'GALA', 'GBP', 'GFI', 'GHST', 'GLM', 'GMT', 'GNO', 'GNT', 'GODS', 'GRT', 'GST', 'GTC', 'GUSD', 'GYEN', 'HBAR', 'HFT', 'HIGH', 'HNT', 'HONEY', 'HOPR', 'ICP', 'IDEX', 'ILV', 'IMX', 'INDEX', 'INJ', 'INV', 'IOTX', 'JASMY', 'JTO', 'JUP', 'KARRAT', 'KAVA', 'KEEP', 'KNC', 'KRL', 'KSM', 'LCX', 'LDO', 'LINK', 'LIT', 'LOKA', 'LOOM', 'LPT', 'LQTY', 'LRC', 'LSETH', 'LTC', 'MAGIC', 'MANA', 'MASK', 'MATH', 'MATIC', 'MCO2', 'MDT', 'MEDIA', 'METIS', 'MINA', 'MIR', 'MKR', 'MLN', 'MNDE', 'MOBILE', 'MONA', 'MPL', 'MSOL', 'MTL', 'MULTI', 'MUSD', 'MUSE', 'MXC', 'NCT', 'NEAR', 'NEON', 'NEST', 'NKN', 'NMR', 'NU', 'OCEAN', 'OGN', 'OMG', 'OMNI', 'ONDO', 'OOKI', 'OP', 'ORCA', 'ORN', 'OSMO', 'OXT', 'PAX', 'PERP', 'PLA', 'PLU', 'PNG', 'POLS', 'POLY', 'POND', 'POWR', 'PRIME', 'PRO', 'PRQ', 'PUNDIX', 'PYR', 'PYUSD', 'QI', 'QNT', 'QSP', 'QUICK', 'RAD', 'RAI', 'RARE', 'RARI', 'RBN', 'REN', 'RENDER', 'REP', 'REQ', 'RGT', 'RLC', 'RLY', 'RNDR', 'RONIN', 'ROSE', 'RPL', 'SAFE', 'SAND', 'SEAM', 'SEI', 'SHDW', 'SHIB', 'SHPING', 'SKL', 'SNT', 'SNX', 'SOL', 'SPA', 'SPELL', 'STG', 'STORJ', 'STRK', 'STX', 'SUI', 'SUKU', 'SUPER', 'SUSHI', 'SWFTC', 'SYLO', 'SYN', 'T', 'TBTC', 'TIA', 'TIME', 'TNSR', 'TONE', 'TRAC', 'TRB', 'TRIBE', 'TRU', 'TVK', 'UMA', 'UNFI', 'UNI', 'UPI', 'USD', 'USDC', 'USDT', 'UST', 'VARA', 'VELO', 'VET', 'VGX', 'VOXEL', 'VTHO', 'WAMPL', 'WAXL', 'WBTC', 'WCFG', 'WLUNA', 'XCN', 'XLM', 'XMON', 'XRP', 'XTZ', 'XYO', 'YFI', 'YFII', 'ZEC', 'ZEN', 'ZETA', 'ZRX')]
        [parameter(Mandatory)]
        [string]
        $From,
        
        [validateset('00', '1INCH', 'AAVE', 'ABT', 'ACH', 'ACS', 'ADA', 'AERGO', 'AERO', 'AGLD', 'AIOZ', 'AKT', 'ALCX', 'ALEPH', 'ALGO', 'ALICE', 'AMP', 'ANKR', 'ANT', 'APE', 'API3', 'APT', 'ARB', 'ARKM', 'ARPA', 'ASM', 'AST', 'ATA', 'ATOM', 'AUCTION', 'AUDIO', 'AURORA', 'AVAX', 'AVT', 'AXL', 'AXS', 'BADGER', 'BAL', 'BAND', 'BAT', 'BCH', 'BICO', 'BIGTIME', 'BIT', 'BLUR', 'BLZ', 'BNT', 'BOBA', 'BOND', 'BONK', 'BTC', 'BTRST', 'BUSD', 'C98', 'CBETH', 'CELR', 'CGLD', 'CHZ', 'CLV', 'COMP', 'COTI', 'COVAL', 'CRO', 'CRPT', 'CRV', 'CTSI', 'CTX', 'CVC', 'CVX', 'DAI', 'DAR', 'DASH', 'DDX', 'DESO', 'DEXT', 'DIA', 'DIMO', 'DNT', 'DOGE', 'DOT', 'DREP', 'DRIFT', 'DYP', 'EGLD', 'ELA', 'ENJ', 'ENS', 'EOS', 'ERN', 'ETC', 'ETH', 'EUR', 'EUROC', 'FARM', 'FET', 'FIDA', 'FIL', 'FIS', 'FLOW', 'FLR', 'FORT', 'FORTH', 'FOX', 'FX', 'GAL', 'GALA', 'GBP', 'GFI', 'GHST', 'GLM', 'GMT', 'GNO', 'GNT', 'GODS', 'GRT', 'GST', 'GTC', 'GUSD', 'GYEN', 'HBAR', 'HFT', 'HIGH', 'HNT', 'HONEY', 'HOPR', 'ICP', 'IDEX', 'ILV', 'IMX', 'INDEX', 'INJ', 'INV', 'IOTX', 'JASMY', 'JTO', 'JUP', 'KARRAT', 'KAVA', 'KEEP', 'KNC', 'KRL', 'KSM', 'LCX', 'LDO', 'LINK', 'LIT', 'LOKA', 'LOOM', 'LPT', 'LQTY', 'LRC', 'LSETH', 'LTC', 'MAGIC', 'MANA', 'MASK', 'MATH', 'MATIC', 'MCO2', 'MDT', 'MEDIA', 'METIS', 'MINA', 'MIR', 'MKR', 'MLN', 'MNDE', 'MOBILE', 'MONA', 'MPL', 'MSOL', 'MTL', 'MULTI', 'MUSD', 'MUSE', 'MXC', 'NCT', 'NEAR', 'NEON', 'NEST', 'NKN', 'NMR', 'NU', 'OCEAN', 'OGN', 'OMG', 'OMNI', 'ONDO', 'OOKI', 'OP', 'ORCA', 'ORN', 'OSMO', 'OXT', 'PAX', 'PERP', 'PLA', 'PLU', 'PNG', 'POLS', 'POLY', 'POND', 'POWR', 'PRIME', 'PRO', 'PRQ', 'PUNDIX', 'PYR', 'PYUSD', 'QI', 'QNT', 'QSP', 'QUICK', 'RAD', 'RAI', 'RARE', 'RARI', 'RBN', 'REN', 'RENDER', 'REP', 'REQ', 'RGT', 'RLC', 'RLY', 'RNDR', 'RONIN', 'ROSE', 'RPL', 'SAFE', 'SAND', 'SEAM', 'SEI', 'SHDW', 'SHIB', 'SHPING', 'SKL', 'SNT', 'SNX', 'SOL', 'SPA', 'SPELL', 'STG', 'STORJ', 'STRK', 'STX', 'SUI', 'SUKU', 'SUPER', 'SUSHI', 'SWFTC', 'SYLO', 'SYN', 'T', 'TBTC', 'TIA', 'TIME', 'TNSR', 'TONE', 'TRAC', 'TRB', 'TRIBE', 'TRU', 'TVK', 'UMA', 'UNFI', 'UNI', 'UPI', 'USD', 'USDC', 'USDT', 'UST', 'VARA', 'VELO', 'VET', 'VGX', 'VOXEL', 'VTHO', 'WAMPL', 'WAXL', 'WBTC', 'WCFG', 'WLUNA', 'XCN', 'XLM', 'XMON', 'XRP', 'XTZ', 'XYO', 'YFI', 'YFII', 'ZEC', 'ZEN', 'ZETA', 'ZRX')]
        [parameter(Mandatory)]
        [string]
        $To,

        [validaterange(0, [int]::MaxValue)]
        $CacheSeconds = 0
    )

    process {
        if ($From -eq $To) {
            $Value | Add-Member -NotePropertyName Currency -NotePropertyValue $To -PassThru
        }
        else {
            $Cached = Join-Path $PSScriptRoot "Crypto-${From}.json"
            $APIUrl = "https://api.coinbase.com/v2/exchange-rates?currency=${From}"
            $RateStr = 'rates'
        
            $isCached = Test-Path $Cached

            if ($isCached) {
                $ExchangeRates = Get-Content $Cached | ConvertFrom-Json
            }

            if (-not $isCached -or ((Get-Date) -gt ($ExchangeRates.Expires | Get-Date))) {
                try {
                    $ExchangeRates = (Invoke-RestMethod $APIUrl -ErrorAction Stop).data

                    if ($CacheSeconds -gt 0) {
                        $ExchangeRates | Add-Member -MemberType NoteProperty -Name Expires -Value (Get-Date).AddSeconds($CacheSeconds)
                        $ExchangeRates | ConvertTo-Json | Out-File $Cached -Force
                    }
                }
                catch {
                    Write-Error $_
                }
            }

            if ($ExchangeRates.$RateStr.$To) {
                $Value * $ExchangeRates.$RateStr.$To | Add-Member -NotePropertyName Currency -NotePropertyValue $To -PassThru
            }
            else {
                Write-Error "Could not convert crypto currency."
            }
        }
    }
}
function Convert-Currency {
    <#
    .SYNOPSIS
        Converts a decimal value between specified currencies
 
    .DESCRIPTION
        Uses the Open Exchange Rate API (https://www.exchangerate-api.com/docs/free) to perform currency conversions.
        Caches the conversion rates for the specified currency (valid for 24 hours).
 
    .PARAMETER Value
        The amount you want to convert between currencies.
 
    .PARAMETER From
        The currency to convert from.
 
    .PARAMETER To
        The currency to convert to.
 
    .PARAMETER APIKey
        Optional: To use the v6 API, provide your API key, as provided by https://www.exchangerate-api.com/
 
    .INPUTS
        A numerical value, can be provided via the pipeline.
 
    .EXAMPLE
        100 | Convert-Currency -From USD -To GBP
 
        Description
        -----------
        Converts the value 100 (provided via the pipeline) from USD (US Dollar) to GBP (British Pound), example result: 79.674700
 
    .EXAMPLE
        Convert-Currency -Value 100 -From AUD -To EUR
 
        Description
        -----------
        Converts the value 100 from USD (US Dollar) to AUD (Australian Dollar), example result: 154.211800
 
    .EXAMPLE
        Convert-Currency -Value 100 -From USD -To EUR | Format-Currency
 
        Description
        -----------
        Converts 100 USD to EUR and pipes the result to Format-Currency, which picks up the destination currency (EUR) from the pipeline, example result: €92.15
    #>

    [cmdletbinding()]
    [OutputType([decimal])]
    param(
        [parameter(ValueFromPipeline, Mandatory, Position = 0)]
        [decimal]
        $Value,

        [validateset('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'FOK', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KID', 'KMF', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS', 'SRD', 'SSP', 'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWL')]
        [parameter(Mandatory)]
        [string]
        $From,
        
        [validateset('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'FOK', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KID', 'KMF', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS', 'SRD', 'SSP', 'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWL')]
        [parameter(Mandatory)]
        [string]
        $To,

        [string]
        $APIKey
    )

    process {
        if ($From -eq $To) {
            $Value | Add-Member -NotePropertyName Currency -NotePropertyValue $To -PassThru
        }
        else {
            if ($APIKey) {
                $Cached = Join-Path $PSScriptRoot "${From}v6.json"
                $APIUrl = "https://v6.exchangerate-api.com/v6/${APIKey}/latest/${From}"
                $RateStr = 'conversion_rates'
            }
            else {
                $Cached = Join-Path $PSScriptRoot "${From}.json"
                $APIUrl = "https://open.er-api.com/v6/latest/${From}"
                $RateStr = 'rates'
            }

            $isCached = Test-Path $Cached

            if ($isCached) {
                $ExchangeRates = Get-Content $Cached | ConvertFrom-Json
            }

            if (-not $isCached -or ((Get-Date) -gt ($ExchangeRates.time_next_update_unix | ConvertFrom-UnixTime))) {
                try {
                    $ExchangeRates = Invoke-RestMethod $APIUrl -ErrorAction Stop
                    $ExchangeRates | ConvertTo-Json | Out-File $Cached -Force
                }
                catch {
                    Write-Error $_
                }
            }

            if ($ExchangeRates.$RateStr.$To) {
                $Value * $ExchangeRates.$RateStr.$To | Add-Member -NotePropertyName Currency -NotePropertyValue $To -PassThru
            }
            else {
                Write-Error "Could not convert currency."
            }
        }
    }
}
function Format-Currency {
    <#
    .SYNOPSIS
        Formats a value as a string with the currency symbol for a specified country.
 
    .DESCRIPTION
        Outputs a value with the specified currency symbol. Can also be used to perform a currency conversion and then format as the converted currency.
 
    .PARAMETER Value
        The currency value.
 
    .PARAMETER Currency
        The currency represented by value. If not specified, this can be picked up from the pipeline by property name, e.g. from the output of Convert-Currency or Convert-CryptoCurrency.
 
    .PARAMETER Decimals
        The number of decimal places to round the value to. Default: 2
 
    .PARAMETER ConvertTo
        Perform a currency conversion and then format as that currency.
 
    .PARAMETER SymbolAtEnd
        Place the currency symbol after the value.
 
    .INPUTS
        A numerical value, can be provided via the pipeline. If piped from Convert-Currency or Convert-CryptoCurrency, the Currency parameter is automatically populated from the destination currency of that conversion.
 
    .EXAMPLE
        100 | Format-Currency -Currency USD
 
        Description
        -----------
        Formats the value (provided via the pipeline) as USD: $100.00.
 
    .EXAMPLE
        Convert-Currency -Value 100 -From USD -To EUR | Format-Currency
 
        Description
        -----------
        Converts 100 USD to EUR and formats the result as EUR, with the Currency parameter inferred from the pipeline, e.g.: €92.15
 
    .EXAMPLE
        100 | Format-Currency -Currency USD -ConvertTo GBP
 
        Description
        -----------
        Converts 100 from USD to GBP and formats as GBP, e.g.: £79.67
 
    .EXAMPLE
        Format-Currency -Value 100 -Currency USD
 
        Description
        -----------
        Formats the value as USD: $100.00.
 
    .EXAMPLE
        Format-Currency -Value 100.2345 -Currency USD -Decimals 3
 
        Description
        -----------
        Formats the value as USD: $100.235.
 
    .EXAMPLE
        Format-Currency -Value 100 -Currency USD -SymbolAtEnd
 
        Description
        -----------
        Formats the value as USD: 100.00$.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param(
        [parameter(ValueFromPipeline, Mandatory)]
        [decimal]
        $Value,

        [validateset('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'FOK', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KID', 'KMF', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS', 'SRD', 'SSP', 'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWL','BTC','ETH','USDT','ADA','XRP','SOL','DOT','DOGE','DAI','LTC','ALGO','BCH','OMI','ICP','ETC','XMR','XTZ','MIOTA','EOS','BSV','MKR','ZEC','DASH','XNO','REP','STEEM')]
        [parameter(ValueFromPipelineByPropertyName, Mandatory)]
        [string]
        $Currency,

        [int]
        $Decimals = 2,

        [validateset('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'FOK', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KID', 'KMF', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS', 'SRD', 'SSP', 'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWL', 'BTC','ETH','USDT','ADA','XRP','SOL','DOT','DOGE','DAI','LTC','ALGO','BCH','OMI','ICP','ETC','XMR','XTZ','MIOTA','EOS','BSV','MKR','ZEC','DASH','XNO','REP','STEEM')]
        [parameter(ValueFromPipelineByPropertyName)]
        [string]
        $ConvertTo,

        [switch]
        $SymbolAtEnd
    )

    process {
        $currencySymbols = @{
            'AED'   = 'د.إ'
            'AFN'   = '؋'
            'ALL'   = 'L'
            'AMD'   = 'Դ'
            'ANG'   = 'ƒ'
            'AOA'   = 'Kz'
            'ARS'   = '$'
            'AUD'   = '$'
            'AWG'   = 'ƒ'
            'AZN'   = 'ман'
            'BAM'   = 'KM'
            'BBD'   = '$'
            'BDT'   = '৳'
            'BGN'   = 'лв'
            'BHD'   = 'ب.د'
            'BIF'   = 'Fr'
            'BMD'   = '$'
            'BND'   = '$'
            'BOB'   = 'Bs.'
            'BRL'   = 'R$'
            'BSD'   = '$'
            'BTN'   = 'Nu.'
            'BWP'   = 'P'
            'BYN'   = 'Br'
            'BZD'   = '$'
            'CAD'   = '$'
            'CDF'   = 'Fr'
            'CHF'   = '₣'
            'CLP'   = '$'
            'CNY'   = '¥'
            'COP'   = '$'
            'CRC'   = '₡'
            'CUP'   = '₱'
            'CVE'   = '$'
            'CZK'   = 'Kč'
            'DJF'   = 'Fr'
            'DKK'   = 'kr'
            'DOP'   = 'RD$'
            'DZD'   = 'د.ج'
            'EGP'   = '£'
            'ERN'   = 'Nfk'
            'ETB'   = 'Br'
            'EUR'   = '€'
            'FJD'   = '$'
            'FKP'   = '£'
            'FOK'   = 'kr'
            'GBP'   = '£'
            'GEL'   = '₾'
            'GGP'   = '£'
            'GHS'   = '₵'
            'GIP'   = '£'
            'GMD'   = 'D'
            'GNF'   = 'Fr'
            'GTQ'   = 'Q'
            'GYD'   = '$'
            'HKD'   = '$'
            'HNL'   = 'L'
            'HRK'   = 'kn'
            'HTG'   = 'G'
            'HUF'   = 'Ft'
            'IDR'   = 'Rp'
            'ILS'   = '₪'
            'IMP'   = '£'
            'INR'   = '₹'
            'IQD'   = 'ع.د'
            'IRR'   = '﷼'
            'ISK'   = 'kr'
            'JEP'   = '£'
            'JMD'   = 'J$'
            'JOD'   = 'د.ا'
            'JPY'   = '¥'
            'KES'   = 'Sh'
            'KGS'   = 'с'
            'KHR'   = '៛'
            'KID'   = '$'
            'KMF'   = 'Fr'
            'KRW'   = '₩'
            'KWD'   = 'د.ك'
            'KYD'   = '$'
            'KZT'   = '₸'
            'LAK'   = '₭'
            'LBP'   = 'ل.ل'
            'LKR'   = 'Rs'
            'LRD'   = '$'
            'LSL'   = 'L'
            'LYD'   = 'ل.د'
            'MAD'   = 'د.م.'
            'MDL'   = 'L'
            'MGA'   = 'Ar'
            'MKD'   = 'ден'
            'MMK'   = 'Ks'
            'MNT'   = '₮'
            'MOP'   = 'P'
            'MRU'   = 'UM'
            'MUR'   = '₨'
            'MVR'   = 'Rf'
            'MWK'   = 'MK'
            'MXN'   = '$'
            'MYR'   = 'RM'
            'MZN'   = 'MT'
            'NAD'   = '$'
            'NGN'   = '₦'
            'NIO'   = 'C$'
            'NOK'   = 'kr'
            'NPR'   = '₨'
            'NZD'   = '$'
            'OMR'   = 'ر.ع.'
            'PAB'   = 'B/.'
            'PEN'   = 'S/'
            'PGK'   = 'K'
            'PHP'   = '₱'
            'PKR'   = '₨'
            'PLN'   = 'zł'
            'PYG'   = '₲'
            'QAR'   = 'ر.ق'
            'RON'   = 'lei'
            'RSD'   = 'дин'
            'RUB'   = '₽'
            'RWF'   = 'Fr'
            'SAR'   = 'ر.س'
            'SBD'   = '$'
            'SCR'   = '₨'
            'SDG'   = 'ج.س.'
            'SEK'   = 'kr'
            'SGD'   = '$'
            'SHP'   = '£'
            'SLE'   = 'Le'
            'SOS'   = 'Sh'
            'SRD'   = '$'
            'SSP'   = '£'
            'STN'   = 'Db'
            'SYP'   = '£'
            'SZL'   = 'L'
            'THB'   = '฿'
            'TJS'   = 'ЅМ'
            'TMT'   = 'm'
            'TND'   = 'د.ت'
            'TOP'   = 'T$'
            'TRY'   = '₺'
            'TTD'   = '$'
            'TVD'   = '$'
            'TWD'   = '$'
            'TZS'   = 'Sh'
            'UAH'   = '₴'
            'UGX'   = 'Sh'
            'USD'   = '$'
            'UYU'   = '$'
            'UZS'   = 'сўм'
            'VES'   = 'Bs.S'
            'VND'   = '₫'
            'VUV'   = 'Vt'
            'WST'   = 'T'
            'XAF'   = 'Fr'
            'XCD'   = '$'
            'XDR'   = 'SDR'
            'XOF'   = 'Fr'
            'XPF'   = 'Fr'
            'YER'   = '﷼'
            'ZAR'   = 'R'
            'ZMW'   = 'ZK'
            'ZWL'   = '$'
            # Cryto Currency
            'BTC'   = '₿'
            'ETH'   = 'Ξ'
            'USDT'  = '₮'
            'ADA'   = '₳'
            'XRP'   = '✕'
            'SOL'   = '◎'
            'DOT'   = '●'
            'DOGE'  = 'Ð'
            'DAI'   = '◈'
            'LTC'   = 'Ł'
            'ALGO'  = 'Ⱥ'
            'BCH'   = 'Ƀ'
            'OMI'   = 'Ο'
            'ICP'   = '∞'
            'ETC'   = 'ξ'
            'XMR'   = 'ɱ'
            'XTZ'   = 'ꜩ'
            'MIOTA' = 'ɨ'
            'EOS'   = 'ε'
            'BSV'   = 'Ɓ'
            'MKR'   = 'Μ'
            'ZEC'   = 'ⓩ'
            'DASH'  = 'Đ'
            'XNO'   = 'Ӿ'
            'REP'   = 'Ɍ'
            'STEEM' = 'ȿ'
        }

        if ($ConvertTo) {
            if ($ConvertTo -in 'BTC','ETH','USDT','ADA','XRP','SOL','DOT','DOGE','DAI','LTC','ALGO','BCH','OMI','ICP','ETC','XMR','XTZ','MIOTA','EOS','BSV','MKR','ZEC','DASH','XNO','REP','STEEM') {
                $Value = $Value | Convert-CryptoCurrency -From $Currency -To $ConvertTo
            }
            else {
                $Value = $Value | Convert-Currency -From $Currency -To $ConvertTo
            }
            
            $Currency = $ConvertTo
        }

        $CurrencySymbol = $CurrencySymbols[$Currency]
        
        if ($SymbolAtEnd) {
            ("{0:n$Decimals}" -f $Value) + $CurrencySymbol
        }
        else {
            $CurrencySymbol + ("{0:n$Decimals}" -f $Value)
        }
    }
}
function Get-CryptoCurrency {
    <#
    .SYNOPSIS
        Returns the list of supported crypto currency codes along with their currency name.
 
    .DESCRIPTION
        Use to list the crypto currencies that are supported by this module, and the CoinBaser API.
 
    .PARAMETER Currency
        The currency to return. Alias: Code.
 
    .PARAMETER Name
        The currency name to return.
 
    .INPUTS
        Currency codes can be provided via the pipeline.
 
    .EXAMPLE
        Get-CryptoCurrency
 
        Description
        -----------
        Returns the list of all supported currency codes, along with their name and type.
 
    .EXAMPLE
        Get-CryptoCurrency -Currency BTC
 
        Description
        -----------
        Returns the code and name for BTC.
 
    .EXAMPLE
        'BTC','ETH' | Get-CryptoCurrency
 
        Description
        -----------
        Returns the code and name details for BTC and ETH.
 
    .EXAMPLE
        Get-CryptoCurrency -Name 'Bitcoin'
 
        Description
        -----------
        Returns all currencies that include the word 'Bitcoin'
    #>

    [OutputType([pscustomobject])]
    [CmdletBinding(DefaultParameterSetName='Code')]
    param(
        [parameter(ValueFromPipeline,ParameterSetName='Code',Position=0)]
        [alias('Code')]
        [string]
        $Currency,
        
        [parameter(ParameterSetName='Name')]
        [string]
        $Name
    )

    process {
        $SupportedCurrency = Import-Csv "$PSScriptRoot\SupportedCryptoCurrency.csv"

        if ($Currency) {
            $SupportedCurrency | Where-Object { $_.Code -eq $Currency }
        }
        elseif ($Name) {
            $SupportedCurrency | Where-Object { $_.Name -match $Name }
        }
        else {
            $SupportedCurrency
        }
    }
}
function Get-CryptoExchangeRate {
    <#
    .SYNOPSIS
        Returns all crypto exchange rates for a specified currency, or a specified exchange rate between two currencies.
 
    .DESCRIPTION
        Uses the Coin Base API (https://api.coinbase.com/v2/exchange-rates) to perform currency conversions.
        Caches the conversion rates for the specified currency for a number of seconds if -CacheSeconds is specified.
 
    .PARAMETER Currency
        The currency to return exchange rates for. (Alias: From)
 
    .PARAMETER To
        The currency to return the exchange rate to (from the currency specified as -Currency or -From).
 
    .PARAMETER Rates
        Switch: Use to return just the exchange rates for a specified currency.
 
    .PARAMETER CacheSeconds
        Number of seconds to cache the result. Default: 0.
 
    .INPUTS
        Currency codes can be provided via the pipeline.
 
    .EXAMPLE
        Get-CryptoExchangeRate -Currency BTC
 
        Description
        -----------
        Returns the exchange rates for Bitcoin as a PowerShell object.
 
    .EXAMPLE
        Get-CryptoExchangeRate -Currency BTC -Rates
 
        Description
        -----------
        Returns all exchange rates for Bitcoin.
     
    .EXAMPLE
        Get-CryptoExchangeRate -From USD -To BTC
 
        Description
        -----------
        Returns the exchange rate from US Dollar to Bitcoin, example result: 0.0000149456903504
 
    .EXAMPLE
        'BTC','ETH' | Get-CryptoExchangeRate
 
        Description
        -----------
        Returns the exchange rates for Bitcoin and Ether as PowerShell objects.
 
    #>

    [CmdletBinding(DefaultParameterSetName = 'ToRate')]
    [OutputType([pscustomobject])]
    [OutputType([pscustomobject], ParameterSetName = ('Rates'))]
    [OutputType([double], ParameterSetName = ('ToRate'))]
    param(
        [validateset('00', '1INCH', 'AAVE', 'ABT', 'ACH', 'ACS', 'ADA', 'AERGO', 'AERO', 'AGLD', 'AIOZ', 'AKT', 'ALCX', 'ALEPH', 'ALGO', 'ALICE', 'AMP', 'ANKR', 'ANT', 'APE', 'API3', 'APT', 'ARB', 'ARKM', 'ARPA', 'ASM', 'AST', 'ATA', 'ATOM', 'AUCTION', 'AUDIO', 'AURORA', 'AVAX', 'AVT', 'AXL', 'AXS', 'BADGER', 'BAL', 'BAND', 'BAT', 'BCH', 'BICO', 'BIGTIME', 'BIT', 'BLUR', 'BLZ', 'BNT', 'BOBA', 'BOND', 'BONK', 'BTC', 'BTRST', 'BUSD', 'C98', 'CBETH', 'CELR', 'CGLD', 'CHZ', 'CLV', 'COMP', 'COTI', 'COVAL', 'CRO', 'CRPT', 'CRV', 'CTSI', 'CTX', 'CVC', 'CVX', 'DAI', 'DAR', 'DASH', 'DDX', 'DESO', 'DEXT', 'DIA', 'DIMO', 'DNT', 'DOGE', 'DOT', 'DREP', 'DRIFT', 'DYP', 'EGLD', 'ELA', 'ENJ', 'ENS', 'EOS', 'ERN', 'ETC', 'ETH', 'EUR', 'EUROC', 'FARM', 'FET', 'FIDA', 'FIL', 'FIS', 'FLOW', 'FLR', 'FORT', 'FORTH', 'FOX', 'FX', 'GAL', 'GALA', 'GBP', 'GFI', 'GHST', 'GLM', 'GMT', 'GNO', 'GNT', 'GODS', 'GRT', 'GST', 'GTC', 'GUSD', 'GYEN', 'HBAR', 'HFT', 'HIGH', 'HNT', 'HONEY', 'HOPR', 'ICP', 'IDEX', 'ILV', 'IMX', 'INDEX', 'INJ', 'INV', 'IOTX', 'JASMY', 'JTO', 'JUP', 'KARRAT', 'KAVA', 'KEEP', 'KNC', 'KRL', 'KSM', 'LCX', 'LDO', 'LINK', 'LIT', 'LOKA', 'LOOM', 'LPT', 'LQTY', 'LRC', 'LSETH', 'LTC', 'MAGIC', 'MANA', 'MASK', 'MATH', 'MATIC', 'MCO2', 'MDT', 'MEDIA', 'METIS', 'MINA', 'MIR', 'MKR', 'MLN', 'MNDE', 'MOBILE', 'MONA', 'MPL', 'MSOL', 'MTL', 'MULTI', 'MUSD', 'MUSE', 'MXC', 'NCT', 'NEAR', 'NEON', 'NEST', 'NKN', 'NMR', 'NU', 'OCEAN', 'OGN', 'OMG', 'OMNI', 'ONDO', 'OOKI', 'OP', 'ORCA', 'ORN', 'OSMO', 'OXT', 'PAX', 'PERP', 'PLA', 'PLU', 'PNG', 'POLS', 'POLY', 'POND', 'POWR', 'PRIME', 'PRO', 'PRQ', 'PUNDIX', 'PYR', 'PYUSD', 'QI', 'QNT', 'QSP', 'QUICK', 'RAD', 'RAI', 'RARE', 'RARI', 'RBN', 'REN', 'RENDER', 'REP', 'REQ', 'RGT', 'RLC', 'RLY', 'RNDR', 'RONIN', 'ROSE', 'RPL', 'SAFE', 'SAND', 'SEAM', 'SEI', 'SHDW', 'SHIB', 'SHPING', 'SKL', 'SNT', 'SNX', 'SOL', 'SPA', 'SPELL', 'STG', 'STORJ', 'STRK', 'STX', 'SUI', 'SUKU', 'SUPER', 'SUSHI', 'SWFTC', 'SYLO', 'SYN', 'T', 'TBTC', 'TIA', 'TIME', 'TNSR', 'TONE', 'TRAC', 'TRB', 'TRIBE', 'TRU', 'TVK', 'UMA', 'UNFI', 'UNI', 'UPI', 'USD', 'USDC', 'USDT', 'UST', 'VARA', 'VELO', 'VET', 'VGX', 'VOXEL', 'VTHO', 'WAMPL', 'WAXL', 'WBTC', 'WCFG', 'WLUNA', 'XCN', 'XLM', 'XMON', 'XRP', 'XTZ', 'XYO', 'YFI', 'YFII', 'ZEC', 'ZEN', 'ZETA', 'ZRX')]
        [parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory)]
        [alias('From')]
        [string]
        $Currency,

        [validateset('00', '1INCH', 'AAVE', 'ABT', 'ACH', 'ACS', 'ADA', 'AERGO', 'AERO', 'AGLD', 'AIOZ', 'AKT', 'ALCX', 'ALEPH', 'ALGO', 'ALICE', 'AMP', 'ANKR', 'ANT', 'APE', 'API3', 'APT', 'ARB', 'ARKM', 'ARPA', 'ASM', 'AST', 'ATA', 'ATOM', 'AUCTION', 'AUDIO', 'AURORA', 'AVAX', 'AVT', 'AXL', 'AXS', 'BADGER', 'BAL', 'BAND', 'BAT', 'BCH', 'BICO', 'BIGTIME', 'BIT', 'BLUR', 'BLZ', 'BNT', 'BOBA', 'BOND', 'BONK', 'BTC', 'BTRST', 'BUSD', 'C98', 'CBETH', 'CELR', 'CGLD', 'CHZ', 'CLV', 'COMP', 'COTI', 'COVAL', 'CRO', 'CRPT', 'CRV', 'CTSI', 'CTX', 'CVC', 'CVX', 'DAI', 'DAR', 'DASH', 'DDX', 'DESO', 'DEXT', 'DIA', 'DIMO', 'DNT', 'DOGE', 'DOT', 'DREP', 'DRIFT', 'DYP', 'EGLD', 'ELA', 'ENJ', 'ENS', 'EOS', 'ERN', 'ETC', 'ETH', 'EUR', 'EUROC', 'FARM', 'FET', 'FIDA', 'FIL', 'FIS', 'FLOW', 'FLR', 'FORT', 'FORTH', 'FOX', 'FX', 'GAL', 'GALA', 'GBP', 'GFI', 'GHST', 'GLM', 'GMT', 'GNO', 'GNT', 'GODS', 'GRT', 'GST', 'GTC', 'GUSD', 'GYEN', 'HBAR', 'HFT', 'HIGH', 'HNT', 'HONEY', 'HOPR', 'ICP', 'IDEX', 'ILV', 'IMX', 'INDEX', 'INJ', 'INV', 'IOTX', 'JASMY', 'JTO', 'JUP', 'KARRAT', 'KAVA', 'KEEP', 'KNC', 'KRL', 'KSM', 'LCX', 'LDO', 'LINK', 'LIT', 'LOKA', 'LOOM', 'LPT', 'LQTY', 'LRC', 'LSETH', 'LTC', 'MAGIC', 'MANA', 'MASK', 'MATH', 'MATIC', 'MCO2', 'MDT', 'MEDIA', 'METIS', 'MINA', 'MIR', 'MKR', 'MLN', 'MNDE', 'MOBILE', 'MONA', 'MPL', 'MSOL', 'MTL', 'MULTI', 'MUSD', 'MUSE', 'MXC', 'NCT', 'NEAR', 'NEON', 'NEST', 'NKN', 'NMR', 'NU', 'OCEAN', 'OGN', 'OMG', 'OMNI', 'ONDO', 'OOKI', 'OP', 'ORCA', 'ORN', 'OSMO', 'OXT', 'PAX', 'PERP', 'PLA', 'PLU', 'PNG', 'POLS', 'POLY', 'POND', 'POWR', 'PRIME', 'PRO', 'PRQ', 'PUNDIX', 'PYR', 'PYUSD', 'QI', 'QNT', 'QSP', 'QUICK', 'RAD', 'RAI', 'RARE', 'RARI', 'RBN', 'REN', 'RENDER', 'REP', 'REQ', 'RGT', 'RLC', 'RLY', 'RNDR', 'RONIN', 'ROSE', 'RPL', 'SAFE', 'SAND', 'SEAM', 'SEI', 'SHDW', 'SHIB', 'SHPING', 'SKL', 'SNT', 'SNX', 'SOL', 'SPA', 'SPELL', 'STG', 'STORJ', 'STRK', 'STX', 'SUI', 'SUKU', 'SUPER', 'SUSHI', 'SWFTC', 'SYLO', 'SYN', 'T', 'TBTC', 'TIA', 'TIME', 'TNSR', 'TONE', 'TRAC', 'TRB', 'TRIBE', 'TRU', 'TVK', 'UMA', 'UNFI', 'UNI', 'UPI', 'USD', 'USDC', 'USDT', 'UST', 'VARA', 'VELO', 'VET', 'VGX', 'VOXEL', 'VTHO', 'WAMPL', 'WAXL', 'WBTC', 'WCFG', 'WLUNA', 'XCN', 'XLM', 'XMON', 'XRP', 'XTZ', 'XYO', 'YFI', 'YFII', 'ZEC', 'ZEN', 'ZETA', 'ZRX')]
        [parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'ToRate')]
        [string]
        $To,

        [parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'Rates')]
        [switch]
        $Rates,

        [validaterange(0, [int]::MaxValue)]
        $CacheSeconds = 0
    )
    process {
        $Cached = Join-Path $PSScriptRoot "Crypto-${Currency}.json"
        $APIUrl = "https://api.coinbase.com/v2/exchange-rates?currency=${Currency}"
        $RateStr = 'rates'
    
        $isCached = Test-Path $Cached

        if ($isCached) {
            $ExchangeRates = Get-Content $Cached | ConvertFrom-Json
        }

        if (-not $isCached -or ((Get-Date) -gt ($ExchangeRates.Expires | Get-Date))) {
            try {
                $ExchangeRates = (Invoke-RestMethod $APIUrl -ErrorAction Stop).data

                if ($CacheSeconds -gt 0) {
                    $ExchangeRates | Add-Member -MemberType NoteProperty -Name Expires -Value (Get-Date).AddSeconds($CacheSeconds)
                    $ExchangeRates | ConvertTo-Json | Out-File $Cached -Force
                }
            }
            catch {
                Write-Error $_
            }
        }

        if ($ExchangeRates) {

            if ($Rates) {
                $ExchangeRates.$RateStr
            }
            elseif ($To) {
                $ExchangeRates.$RateStr.$To
            }
            else {
                $ExchangeRates
            }
        }
        else {
            Write-Error "Failed to retrieve rates for $Currency."
        }
    }
}
function Get-Currency {
    <#
    .SYNOPSIS
        Returns the list of supported currency codes along with their currency name and country code.
 
    .DESCRIPTION
        Use to list the countries and currencies that are supported by this module, and the Exchange Rate API.
 
    .PARAMETER Currency
        The currency to return. Alias: Code.
 
    .PARAMETER Name
        The currency name to return.
 
    .PARAMETER Country
        The country to return.
 
    .INPUTS
        Currency codes can be provided via the pipeline.
 
    .EXAMPLE
        Get-Currency
 
        Description
        -----------
        Returns the list of all supported currency codes, along with their name and country.
 
    .EXAMPLE
        Get-Currency -Currency GBP
 
        Description
        -----------
        Returns the code, name and country for GBP.
 
    .EXAMPLE
        'GBP','USD' | Get-Currency
 
        Description
        -----------
        Returns the code, name and country details for GBP and USD.
 
    .EXAMPLE
        Get-Currency -Country 'United Kingdom'
 
        Description
        -----------
        Returns the code, name and country for the United Kingdom.
 
    .EXAMPLE
        Get-Currency -Name 'Dollar'
 
        Description
        -----------
        Returns all currencies that include the word 'Dollar'
    #>

    [OutputType([pscustomobject])]
    [CmdletBinding(DefaultParameterSetName='Code')]
    param(
        [parameter(ValueFromPipeline,ParameterSetName='Code',Position=0)]
        [alias('Code')]
        [string]
        $Currency,
        
        [parameter(ParameterSetName='Name')]
        [string]
        $Name,

        [parameter(ParameterSetName='Country')]
        [string]
        $Country
    )

    process {
        $SupportedCurrency = Import-Csv "$PSScriptRoot\SupportedCurrency.csv"

        if ($Currency) {
            $SupportedCurrency | Where-Object { $_.Code -eq $Currency }
        }
        elseif ($Name) {
            $SupportedCurrency | Where-Object { $_.Name -match $Name }
        }
        elseif ($Country) {
            $SupportedCurrency | Where-Object { $_.Country -match $Country }
        }
        else {
            $SupportedCurrency
        }
    }
}
function Get-ExchangeRate {
    <#
    .SYNOPSIS
        Returns all exchange rates for a specified currency, or a specified exchange rate between two currencies.
 
    .DESCRIPTION
        Uses the Open Exchange Rate API (https://www.exchangerate-api.com/docs/free) to retrieve currency rates.
        Caches the conversion rates for the specified currency (valid for 24 hours).
 
    .PARAMETER Currency
        The currency to return exchange rates for. (Alias: From)
 
    .PARAMETER To
        The currency to return the exchange rate to (from the currency specified as -Currency or -From).
 
    .PARAMETER Rates
        Switch: Use to return just the exchange rates for a specified currency.
 
    .PARAMETER APIKey
        Optional: To use the v6 API, provide your API key, as provided by https://www.exchangerate-api.com/
 
    .INPUTS
        Currency codes can be provided via the pipeline.
 
    .EXAMPLE
        Get-ExchangeRate -Currency USD
 
        Description
        -----------
        Returns the exchange rates for US Dollar as a PowerShell object.
 
    .EXAMPLE
        Get-ExchangeRate -Currency USD -Rates
 
        Description
        -----------
        Returns all exchange rates for US Dollar.
     
    .EXAMPLE
        Get-ExchangeRate -From USD -To GBP
 
        Description
        -----------
        Returns the exchange rate from US Dollar to British Pound, example result: 0.792011
 
    .EXAMPLE
        'USD','GBP' | Get-ExchangeRate
 
        Description
        -----------
        Returns the exchange rates for US Dollar and British Pound as PowerShell objects.
 
    #>

    [CmdletBinding(DefaultParameterSetName = 'ToRate')]
    [OutputType([pscustomobject])]
    [OutputType([pscustomobject], ParameterSetName=('Rates'))]
    [OutputType([double], ParameterSetName=('ToRate'))]
    param(
        [validateset('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'FOK', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KID', 'KMF', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS', 'SRD', 'SSP', 'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWL')]
        [parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory)]
        [alias('From')]
        [string]
        $Currency,

        [validateset('AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'FOK', 'GBP', 'GEL', 'GGP', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KID', 'KMF', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SOS', 'SRD', 'SSP', 'STN', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XDR', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMW', 'ZWL')]
        [parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'ToRate')]
        [string]
        $To,

        [parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'Rates')]
        [switch]
        $Rates,

        [string]
        $APIKey
    )
    process {
        if ($APIKey) {
            $Cached = Join-Path $PSScriptRoot "${Currency}v6.json"
            $APIUrl = "https://v6.exchangerate-api.com/v6/${APIKey}/latest/${Currency}"
            $RateStr = 'conversion_rates'
        }
        else {
            $Cached = Join-Path $PSScriptRoot "${Currency}.json"
            $APIUrl = "https://open.er-api.com/v6/latest/${Currency}"
            $RateStr = 'rates'
        }

        $isCached = Test-Path $Cached

        if ($isCached) {
            $ExchangeRates = Get-Content $Cached | ConvertFrom-Json
        }

        if (-not $isCached -or ((Get-Date) -gt ($ExchangeRates.time_next_update_unix | ConvertFrom-UnixTime))) {
            try {
                $ExchangeRates = Invoke-RestMethod $APIUrl -ErrorAction Stop
                $ExchangeRates | ConvertTo-Json | Out-File $Cached -Force
            }
            catch {
                Write-Error $_
            }
        }

        if ($ExchangeRates) {

            if ($Rates) {
                $ExchangeRates.$RateStr
            }
            elseif ($To) {
                $ExchangeRates.$RateStr.$To
            }
            else {
                $ExchangeRates
            }
        }
        else {
            Write-Error "Failed to retrieve rates for $Currency."
        }
    }
}
function ConvertFrom-UnixTime {
    <#
    .SYNOPSIS
        Converts a unix timestamp to a datetime object.
    #>

    param(
        [parameter(ValueFromPipeline, Mandatory)]
        $UnixTime
    )
    begin {
        [datetime]$Origin = '1970-01-01 00:00:00'
    }
    process {
        $Origin.AddSeconds($UnixTime)
    }
}