So here we are again. A long adventure to get some food has been completed. The TV blaring Season 5 of New Girl. I think to myself, you know what would go really well with this Shawarma? If I could finally read an IPv6 address without looking like an idiot. So here goes. IPv4 is simple, 32 bits of easy to understand goodness. Every single IPv4 address is made up of 4 bytes. For example "192.168.1.1". There is no shorthand either, that is the address, that's it. There is no better way to write it. Ok, so now that that is out of the picture, what is IPv6.
IPv6 is 128 bits of a little bit more confusing. Well actually, it's not the address that is confusing, it's the notation. When you see IPv6, a lot of times you see things like "::1" and "FE80::1". What does that even mean. How is that 128 bits. How will we ever know. So the secret is in the "::", which is pretty much just shorthand for "a lot of zeros go here".
For example: if we take the address "::1", it actually expands out to "0000:0000:0000:0000:0000:0000:0000:0001". Literally just means fill in this space with zeros. Another example: "FE80::1" becomes "FE80:0000:0000:0000:0000:0000:0000:0001". Just FYI, you are only allowed to use the "::" once, otherwise addresses would be unreadable. ("::1::") So before anything, here is a function to automate that, because it drives me nuts.
raw
#
# Expand an IPv6 address. For example ::1 becomes 0000:0000:0000:0000:0000:0000:0000:0001
#
function Expand-IPV6
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, 
                   Position = 0,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)][String]$IPv6
    )
    process
    {
        $count = 0
        $loc = -1

        # Count the number of colons, and keep track of the double colon
        for($i = 0; $i -lt $IPv6.Length; $i++) 
        { 
            if($IPv6[$i] -eq ':') 
            {
                $count++
                if(($i - 1) -ge 0 -and $IPv6[$i-1] -eq ':')
                {
                    $loc = $i
                }
            }
        }

        # If we didnt find a double colon and the count isn't 7, then throw an exception
        if($loc -lt 0 -and $count -ne 7)
        {
            throw "Invalid IPv6 Address"
        }

        # Add in any missing colons if we had a double
        $cleaned = $IPv6
        if($count -lt 7)
        {
            $cleaned = $IPv6.Substring(0, $loc) + (':'*(7-$count)) + $IPv6.Substring($loc)
        }

        # Parse current values in fill in new IP with hex numbers padded to 4 digits
        $result = @()
        foreach($splt in $cleaned -split ':')
        {
            $val = 0
            $r = [int]::TryParse($splt, [System.Globalization.NumberStyles]::HexNumber, [System.Globalization.CultureInfo]::InvariantCulture, [ref]$val)
            $result += ('{0:X4}' -f $val)
        }

        return $result -join ':'
    }
}
                            
                        
So this does the expansions work for us, because it’s a pain in the butt to deal with these addresses in their short form. Also, I know the code is gross and I apologize for that, but there is more to come. Ok, so now, what happens if we have an IPv4 address and we need to turn it into IPv6. Boom, its easy. The last 32 bits of the IPv6 address are equal to our IPv4 address, and the 16 bits preceding those are all set to 1. Easy enough! That means, the IP address 1.1.1.1 would turn into "::FFFF:0101:0101" or "0000:0000:0000:0000:0000:FFFF:0101:0101" in full form. So how do we make that happen?
raw
# Map an IPv4 address to IPv6
function Map-IPv4ToIPv6
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, 
            Position = 0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true)][String]$IPv4
    )
    process
    {
        # Split on the dots
        $split = $IPv4 -split '\.'
        if($split.Length -ne 4)
        {
            throw 'Not a valid IPv4 Address'
        }

        # Parse into numbers
        $vals = @()
        foreach($v in $split)
        {
            $vals += [int]::Parse($v)
        }

        # Return as shorthand ipv6
        return "::FFFF:{0:X2}{1:X2}:{2:X2}{3:X2}" -f $vals
    }
}
                            
                        
BOOM, mission accomplished. Hopefully (it worked in a few tests). Also, for completeness, here is a function which turns an IPv4 address which is represented in IPv6 back into an IPv4 address.
raw
#
# Transforms an IPv4 address which is represented in IPv6 back into IPv4
#
function Map-IPv6ToIPv4
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, 
            Position = 0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true)][String]$IPv6
    )
    process
    {
        # Get the expanded form
        $expanded = Expand-IPV6 $IPv6
        $split = $expanded.Split(':')

        # Make sure this is valid...
        $is4MappedTo6 = $split[5] -match 'FFFF'
        if(-not $is4MappedTo6)
        {
            throw 'This is not an IPv4 Address mapped to IPv6'
        }

        # Parse each byte as an integer
        $addr = @()
        for($i = 0; $i -lt 8; $i+=2)
        {
            $addr += [int]::Parse(($split[6 + [math]::Floor(($i / 4))][($i % 4)..(($i%4)+1)] -join ''), [System.Globalization.NumberStyles]::HexNumber)
        }

        return $addr -join '.'
    }
}
                            
                        
The classes built in to handle IP addresses are definitely much smarter, and the way to go. But this was a sad attempt at a way to do it in Powershell!