Of IPs & Subnets

While if you look, there are tools to calculate a IP subnet/address range, they all seem to rely on string splitting and converting the address to binary manually. Which I think is bulky, hard to maintain, and more importantly, not that elegant. So pulling to mind my Cisco CCNA classes where my instructor would drill into us the binary ands and ors of IP and subnet addressing, I got down to work.

All examples are in Powershell, however they could be translated to C#, any .NET language or even some other language quite easily.

Examples

Including System.net. This may not be necessary, but I’ve mucked with my Powershell settings way too much to know about a vanilla install.

#Powershell v1.0
[reflection.assembly]::LoadWithPartialName("system.net");
#Powershell v2.0
Add-Type -AssemblyName System.Net;

A common plight for me is finding out if two different IP addresses are on the same local network.

$router = [net.ipaddress]::Parse("192.168.1.254");
$subnet = [net.ipaddress]::Parse("255.255.255.0");
$IP_one = [net.ipaddress]::Parse("192.168.1.23");
$IP_two = [net.ipaddress]::Parse("192.168.1.55");
$IP_three = [net.ipaddress]::Parse("33.21.9.1");

#get the network ID
#in this case it's 192.168.1.0
$network = $router.address -band $subnet.Address

($network -band $IP_one.Address) -eq $network #True
($network -band $IP_two.Address) -eq $network #True
($network -band $IP_three.Address) -eq $network #False

Of course there are also times where I need to know how many addresses there are in the network or what they are.

$seed = [net.ipaddress]::Parse("192.168.23.45");
$subnet = [net.ipaddress]::Parse("255.255.252.0");

$begin = ($seed.address -band $subnet.address)
$end = (([net.ipaddress]::Broadcast.Address -bxor $subnet.Address) -bor $seed.address)

#It's the same for both start and ending IP's
#We convert from a 64 to 32 bit integer (8 to 4 bytes) and then reverse it so we can do addition/subtraction math to later on.
$start_bytes = new-object byte[] 4;
[array]::copy([bitconverter]::getBytes(($seed.address -band $subnet.address)), $start_bytes, 4);
[array]::Reverse($start_bytes);
$start_int = [bitconverter]::ToInt32($start_bytes,0);

$end_bytes = new-object byte[] 4;
[array]::copy([bitconverter]::getBytes((([net.ipaddress]::Broadcast.Address -bxor $subnet.Address) -bor $seed.address)), $end_bytes, 4);
[array]::Reverse($end_bytes);
$end_int = [bitconverter]::ToInt32($end_bytes,0);

#Entire range including the network ID and Broadcast addresses
[math]::Abs($start_int - $end_int) + 1

#Just the number of usable addresses
[math]::Abs($start_int - $end_int) - 1

#Address list!
for($i=0; $i -le [math]::abs($start_int - $end_int); $i++) {
    $tba = [bitconverter]::getbytes($i + $start_int);
	[array]::Reverse($tba)
    (new-object net.ipaddress ([bitconverter]::ToInt64($tba + [byte[]]@(0,0,0,0),0))).tostring();
}

Conclusion

As you can see, using bitwise operations greatly reduces the complexity required to calculate network addresses. By simplifying the process, it makes it much easier to maintain the code and build on it later!

Restoring Hyper-V VM with snapshot tree

For whatever reason, you’ve lost your virtual machine settings in Hyper-V and it just so happened they are snapshots. I sure hope that this was a test server and not a production one! Tsktsk! By now, you’ve probably scoured the interweb searching for a cure, and you’re in luck, you’ve found a way to get back your snapshot tree instead of just merging the disks! Oh joy!

It would seem everyone out there is happy with just merging their VHDs and getting back to work, but not me, no sir! I want things back the way they were! It took me about half a day to get this, so hopefully, this will save you some time for more important things, like tetris!

Steps

  1. Create same number of pre-existing snapshots using the Hyper-V MMC.
  2. Replace new snapshots with old snapshots while renaming the old to the same as the new, except the file extension should be “vhd” instead of “avhd”. The reason we’ll see later, but the Hyper-V tool to repair VHD chains auto-appends .vhd! (Grr Hyper-V Team, grr!)
  3. Repair the vhd’s. Because of our renaming we’ve broken the differencing chain. To fix this, go to open Hyper-V, go to the VM’s Settings and then the hard drive. Change the VHD to the new one (simply changing the extension should work) and click “inspect disk”. This will walk you through fixing the chain.
  4. Modify the ACL to include the VM specific account. This you must to in Powershell since the Explorer GUI can’t seem to find the account. I don’t know why and there may be a way, but I’m to lazy to dig into it and this works. (Below you can find some sample code.) The account to add from the old VHD, is the one that starts with “NT VIRTUAL MACHINE” and ends with a GUID.
    ##START POWERSHELL CODE
    #get the old vhd's permissions
    $vm_perm = (get-acl .\old.vhd).access | where { $_.IdentityReference.tostring().contains("NT VIRTUAL MACHINE") }
    
    #Load the new vhd's acl into memory
    $newvhd = get-acl .\new.vhd
    
    $newvhd.AddAccessRule($vm_perm)
    
    $newvhd | set-acl .\new.vhd
    ##END POWERSHELL CODE
  5. Open all the VM’s XML setting files and make sure that any settings related the the VHD’s is correct. This should only be the filename. If you need to edit these files be sure to turn off the Hyper-V Management Service, this will not affect the VM’s running, only the managing of them. The XML files can be found wherever you made the VM.
  6. You should now have a restored VM with the snapshot tree! Woo! Go you!

I’m on a boat!

Well, I’m married now and very probably enjoying a lovely honeymoon given to us by my aunt and uncle from California. They got us two tickets on a cruise in the Caribbean (?), which is super nice since it’ll be warm and by the ocean which means Katrina’s gonna be in a bikini a lot of the time!

See you all next week!

This has been a prerecorded message.

I’m getting married!

In the evening, not the morning…and it’s this evening.

I’m getting married to my bestest friend in the whole wide world, Katrina Bakker!

My brother (best man), cousin, and Katrina’s brothers are standing up for me and both of our sisters are standing up her. My grandpa who is here all the way from California is officiating the wedding, so this whole thing is very much a family affair.

After today I’m going to be married man. With…responsibilities! :S Never the less, I go now to meet my destiny!

This has been a prerecorded message.

My first cmdlet, Out-Web

It’s been a while since I’ve done a for fun computer project, so I decided I wanted to learn how to make PowerShell Cmdlets. The problem was that I couldn’t think of really anything I wanted to make! Then one day I was reading Lee Holmes’ blog, saw the “Out-Web” and had a project.

Download the source and binaries here. You should be able to open the solution with both Visual Studio or Visual C# Express, but if you have neither, you can build it from the command line (instructions included!). I don’t know if it’ll work with PowerShell V1, but you should have upgraded by now anyway.

I’d like to thank Mr. Cook from Cook Computing for writing an awesome tool, XML-RPC.NET. And I’d also like to thank Orbifold for their Wordpress XML-RPC library which helped decipher the RPC calls.

Test post.
Capture

Out-web test

Blogging from powershell?! Oh yeah!

Interesting Comment

I got this interesting comment today.

Hello from Russia!
Can I quote a post in your blog with the link to you?

It’s almost…not spam, but it is.

Windows Server Updates

This is what happens when automatic updates are turned off and I’m left to update the servers….I find a way to do it with as little interaction as possible.

Cracking the Windows Update API

Something that I’ve been working on for a while is an application or script that checks the availability of other servers to decide if it should start the update/restart steps. Though testing and more testing, I’ve found that even with the awesome power of Powershell, I still needed the power of a binary to get the best performance and least complexity.

However, unlike with Powershell where you can just set a variable, you gotta put more effort with C# to do something similar, especially when there’s so little documentation and I know so little about nitty gritty COM programming.

So getting the WUApi working in C# things to know.

  1. You need to reference “c:\windows\system32\wuapi.dll”
  2. You must have have the resulting “Interop.WUApi.DLL” in the same directory as you executable. (I haven’t figured out a way past this yet.)
  3. WUApi likes to die and quickly if there is the slightest error, and under C# these errors seem to be harder to pick up on.
  4. Some updates don’t like to report back how far they are in their process. IE8 for example sits at 0% until its done, so you just have to wait and wait some more.

The following code you can pretty much copy and paste into a cs file add the necessary hooks into the blank C# project, compile and it should work. It’s very Alpha and there is little error checking since I haven’t taken the time to throw test cases its way. It should also work on any OS from XP to 7.

namespace winupdate_scheduler
{
    /// <remarks>Methods actual shutdown.</remarks>
    public class grunt
    {
        public void shutdown()
        {
            throw new System.NotImplementedException();
        }

        public void restart()
        {
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// Initiate the update for great justice!
        /// </summary>
        public void update()
        {
            try
            {
                //Initate the session and begin the search!
                WUApiLib.UpdateSessionClass session = new WUApiLib.UpdateSessionClass();
                WUApiLib.IUpdateSearcher searcher = session.CreateUpdateSearcher();
                WUApiLib.ISearchResult result = searcher.Search("IsInstalled=0 and IsAssigned=1");

                //Initate the interfaces for progress and wholeness.
                InstallProgress progress = new InstallProgress();
                InstallComplete completion = new InstallComplete();

                //Dummy object for installer.BeginInstall
                object t3 = (new object());

                //Do we have anything to do?
                if (result.Updates.Count > 0)
                {
                    //Begin the long wait.
                    //Probably should look into doing that async thing here too....later.
                    Console.WriteLine("Downloading...");
                    WUApiLib.IUpdateDownloader download = session.CreateUpdateDownloader();
                    download.Updates = result.Updates;
                    download.Download();

                    //Finally, get around to installing the suckers!
                    Console.WriteLine("Installing...");
                    WUApiLib.IUpdateInstaller installer = session.CreateUpdateInstaller();
                    installer.Updates = download.Updates;
                    installer.BeginInstall(progress, completion, t3);

                    //Hold your horses! We're not done yet!
                    while (!completion.jobdone)
                    {
                        System.Threading.Thread.Sleep(2000);
                    }
                }

                //Now you can let go of your horses!
                Console.WriteLine("Done");
            }
                //Until I can get a grasp of all the exceptions that can be raised, this will have to do.
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        /// <summary>
        /// Get list of updates
        /// </summary>
        public void getupdates()
        {
            throw new System.NotImplementedException();
            WUApiLib.UpdateSessionClass session = new WUApiLib.UpdateSessionClass();
            WUApiLib.IUpdateSearcher searcher = session.CreateUpdateSearcher();
            WUApiLib.ISearchResult result = searcher.Search("IsInstalled=0 and IsAssigned=1");
        }
    }

    class InstallProgress : WUApiLib.IInstallationProgressChangedCallback
    {

        public void Invoke(WUApiLib.IInstallationJob job, WUApiLib.IInstallationProgressChangedCallbackArgs args)
        {
            this.job = job;
            this.OverallProgress = this.job.GetProgress().PercentComplete;
            this.UpdateProgress = this.job.GetProgress().CurrentUpdatePercentComplete;
            this.UpdateIndex = this.job.GetProgress().CurrentUpdateIndex;

            this.Update = this.job.Updates[this.UpdateIndex];

            string str = "Update: {0}, UpdateProgress: {1}%, Progress {2}%";
            Console.WriteLine(string.Format(str, (this.UpdateIndex + 1), this.UpdateProgress, this.OverallProgress));
        }

        public WUApiLib.IInstallationJob job;

        public int OverallProgress = 0;
        public int UpdateProgress = 0;
        public int UpdateIndex = 0;
        public WUApiLib.IUpdate Update;

    }

    class InstallComplete : WUApiLib.IInstallationCompletedCallback
    {
        public void Invoke(WUApiLib.IInstallationJob job, WUApiLib.IInstallationCompletedCallbackArgs args)
        {
            //string str = "job.IsCompleted: {0}, args.Progress: {1}% completed";
            //Console.WriteLine(string.Format(str, job.IsCompleted, job.GetProgress().PercentComplete));
            this.jobdone = job.IsCompleted;
        }
        public bool jobdone = false;
    }
}

More reading:

Fixed: fastping, now with working get-help comments

After getting frustrated with my fastping not displaying anything after using get-help, I asked the twitterverse for help, and they did! Super-duper thanks to @djryan (twitter/web) for the pointers.

<#
.SYNOPSIS
Ping a node as fast as you can.
.DESCRIPTION
Whereas the ping.exe utility keeps steady at 1 ping per second,
this will ping with custom wait periods as low as 0 milliseconds.
.Parameter ip
IP or hostname of network node.
.Parameter count
Number of pings to execute (defaults to 4)
.Parameter wait
Time to wait for a reply.
.Parameter sleep
Time to wait between pings.
.Parameter size
Number of bytes to send (all Null or 0).
.Parameter ttl
Time to live.
.INPUTS
None. You cannot pipe objects to fastping.
.OUTPUTS
Reply from {host}: status={status bytes={bytes} time={tripTime}
(xxx% loss)
.Example
    PS> fastping.ps1 -ip josherickson.org -size 1337 -wait 1
	Reply from josherickson.org: status=Success bytes=1337 time=81
	Reply from josherickson.org: status=Success bytes=1337 time=96
	Reply from josherickson.org: status=Success bytes=1337 time=81
	Reply from josherickson.org: status=TimedOut bytes=1337 time=0
	(25% loss)
.LINK
Original: http://josherickson.org/2009/09/24/586/ping-faster-from-powershell-with-fastping
.Notes
TODO: Add object based return instead of just text strings.
NAME:      verb
AUTHOR:    josherickson.org\josh
LASTEDIT:  09/25/2009
#>
param (
	[string]$ip = "127.0.0.1",
	[int]$count = 4,
	[int]$wait = 5,
	[int]$sleep = 0,
	[int]$size = 32,
	[int]$ttl = 128
)

$ping = new-object System.Net.NetworkInformation.ping
$pingo = new-object System.Net.NetworkInformation.PingOptions $ttl, $false

if($size -gt 65500) {
	throw "`$size must be equal to or less than 65500";
}

$bsize = new-object byte[] $size;

$s = 0;
$f = 0;
for($i = 0; $i -lt $count; $i++) {
	$pr = $ping.Send($ip, $wait, $bsize, $pingo)
	$s += [int][bool]($pr.status -eq "Success");
	$f += [int][bool]($pr.status -ne "Success");

	"Reply from $($ip): status=$($pr.status) bytes=$size time=$($pr.RoundtripTime)" | write-host

	sleep -Milliseconds $sleep;
}

if($f -gt 0) {
	"(" + ((100/$count)*$f) + "% loss)";
} else {
	"(0% loss)";
}
return;