Living with your Microsoft VMs "in the cloud" on a Mac

Some Background

So I am a software development consultant. This often requires me to have several different environments setup for several different customers. The best way to accomplish this that I have found is to have a virtual machine setup for each customer. This also requires that I have a copy of that vm on a laptop and at my home setup since sometimes I travel to the customer's office with my laptop.

Old Environment

Apple FanBoy is another adjective that describes who I am. I make money writing code in Microsoft .NET and in the Windows environment but I use the Mac side for everything else. I use a 13" Macbook for client visits and a MacPro beast at home. I placed each client's Windows environment in a VMWare VM with the necessary tools like Visual Studio, Subversion, Git, SQL Server, etc. I would then keep the VM on an external drive and run he VM from my MacPro at home or my MacBook on the road. If I knew that I was going to be at a client for a long time, I would copy that VM locally to my MacBook since it would run faster from my laptops SSD drive. Once I worked at the client site a couple of days, I would copy that VM back to my external drive to run from both at home and at a client site.

Some Issues with Old Environment

There were a lot of issues that I did not like with this setup of copying vms. The first issue was that this was substantially inefficient. Copying 30 gig vm files from external drive to internal drive on various computers took around 20 minutes a piece. This made it hard to quickly get out to a client site for a meeting or to quickly copy the VM back for a "quick fix".

Another issue related to copying vms was that Windows Software Authentication which makes sure you're not using the latest China build is horrible. When copying the vm from one machine to another and/or running the vm on an external drive from different host machines, the horrible satanic "Genuine Advantage" would get confused and de-authenticate your OS since the hardware is changing so much.

The New Environment

The new environment eliminates the issues with the old environment. With the new environment, I still run all of my customer setups in separate VMs. The difference is that these VMs are always run from home on my MacPro. This 8-core, 16G Ram machine is perfectly fine with running multiple (anywhere from 5 - 8) VMs at a time. When I bounce to a client site I still run these VMs from my home computer and I connect to them over Windows Remote Desktop Connection for the Mac.

You really do not see any difference with running this way. The advantage is that I do not need to copy the VMs onto my laptop anymore and I do not get bothered with the software authentication anymore. I don't have to worry about having multiple copies of the same VM on different machines and a portable drive. The biggest advantage is the state of the VM is always constant. I can close my laptop at anytime and know that when I get home, the VM will be in the exact state as I have left it when I closed my laptop. This is especially useful with long running scripts or builds that need to be run and you have to split.

There are a few disadvantages that mostly deal with connection issues. You may have spotty Wifi coverage that causes some lag but the Windows Remote Desktop software is really well written for those scenarios. I have used a VM over a Sprint 3G connection many-o-times without any issues. 

Another issue is that I cannot get any Windows Aero features since Windows does not like you to use those features over RDC. This is not a big deal for me but it may be for you.

I still carry a portable VM with me just in case of an emergency. If I can't connect for some reason, I still have VMWare installed on my laptop and I can get some version of the customer VM from the local drive.

How to setup the New Environment

There are 3 steps to getting this new environment setup on your VM.

 

  1. Setup your guest virtual machine
  2. Setup your host machine & router
  3. Create a dynamic DNS to connect over the internet

Setup your guest virtual machine

I am using VMWare Fusion on my Mac and the screenshots below are from that application. I am sure all virtual machine software apps have these features so use what you like such as Parallels or Virtual Box.

 

  • Change wireless settings on VM to use a bridged connection

In order for your host machine to pass the connection on from the internet to your VM, your VM must have it's network settings on Bridged. I believe the default for Fusion is NAT and so you to change this to Bridged. 

[DISCLAIMER: I am horrible at network administration and so some of this may not be needed or wrong. Please check with a certified network person thingy. I am not responsible for you fucking your stuff up.]

From Fusion, select your VM from you want to make available from the interwebs and select Virtual Machine -> Settings (CMD+E). Select Network and make sure your settings are like the following:


 

  • Change Remote Settings on your Windows VM

On your guest machine, you need to setup Windows to allow for remote connections for remote desktop.

From the Control Panel, browse to System and Maintenance -> System. On the left hand side, select Remote settings.


 

On the Remote settings screen, check "Allow Remote Assistance connections to this computer" and check "Allow connections from computers running any version of Remote Desktop (less secure)."


 

  • Turn off IPv6 [if needed] on your Windows VM

OK, I am unsure why you need to do this but I did in my case. You may not need to do this or you may have to change other settings. Again, I am an idiot when it comes to network administration.

From the Control Panel, browse to Network and Internet -> Network and Sharing Center. On the lef hand side, select Manage network connections.


 

Right-click on your active network connection, and select Properties. Uncheck "Internet Protocol Version 6 (TCP/IPv6)".


 

  • Set static IP address on your Windows VM

You need to setup a static IP address for your VM instead of using a DHCP server which is normally the default. This is an internal static IP address for your internal network. These usually start with 10.0.1.XX. I make sure that the XX will be the same number as the port that I am going to be using to identify the VM later. I start with port 85 and go up from there (skipping 89). You can use any number for XX as long as it does not conflict with other devices in your house such as a Slingbox or another FileServer, etc.

From the Control Panel, browse to Network and Internet -> Network and Sharing Center. On the right hand side, select Manage network connections (same as above).

Right-click on your active network connection, and select Properties (same as above).

Click on "Internet Protocol Version 4 (TCP/IPv4)" and click Properties. In the following window, click on "Use the following IP address" and set your IP address according to the recommendations above.

In this instance, I used 10.0.1.90 to identify this machine since I will connect to it over port 3390. Make sure you remember what this is as you will need it in a little bit.


 

 

You should now be able to ping your VM from another computer in your house and from your host machine. Try to ping your static IP address that you set. If you are unsuccessful, carefully follow the steps above again.

 

 

  • Update Registry settings on your Windows VM

In order to connect to your multiple VMs from the internet, you need to change the port number that they are connecting to. By default, Remote Desktop connections occur over port 3389 and we will change this default port since we will have multiple VMs. Another advantage of doing this is that if you are a customer site, some customer sites block outgoing port 3389 requests and this will get around that.

 

Start the Registry Editor by going to Start -> and type regedit and click enter.

Browse to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TerminalServer\WinStations\RDP-Tcp\PortNumber.

Change the value to the port number you want to use. In this instance, I used 3390 as the port number.


 

Here is another article on changing your RD listening port: http://support.microsoft.com/kb/306759.

  • Add Firewall port exceptions on your Windows VM

You need to add TCP and UDP exceptions to the Windows Firewall in order to connect to your VM over RD for the port that you specified above. 

From the Control Panel, browse to Network and Internet -> Windows Firewall. On the left hand side, select "Allow a program through Windows Firewall".


 

Click on the Exceptions tab and then click the "Add port..." button. On the following window, set the name to "Remote Desktop TCP (3390)" (or the port number you used), set Port number to the one you specified above, and set the Protocol to TCP. Here is what it should look like in this instance:


 

You will want to do the same thing for UDP. Here is what that should look like in this instance:


 

 

Setup your host machine / router

OK, the hard part is done. Now in order to connect to your VM from the internets, you need to be able to route your request in your router for the specified port number to the appropriate VM. To do this, you need to map your port to the appropriate VM. I will show you how to do this for the Apple Airport Extreme / Time Capsule since that is what I am using. I am sure it is easy to find information on port mapping for your specific router on the internet, just Google it.

Open up your Airport Utility and click on Manual Setup for your router.


 

Click on the Advanced tab and click on Port Mapping (it may take a few seconds to be enabled).



  

Click on the small + at the bottom of the Allow list.

Enter your port number (3390 in this case) in the public and private UDP ports and the public and private TCP ports. Enter your internal static IP address (10.0.1.90 in this case).


 

Click Continue.

Enter a description here and click done. I usually use the name of my client followed by " Windows VM" as the name.

That is it for the port mapping. Continue adding all the VMs you want to allow with different ports and IP addresses. Make sure that they do not collide with other devices and services on your network.

The next step is to download the Remote Desktop Client for the Mac on your laptop or other device where you want to access these VMs remotely. You can get the software here. The Remote Desktop client is at the bottom listed under products (horrible page, I know). You then want the latest version.


 

You should be able to connect to your VMs over the internet now. Using your current outside IP address (you can find out what it is by going to http://checkip.dyndns.com/) and the port number, you can connect via Remote Desktop Client. Just use the format XX.XXX.XX.X:3390 (or your port number) and click connect. It will then ask you for your Windows username and password. Bam! Your living in the cloud man.

You can save each connection via the RD Client. I do this by saving via customer name and then use the Recent Connections menu item to switch back and forth.

Create a dynamic DNS to connect over the internet

The final thing you need is a static IP address if you do not already have one through your ISP. The good news is that there is a free service which allows you to use your dynamic IP address that is usually what your ISP will give you for free. They usually don't change this often but when they do, you will not be able to connect to your VMs anymore.

DynDNS allows you to specify a domain name and you can use this domain name to link to your dynamic ip address. The trick is that you download a small application on your host machine which notifies DynDNS when your IP address has changed so that it can update where it points the domain to. The free account is pretty easy to use. The only catch is that DynDNS will send you an email once a month with a link that you need to verify that you are still using the service. If that is too much trouble for you, feel free to pay for it using their pricing services.

The signup is pretty self explanatory. You can download the client at https://www.dyndns.com/support/clients. The client is not needed as they have a web interface as well if you don't want to clutter up your system. I did not install it as the dynamic IP address does not change at all for me.


I know this was long but I wanted to make it detailed enough to follow pretty easy. It's really nice to work this way once it is set up properly. Happy living...

 

CodeRush Template for CSLA Properties [Updated]

[Update: Thanks to Mark Miller's comments below, I have changed the templates and added a link to the new ones below marked as version 2. The new templates fix some bugs and add some additional functionality. You can now use nullables and generics in your type definition without issue. I changed the shortcuts as well as added additional shortcuts. I have outlined these below:

  1. krp -> [Rocky Lhotka Register Property] Registers a CSLA property
  2. kdp -> [Rocky Lhotka Declare Property] Declares a CSLA property
  3. krdp -> [Rocky Lhotka Register and Declare Property] Declare and Register a CSLA property
  4. krp<Type> -> Registers a CSLA property with a specified type where you only have to fill in the property name. For example krpi will create a registered property of type int. There are a lot of type shortcuts that ship with CodeRush.
  5. kdp<Type> -> Declares a CSLA property with a specified type. Works similar to#4 above except it declares the property.

]

Version 3.0 of CSLA.NET brought a new way of declaring fields and properties within business objects. This was done in order to reduce the amount of code that needed to be written and to reduce the possibility of creating runtime exceptions.

Before version 3.0 of CSLA.NET, the business object developer would have to ensure that certain lines of code were present in order for state tracking and validation to work correctly. The following lines of code are an example of how business object properties were written previous to version 3.0.

 

1: [Serializable()]
2: public class Customer : Csla.BusinessBase<Customer>
3: {
4:  private string _firstName;
5:  
6:  public string FirstName
7:  {
8:  get
9:  {
10:  CanReadProperty(true);
11:  return _firstName;
12:  }
13:  set
14:  {
15:  CanWriteProperty(true);
16:  if (_firstName != value)
17:  {
18:  _firstName = value;
19:  PropertyHasChanged();
20:  }
21:  }
22:  }
23:  
24:  private Customer()
25:  {
26:  }
27: }

 

You can see this is pretty standard property/field declaration that you would see in any object (before Auto-Implemented properties). Let me explain what the various CSLA.NET specific calls do.

In line 10, there is a call to a base class method CanReadProperty. This method checks the current roles that are assigned to the user that is logged and makes sure that the current user has the rights to read this specific property. Property level authorization is another feature of CSLA.NET which I will explain at a later date. The parameter of true that is passed to the call specifies that the application should throw an exception at this point if the user is not authorized to read the property.

Similar functionality for authorizing a property setter is found in line 15 with a call to the base method of CanWriteProperty. 

The last bit of functionality that this code sample demonstrates is the ability for CSLA to perform state tracking and validation. Business objects in CSLA have the ability to let the client of the business layer to determine if an object is dirty, new, or saved to the data store. A key piece of this functionality is implemented with a call to the PropertyHasChanged method as shown in line 19 above. This call does 2 things. First it marks the object as being dirty. Therefore, when the client application calls Save, the business object knows that it needs to perform an update or an insert into the data store. Second, the business object performs validation for all the validation rules based on that property. For example, if the Customer object contained a business rule stating that the FirstName property needed to have a non null or empty value and the client application assigned a string.Empty, the object would then be marked as invalid. If the user then tried to save the object, a ValidationException would be thrown by the business object.

As you can see, these steps of simply retrieving and setting property values have a large impact on how the CSLA business object operates. Skipping one of these steps or performing one of these steps at the wrong time can easily lead to logical errors. Because of this, Rocky Lhotka introduced the concept of registering properties in CSLA version 3, a la Windows Workflow properties.

Here is an example of the how a business object developer would write the same functionality in CSLA version 3.0 and above:

 

1: [Serializable()]
2: public class Customer : Csla.BusinessBase<Customer>
3: {
4:  private static PropertyInfo<string> FirstNameProperty = RegisterProperty<string>(typeof(Customer), new PropertyInfo<string>("FirstName"));
5:  
6:  public string FirstName
7:  {
8:  get
9:  {
10:  return GetProperty<string>(FirstNameProperty);
11:  }
12:  set
13:  {
14:  SetProperty<string>(FirstNameProperty, value);
15:  }
16:  }
17:  
18:  private Customer()
19:  {
20:  }
21: }

 

As you can see, this is a lot less code and it performs the same amount of functionality as the code listed above. The code at line 10 makes a call to a base class GetProperty method. This method internally makes a call to CanReadProperty just as above. The code at line 14 makes a call to SetProperty. This methon internally makes a call to CanWriteProperty and PropertyHasChanged respectively.

Although the latter implementation requires less code and is less error prone, it is still very verbose and it requires a lot of typing. Since declaring properties is what a business object developer does a lot of, I decided that a code template would be great to implement. I am a huge fan of CodeRush and Refactor as I have been using those productivity tools for a while now. I decided to write a custom CodeRush template for declaring properties in CSLA.

Creating a field, or in this case, registering a property on a class, only requires a user to type RP (Register Property), followed by the type and name of the property. Creating a property only requires a user to type DRP (Declare Registered Property), followed by the type and name of the property.

I demonstrate their use in the video below. [NOTE: In the video, I make reference to generics when I really meant nullable types. I was obviously on something.].

 

 

If you use CodeRush and you would like to install these templates, I outlined the steps below.

  1. Download the attached xml file
  2. Open Visual Studio
  3. Browse to DevExpress -> Options
  4. On the left hand, find Editor -> Templates
  5. Create a folder called Custom Templates if it is not already created
    1. Right-click on the folder structure and click New Root Category...
    2. Name the folder Custom Templates
  • Import attached template (xml file)
    1. Right click on Custom Templates and click Import Templates...
  • You will now be able to use the RP and DRP custom templates as shown above. You may need to restart Visual Studio for these templates to take effect.

    There are also Codesmith templates available if you would rather use Codesmith templates as there are a lot of these available for CSLA. You can check the templates out here.

    Download CodeRush Template (XML file)

    Download CodeRush Template Version 2 (see update above) (XML file)