Changing laptops, keeping boot to VHDx

A couple-few months ago I decided that I wanted to give Windows’ newish feature of booting to a VHD a real try. Actually use it for every day computing instead of just a one off test.

I won’t go into details of setting up the system, there are plenty of tutorials out there. Like the one I used.

What I will go into is a recent laptop move. You see, I was using my work laptop originally. For one thing it was way more powerful than my personal one and I really didn’t like the idea of removing my nice Logitech M570┬ádongle every day. (So instead I moved the whole laptop.) However now that I have a new laptop, I wanted to move my environment so I didn’t need to setup every little thing again.

So I copied my VHDx file to the new laptop, mounted it and ran bcdboot.exe, restarted and after some “getting devices ready” screens, was in a very familiar Windows 8. The only thing I needed to do was install drivers, and they were right there on the physical drive (thanks HP!). I had downloaded drivers in preparation for no reason!

All in all, besides the annoyingly long copy time –about an hour and a half– I was back to my desktop in about 15-20 minutes. I could probably have done better on the copy time by making use of gigabit Ethernet instead of external USB drives, which according to the google would be roughly 16 minutes.

With this experience being so easy, I’m thinking that this may be a feature I’m going to have to get my peers to use as well. With things being this easy to change hardware, it would be a welcome change to rebuilding a failing machine. Heck with some fancy scripting, you could probably make a backup and move it someplace on the network at night.

IPv6 range/subnet calculater for powershell

From what I can tell, there aren’t many…if any, IPv6 address range calculators. While I read it is recommended that you use the entire /64 block, I don’t think it’s always necessary to do so. Besides, what happens when you want to route only a portion of the block to one place?

Example usage:

ipv6range.ps1 2001:470:1f10:60::10 64 | ft ipaddress*
ipv6range.ps1 2003:5:1f:fa0::10 104 | ft ipaddress* #ipv4 /8 equivalent
ipv6range.ps1 2003:5:1f:fa0::10 112 | ft ipaddress* #ipv4 /16 equivalent
ipv6range.ps1 2003:5:1f:fa0::10 120 | ft ipaddress* #ipv4 /24 equivalent
ipv6range.ps1 2003:5:1f:fa0::10 124 | ft ipaddress* #ipv4 /28 equivalent

….and the code….

param(
    [net.ipaddress]$Addr,
    [int]$netmask = 64,
    [switch]$ForceListing

)

if($Addr.AddressFamily -ne 'InterNetworkV6') { throw "`$Addr must be a valid IPv6 address."; }

<#
Create a subnet mask based on a CIDR input.
#>
function subnet {
    param(
        [int]$netmask
    )

    if($netmask -gt 128) { throw "`$netmask cannot be greater than 128"; }

    $mask = (@($true) * $netmask) + (@($false) * (128-$netmask));
    return New-Object Collections.BitArray @(,$mask);
}

<#
Convert a BitArray into a byte array for easy conversion into an IPAddress.
#>
function bit2byte {
    param(
        [Collections.BitArray]$bitArray
    )

    for($i = 0; $i -lt $bitArray.length; $i+=8) {
        [convert]::ToByte([string]::Join("", ([string[]][byte[]]($bitArray[$i..($i+7)]))), 2)
    }
}

<#
convert an ip into a BitArray for easy bitwise operations.
#>
function ip2bit {
    param([net.ipaddress]$addr)

    $b = $addr.GetAddressBytes();
    $bits = @();
    foreach($a in $b) {
        $t = [convert]::ToString($a,2).padleft(8,"0") #[7..0];
        $bits += [string]::join("",$t);
    }
    $nbits = ($bits | %{[char[]]$_} | %{[bool]::Parse("$_".replace("1","true").replace("0","false"))});
    return New-Object collections.bitarray @(,$nbits)
}

<#
Increment an ipv6 address.
#>
function inc {
    param([net.ipaddress]$addr)

    $b = $addr.GetAddressBytes();

    for($i = $b.length-1; $i -ge 0; $i--) {
        if($b[$i] -gt 254) { continue; }
        $b[$i]++;
        break;
    }
    New-Object net.ipaddress @(,$b);
}

<#
Decrement an ipv6 address.
#>
function dec {
    param([net.ipaddress]$addr)

    $b = $addr.GetAddressBytes();

    for($i = $b.length-1; $i -ge 0; $i--) {
        if($b[$i] -eq 0) { continue; }
        $b[$i]--;
        break;
    }
    New-Object net.ipaddress @(,$b);
}

$ipArr = new-object collections.bitarray @(,(ip2bit $Addr.GetAddressBytes()))

$netBits = New-Object collections.bitarray @(,(subnet $netmask))
$hostBits = (New-Object collections.bitarray $netBits).Xor((New-Object collections.bitarray 128, $true)) #.xor((New-Object collections.bitarray 128, $true))

$netId = New-Object net.ipaddress @(, (bit2byte (New-Object collections.bitarray $ipArr).And($netBits)));
$netBcast = New-Object net.ipaddress @(, (bit2byte (New-Object collections.bitarray $ipArr).Or($hostBits)));

$numHosts = [math]::Pow(2, ($hostBits | ?{$_} | measure).count)

if($numHosts -gt 256 -and !$ForceListing.ispresent) {
    #well, if we have more than this, just output the (ipv4 equivalent) network id and broadcast address.
    $netId
    $netBcast
} else {
    Add-Member -PassThru -Force -InputObject $netId -MemberType NoteProperty -Name IsUsable -Value $false;
    try {
        $lastAddr = $netId;
        for($i = 0; $i -lt $numHosts-2; $i ++) {
            $lastAddr = inc $lastAddr
            Add-Member -PassThru -Force -InputObject $lastAddr -MemberType NoteProperty -Name IsUsable -Value $true;
        }
    } catch {}
    Add-Member -PassThru -Force -InputObject $netBcast -MemberType NoteProperty -Name IsUsable -Value $false;
    #$res
}

Notes:

  • Not commented well. RTCFA (read the code for answers)! >:(
  • Only increments despite there being a decrement function.
  • If the number of host addresses is less then 256, it will always display the complete listing.