CLOUDSTACK-6518 [Hyper-V] Efficient way of finding the empty nic in VR/VpcVR to configure VPC entities fixed windows line ending issues

Conflicts:
	plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
diff --git a/core/src/com/cloud/agent/api/GetVmConfigAnswer.java b/core/src/com/cloud/agent/api/GetVmConfigAnswer.java
index 46e003e..e0d1536 100644
--- a/core/src/com/cloud/agent/api/GetVmConfigAnswer.java
+++ b/core/src/com/cloud/agent/api/GetVmConfigAnswer.java
@@ -42,13 +42,15 @@
     public class NicDetails {
         String macAddress;
         int vlanid;
+        boolean state;
 
         public NicDetails() {
         }
 
-        public NicDetails(String macAddress, int vlanid) {
+        public NicDetails(String macAddress, int vlanid, boolean state) {
             this.macAddress = macAddress;
             this.vlanid = vlanid;
+            this.state = state;
         }
 
         public String getMacAddress() {
@@ -59,6 +61,9 @@
             return vlanid;
         }
 
+        public boolean getState() {
+            return state;
+        }
     }
 
     @Override
diff --git a/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java b/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
index 5f4f0e1..54c0eb0 100644
--- a/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
+++ b/core/src/com/cloud/agent/api/ModifyVmNicConfigCommand.java
@@ -22,6 +22,9 @@
     int vlan;
     String macAddress;
     int index;
+    boolean enable;
+    String switchLableName;
+
     protected ModifyVmNicConfigCommand() {
     }
 
@@ -37,10 +40,24 @@
         this.index = position;
     }
 
+    public ModifyVmNicConfigCommand(String vmName, int vlan, int position, boolean enable) {
+        this.vmName = vmName;
+        this.vlan = vlan;
+        this.index = position;
+        this.enable = enable;
+    }
+
     public String getVmName() {
         return vmName;
     }
 
+    public String getSwitchLableName() {
+        return switchLableName;
+    }
+
+    public void setSwitchLableName(String switchlableName) {
+        this.switchLableName = switchlableName;
+    }
 
     @Override
     public boolean executeInSequence() {
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
index c222102..ef24c79 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/CloudStackTypes.cs
@@ -711,11 +711,22 @@
         public string macaddress;
         [JsonProperty("vlanid")]
         public int vlanid;
+        [JsonProperty("state")]
+        public bool state;
         public NicDetails() { }
-        public NicDetails(String macaddress, int vlanid)
+        public NicDetails(String macaddress, int vlanid, int enabledState)
         {
             this.macaddress = macaddress;
             this.vlanid = vlanid;
+            if (enabledState == 2)
+            {
+                this.state = true;
+            }
+            else
+            {
+                this.state = false;
+            }
+
         }
     }
 
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
index 0f084db..67c367d 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResourceController.cs
@@ -1,112 +1,112 @@
-// Licensed to the Apache Software Foundation (ASF) under one

-// or more contributor license agreements.  See the NOTICE file

-// distributed with this work for additional information

-// regarding copyright ownership.  The ASF licenses this file

-// to you under the Apache License, Version 2.0 (the

-// "License"); you may not use this file except in compliance

-// with the License.  You may obtain a copy of the License at

-//

-//   http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing,

-// software distributed under the License is distributed on an

-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

-// KIND, either express or implied.  See the License for the

-// specific language governing permissions and limitations

-// under the License.

-

-using Amazon;

-using Amazon.S3;

-using Amazon.S3.Model;

-using log4net;

-using Microsoft.CSharp.RuntimeBinder;

-using Newtonsoft.Json;

-using Newtonsoft.Json.Linq;

-using System;

-using System.Collections;

-using System.Collections.Specialized;

-using System.Collections.Generic;

-using System.Configuration;

-using System.IO;

-using System.Linq;

-using System.Net;

-using System.Net.Http;

-using System.Text;

-using System.Security.Cryptography;

-using System.Security.Principal;

-using System.Web.Http;

-using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;

-

-namespace HypervResource

-{

-

-    public struct HypervResourceControllerConfig

-    {

-        private string privateIpAddress;

-        private static ILog logger = LogManager.GetLogger(typeof(HypervResourceControllerConfig));

-

-        public string PrivateIpAddress

-        {

-            get

-            {

-                return privateIpAddress;

-            }

-            set

-            {

-                ValidateIpAddress(value);

-                privateIpAddress = value;

-                System.Net.NetworkInformation.NetworkInterface nic = HypervResourceController.GetNicInfoFromIpAddress(privateIpAddress, out PrivateNetmask);

-                PrivateMacAddress = nic.GetPhysicalAddress().ToString();

-            }

-        }

-

-        private static void ValidateIpAddress(string value)

-        {

-            // Convert to IP address

-            IPAddress ipAddress;

-            if (!IPAddress.TryParse(value, out ipAddress))

-            {

-                String errMsg = "Invalid PrivateIpAddress: " + value;

-                logger.Error(errMsg);

-                throw new ArgumentException(errMsg);

-            }

-        }

-        public string GatewayIpAddress;

-        public string PrivateMacAddress;

-        public string PrivateNetmask;

-        public string StorageNetmask;

-        public string StorageMacAddress;

-        public string StorageIpAddress;

-        public long RootDeviceReservedSpaceBytes;

-        public string RootDeviceName;

-        public ulong ParentPartitionMinMemoryMb;

-        public string LocalSecondaryStoragePath;

-        public string systemVmIso;

-

-        private string getPrimaryKey(string id)

-        {

-            return "primary_storage_" + id;

-        }

-

-        public string getPrimaryStorage(string id)

-        {

-            NameValueCollection settings = ConfigurationManager.AppSettings;

-            return settings.Get(getPrimaryKey(id));

-        }

-

-        public void setPrimaryStorage(string id, string path)

-        {

-            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

-            KeyValueConfigurationCollection settings = config.AppSettings.Settings;

-            string key = getPrimaryKey(id);

-            if (settings[key] != null)

-            {

-                settings.Remove(key);

-            }

-            settings.Add(key, path);

-            config.Save(ConfigurationSaveMode.Modified);

-            ConfigurationManager.RefreshSection("appSettings");

-        }

+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using Amazon;
+using Amazon.S3;
+using Amazon.S3.Model;
+using log4net;
+using Microsoft.CSharp.RuntimeBinder;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Security.Cryptography;
+using System.Security.Principal;
+using System.Web.Http;
+using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;
+
+namespace HypervResource
+{
+
+    public struct HypervResourceControllerConfig
+    {
+        private string privateIpAddress;
+        private static ILog logger = LogManager.GetLogger(typeof(HypervResourceControllerConfig));
+
+        public string PrivateIpAddress
+        {
+            get
+            {
+                return privateIpAddress;
+            }
+            set
+            {
+                ValidateIpAddress(value);
+                privateIpAddress = value;
+                System.Net.NetworkInformation.NetworkInterface nic = HypervResourceController.GetNicInfoFromIpAddress(privateIpAddress, out PrivateNetmask);
+                PrivateMacAddress = nic.GetPhysicalAddress().ToString();
+            }
+        }
+
+        private static void ValidateIpAddress(string value)
+        {
+            // Convert to IP address
+            IPAddress ipAddress;
+            if (!IPAddress.TryParse(value, out ipAddress))
+            {
+                String errMsg = "Invalid PrivateIpAddress: " + value;
+                logger.Error(errMsg);
+                throw new ArgumentException(errMsg);
+            }
+        }
+        public string GatewayIpAddress;
+        public string PrivateMacAddress;
+        public string PrivateNetmask;
+        public string StorageNetmask;
+        public string StorageMacAddress;
+        public string StorageIpAddress;
+        public long RootDeviceReservedSpaceBytes;
+        public string RootDeviceName;
+        public ulong ParentPartitionMinMemoryMb;
+        public string LocalSecondaryStoragePath;
+        public string systemVmIso;
+
+        private string getPrimaryKey(string id)
+        {
+            return "primary_storage_" + id;
+        }
+
+        public string getPrimaryStorage(string id)
+        {
+            NameValueCollection settings = ConfigurationManager.AppSettings;
+            return settings.Get(getPrimaryKey(id));
+        }
+
+        public void setPrimaryStorage(string id, string path)
+        {
+            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+            KeyValueConfigurationCollection settings = config.AppSettings.Settings;
+            string key = getPrimaryKey(id);
+            if (settings[key] != null)
+            {
+                settings.Remove(key);
+            }
+            settings.Add(key, path);
+            config.Save(ConfigurationSaveMode.Modified);
+            ConfigurationManager.RefreshSection("appSettings");
+        }
 
         public List<string> getAllPrimaryStorages()
         {
@@ -122,673 +122,673 @@
             }
             return poolPaths;
         }
-    }

-

-    /// <summary>

-    /// Supports one HTTP GET and multiple HTTP POST URIs

-    /// </summary>

-    /// <remarks>

-    /// <para>

-    /// POST takes dynamic to allow it to receive JSON without concern for what is the underlying object.

-    /// E.g. http://stackoverflow.com/questions/14071715/passing-dynamic-json-object-to-web-api-newtonsoft-example 

-    /// and http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object

-    /// Use ActionName attribute to allow multiple POST URLs, one for each supported command

-    /// E.g. http://stackoverflow.com/a/12703423/939250

-    /// Strictly speaking, this goes against the purpose of an ApiController, which is to provide one GET/POST/PUT/DELETE, etc.

-    /// However, it reduces the amount of code by removing the need for a switch according to the incoming command type.

-    /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx

-    /// </para>

-    /// <para>

-    /// Exceptions handled on command by command basis rather than globally to allow details of the command

-    /// to be reflected in the response.  Default error handling is in the catch for Exception, but

-    /// other exception types may be caught where the feedback would be different.

-    /// NB: global alternatives discussed at 

-    /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx

-    /// </para>

-    /// </remarks>

-    public class HypervResourceController : ApiController

-    {

-        public static void Configure(HypervResourceControllerConfig config)

-        {

-            HypervResourceController.config = config;

-            wmiCallsV2 = new WmiCallsV2();

-        }

-

-        public static HypervResourceControllerConfig config = new HypervResourceControllerConfig();

-

-        private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController));

-        private string systemVmIso  = "";

-        Dictionary<String, String> contextMap = new Dictionary<String, String>();

-

-        public static void Initialize()

-        {

-        }

-

-        public static IWmiCallsV2 wmiCallsV2 { get; set;}

-

-        // GET api/HypervResource

-        public string Get()

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                return "HypervResource controller running, use POST to send JSON encoded RPCs"; ;

-            }

-        }

-

-        /// <summary>

-        /// NOP - placeholder for future setup, e.g. delete existing VMs or Network ports 

-        /// POST api/HypervResource/SetupCommand

-        /// </summary>

-        /// <param name="cmd"></param>

-        /// <returns></returns>

-        /// TODO: produce test

-        [HttpPost]

-        [ActionName(CloudStackTypes.SetupCommand)]

-        public JContainer SetupCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+    }
+
+    /// <summary>
+    /// Supports one HTTP GET and multiple HTTP POST URIs
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// POST takes dynamic to allow it to receive JSON without concern for what is the underlying object.
+    /// E.g. http://stackoverflow.com/questions/14071715/passing-dynamic-json-object-to-web-api-newtonsoft-example 
+    /// and http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object
+    /// Use ActionName attribute to allow multiple POST URLs, one for each supported command
+    /// E.g. http://stackoverflow.com/a/12703423/939250
+    /// Strictly speaking, this goes against the purpose of an ApiController, which is to provide one GET/POST/PUT/DELETE, etc.
+    /// However, it reduces the amount of code by removing the need for a switch according to the incoming command type.
+    /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
+    /// </para>
+    /// <para>
+    /// Exceptions handled on command by command basis rather than globally to allow details of the command
+    /// to be reflected in the response.  Default error handling is in the catch for Exception, but
+    /// other exception types may be caught where the feedback would be different.
+    /// NB: global alternatives discussed at 
+    /// http://weblogs.asp.net/fredriknormen/archive/2012/06/11/asp-net-web-api-exception-handling.aspx
+    /// </para>
+    /// </remarks>
+    public class HypervResourceController : ApiController
+    {
+        public static void Configure(HypervResourceControllerConfig config)
+        {
+            HypervResourceController.config = config;
+            wmiCallsV2 = new WmiCallsV2();
+        }
+
+        public static HypervResourceControllerConfig config = new HypervResourceControllerConfig();
+
+        private static ILog logger = LogManager.GetLogger(typeof(HypervResourceController));
+        private string systemVmIso  = "";
+        Dictionary<String, String> contextMap = new Dictionary<String, String>();
+
+        public static void Initialize()
+        {
+        }
+
+        public static IWmiCallsV2 wmiCallsV2 { get; set;}
+
+        // GET api/HypervResource
+        public string Get()
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                return "HypervResource controller running, use POST to send JSON encoded RPCs"; ;
+            }
+        }
+
+        /// <summary>
+        /// NOP - placeholder for future setup, e.g. delete existing VMs or Network ports 
+        /// POST api/HypervResource/SetupCommand
+        /// </summary>
+        /// <param name="cmd"></param>
+        /// <returns></returns>
+        /// TODO: produce test
+        [HttpPost]
+        [ActionName(CloudStackTypes.SetupCommand)]
+        public JContainer SetupCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.SetupCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.SetupCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = "success - NOP",

-                    _reconnect = false,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.SetupAnswer);

-            }

-        }

-

-        // POST api/HypervResource/AttachCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.AttachCommand)]

-        public JContainer AttachCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.AttachCommand + Utils.CleanString(cmd.ToString()));

-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    string vmName = (string)cmd.vmName;

-                    DiskTO disk = DiskTO.ParseJson(cmd.disk);

-

-                    if (disk.type.Equals("ISO"))

-                    {

-                        TemplateObjectTO dataStore = disk.templateObjectTO;

-                        NFSTO share = dataStore.nfsDataStoreTO;

-                        Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);

-                        string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));

-                        wmiCallsV2.AttachIso(vmName, diskPath);

-                        result = true;

-                    }

-                    else if (disk.type.Equals("DATADISK"))

-                    {

-                        VolumeObjectTO volume = disk.volumeObjectTO;

-                        PrimaryDataStoreTO primary = volume.primaryDataStore;

-                        if (!primary.isLocal)

-                        {

-                            Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);

-                        }

-                        string diskPath = Utils.NormalizePath(volume.FullFileName);

-                        wmiCallsV2.AttachDisk(vmName, diskPath, disk.diskSequence);

-                        result = true;

-                    }

-                    else

-                    {

-                        details = "Invalid disk type to be attached to vm " + vmName;

-                    }

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.AttachCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    disk = cmd.disk,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.AttachAnswer);

-            }

-        }

-

-        // POST api/HypervResource/DetachCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.DettachCommand)]

-        public JContainer DetachCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.DettachCommand + Utils.CleanString(cmd.ToString()));

-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    string vmName = (string)cmd.vmName;

-                    DiskTO disk = DiskTO.ParseJson(cmd.disk);

-

-                    if (disk.type.Equals("ISO"))

-                    {

-                        TemplateObjectTO dataStore = disk.templateObjectTO;

-                        NFSTO share = dataStore.nfsDataStoreTO;

-                        string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));

-                        wmiCallsV2.DetachDisk(vmName, diskPath);

-                        result = true;

-                    }

-                    else if (disk.type.Equals("DATADISK"))

-                    {

-                        VolumeObjectTO volume = disk.volumeObjectTO;

-                        PrimaryDataStoreTO primary = volume.primaryDataStore;

-                        string diskPath = Utils.NormalizePath(volume.FullFileName);

-                        wmiCallsV2.DetachDisk(vmName, diskPath);

-                        result = true;

-                    }

-                    else

-                    {

-                        details = "Invalid disk type to be dettached from vm " + vmName;

-                    }

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.DettachCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.DettachAnswer);

-            }

-        }

-

-        // POST api/HypervResource/RebootCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.RebootCommand)]

-        public JContainer RebootCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.SetupCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = "success - NOP",
+                    _reconnect = false,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.SetupAnswer);
+            }
+        }
+
+        // POST api/HypervResource/AttachCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.AttachCommand)]
+        public JContainer AttachCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.AttachCommand + Utils.CleanString(cmd.ToString()));
+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string vmName = (string)cmd.vmName;
+                    DiskTO disk = DiskTO.ParseJson(cmd.disk);
+
+                    if (disk.type.Equals("ISO"))
+                    {
+                        TemplateObjectTO dataStore = disk.templateObjectTO;
+                        NFSTO share = dataStore.nfsDataStoreTO;
+                        Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);
+                        string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));
+                        wmiCallsV2.AttachIso(vmName, diskPath);
+                        result = true;
+                    }
+                    else if (disk.type.Equals("DATADISK"))
+                    {
+                        VolumeObjectTO volume = disk.volumeObjectTO;
+                        PrimaryDataStoreTO primary = volume.primaryDataStore;
+                        if (!primary.isLocal)
+                        {
+                            Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);
+                        }
+                        string diskPath = Utils.NormalizePath(volume.FullFileName);
+                        wmiCallsV2.AttachDisk(vmName, diskPath, disk.diskSequence);
+                        result = true;
+                    }
+                    else
+                    {
+                        details = "Invalid disk type to be attached to vm " + vmName;
+                    }
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.AttachCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    disk = cmd.disk,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.AttachAnswer);
+            }
+        }
+
+        // POST api/HypervResource/DetachCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.DettachCommand)]
+        public JContainer DetachCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.DettachCommand + Utils.CleanString(cmd.ToString()));
+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string vmName = (string)cmd.vmName;
+                    DiskTO disk = DiskTO.ParseJson(cmd.disk);
+
+                    if (disk.type.Equals("ISO"))
+                    {
+                        TemplateObjectTO dataStore = disk.templateObjectTO;
+                        NFSTO share = dataStore.nfsDataStoreTO;
+                        string diskPath = Utils.NormalizePath(Path.Combine(share.UncPath, dataStore.path));
+                        wmiCallsV2.DetachDisk(vmName, diskPath);
+                        result = true;
+                    }
+                    else if (disk.type.Equals("DATADISK"))
+                    {
+                        VolumeObjectTO volume = disk.volumeObjectTO;
+                        PrimaryDataStoreTO primary = volume.primaryDataStore;
+                        string diskPath = Utils.NormalizePath(volume.FullFileName);
+                        wmiCallsV2.DetachDisk(vmName, diskPath);
+                        result = true;
+                    }
+                    else
+                    {
+                        details = "Invalid disk type to be dettached from vm " + vmName;
+                    }
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.DettachCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.DettachAnswer);
+            }
+        }
+
+        // POST api/HypervResource/RebootCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.RebootCommand)]
+        public JContainer RebootCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.RebootCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    string vmName = (string)cmd.vmName;

-                    var sys = wmiCallsV2.GetComputerSystem(vmName);

-                    if (sys == null)

-                    {

-                        details = CloudStackTypes.RebootCommand + " requested unknown VM " + vmName;

-                        logger.Error(details);

-                    }

-                    else

-                    {

-                        wmiCallsV2.SetState(sys, RequiredState.Reset);

-                        result = true;

-                    }

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.RebootCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer);

-            }

-        }

-

-        // POST api/HypervResource/DestroyCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.DestroyCommand)]

-        public JContainer DestroyCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string vmName = (string)cmd.vmName;
+                    var sys = wmiCallsV2.GetComputerSystem(vmName);
+                    if (sys == null)
+                    {
+                        details = CloudStackTypes.RebootCommand + " requested unknown VM " + vmName;
+                        logger.Error(details);
+                    }
+                    else
+                    {
+                        wmiCallsV2.SetState(sys, RequiredState.Reset);
+                        result = true;
+                    }
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.RebootCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.RebootAnswer);
+            }
+        }
+
+        // POST api/HypervResource/DestroyCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.DestroyCommand)]
+        public JContainer DestroyCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.DestroyCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    // Assert

+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    // Assert
                     String errMsg = "No 'volume' details in " + CloudStackTypes.DestroyCommand + " " + Utils.CleanString(cmd.ToString());
-                    if (cmd.volume == null)

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-

-                    // Assert

-                    errMsg = "No valide path in DestroyCommand in " + CloudStackTypes.DestroyCommand + " " + (String)cmd.ToString();

-                    if (cmd.volume.path == null)

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-

-                    String path = (string)cmd.volume.path;

-                    if (!File.Exists(path))

-                    {

-                        logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);

-                    }

-

-                    string vmName = (string)cmd.vmName;

-                    if (!string.IsNullOrEmpty(vmName) && File.Exists(path))

-                    {

-                        // Make sure that this resource is removed from the VM

-                        wmiCallsV2.DetachDisk(vmName, path);

-                    }

-

-                    File.Delete(path);

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                    {

-                        result = result,

-                        details = details,

-                        contextMap = contextMap

-                    };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

-        // POST api/HypervResource/DeleteCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.DeleteCommand)]

-        public JContainer DeleteCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                    if (cmd.volume == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+
+                    // Assert
+                    errMsg = "No valide path in DestroyCommand in " + CloudStackTypes.DestroyCommand + " " + (String)cmd.ToString();
+                    if (cmd.volume.path == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+
+                    String path = (string)cmd.volume.path;
+                    if (!File.Exists(path))
+                    {
+                        logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);
+                    }
+
+                    string vmName = (string)cmd.vmName;
+                    if (!string.IsNullOrEmpty(vmName) && File.Exists(path))
+                    {
+                        // Make sure that this resource is removed from the VM
+                        wmiCallsV2.DetachDisk(vmName, path);
+                    }
+
+                    File.Delete(path);
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                    {
+                        result = result,
+                        details = details,
+                        contextMap = contextMap
+                    };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
+        // POST api/HypervResource/DeleteCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.DeleteCommand)]
+        public JContainer DeleteCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.DestroyCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    // Assert

+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    // Assert
                     String errMsg = "No 'volume' details in " + CloudStackTypes.DestroyCommand + " " + Utils.CleanString(cmd.ToString());
-                    VolumeObjectTO destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.data);

-

-                    if (destVolumeObjectTO.name == null)

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-

-                    String path = destVolumeObjectTO.FullFileName;

-                    if (!File.Exists(path))

-                    {

-                        logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);

-                    }

-

-                    string vmName = (string)cmd.vmName;

-                    if (!string.IsNullOrEmpty(vmName) && File.Exists(path))

-                    {

-                        // Make sure that this resource is removed from the VM

-                        wmiCallsV2.DetachDisk(vmName, path);

-                    }

-

-                    File.Delete(path);

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

-        

-        private static JArray ReturnCloudStackTypedJArray(object ansContent, string ansType)

-        {

-            JObject ansObj = Utils.CreateCloudStackObject(ansType, ansContent);

-            JArray answer = new JArray(ansObj);

-            logger.Info(Utils.CleanString(ansObj.ToString()));

-            return answer;

-        }

-

-        // POST api/HypervResource/CreateCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CreateCommand)]

-        public JContainer CreateCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.CreateCommand + Utils.CleanString(cmd.ToString()));

-

-                string details = null;

-                bool result = false;

-                VolumeInfo volume = new VolumeInfo();

-

-                try

-                {

-                    string diskType = cmd.diskCharacteristics.type;

-                    ulong disksize = cmd.diskCharacteristics.size;

-                    string templateUri = cmd.templateUrl;

-

-                    // assert: valid storagepool?

-                    string poolTypeStr = cmd.pool.type;

-                    string poolLocalPath = cmd.pool.path;

-                    string poolUuid = cmd.pool.uuid;

-                    string newVolPath = null;

-                    long volId = cmd.volId;

-                    string newVolName = null;

-

-                    if (ValidStoragePool(poolTypeStr, poolLocalPath, poolUuid, ref details))

-                    {

-                        // No template URI?  Its a blank disk.

-                        if (string.IsNullOrEmpty(templateUri))

-                        {

-                            // assert

-                            VolumeType volType;

-                            if (!Enum.TryParse<VolumeType>(diskType, out volType) && volType != VolumeType.DATADISK)

-                            {

-                                details = "Cannot create volumes of type " + (string.IsNullOrEmpty(diskType) ? "NULL" : diskType);

-                            }

-                            else

-                            {

-                                newVolName = cmd.diskCharacteristics.name;

-                                newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower());

-                                // TODO: make volume format and block size configurable

-                                wmiCallsV2.CreateDynamicVirtualHardDisk(disksize, newVolPath);

-                                if (File.Exists(newVolPath))

-                                {

-                                    result = true;

-                                }

-                                else

-                                {

-                                    details = "Failed to create DATADISK with name " + newVolName;

-                                }

-                            }

-                        }

-                        else

-                        {

-                            // TODO:  Does this always work, or do I need to download template at times?

-                            if (templateUri.Contains("/") || templateUri.Contains("\\"))

-                            {

-                                details = "Problem with templateURL " + templateUri +

-                                                " the URL should be volume UUID in primary storage created by previous PrimaryStorageDownloadCommand";

-                                logger.Error(details);

-                            }

-                            else

-                            {

-                                logger.Debug("Template's name in primary store should be " + templateUri);

-                                //            HypervPhysicalDisk BaseVol = primaryPool.getPhysicalDisk(tmplturl);

-                                FileInfo srcFileInfo = new FileInfo(templateUri);

-                                newVolName = Guid.NewGuid() + srcFileInfo.Extension;

-                                newVolPath = Path.Combine(poolLocalPath, newVolName);

-                                logger.Debug("New volume will be at " + newVolPath);

-                                string oldVolPath = Path.Combine(poolLocalPath, templateUri);

-                                File.Copy(oldVolPath, newVolPath);

-                                if (File.Exists(newVolPath))

-                                {

-                                    result = true;

-                                }

-                                else

-                                {

-                                    details = "Failed to create DATADISK with name " + newVolName;

-                                }

-                            }

-                            volume = new VolumeInfo(

-                                      volId, diskType,

-                                    poolTypeStr, poolUuid, newVolName,

-                                    newVolPath, newVolPath, (long)disksize, null);

-                        }

-                    }

-                }

-                catch (Exception sysEx)

-                {

-                    // TODO: consider this as model for error processing in all commands

-                    details = CloudStackTypes.CreateCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    volume = volume,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateAnswer);

-            }

-        }

-

-        // POST api/HypervResource/PrimaryStorageDownloadCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.PrimaryStorageDownloadCommand)]

-        public JContainer PrimaryStorageDownloadCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.PrimaryStorageDownloadCommand + Utils.CleanString(cmd.ToString()));

-                string details = null;

-                bool result = false;

-                long size = 0;

-                string newCopyFileName = null;

-

-                string poolLocalPath = cmd.localPath;

-                string poolUuid = cmd.poolUuid;

-                if (!Directory.Exists(poolLocalPath))

-                {

-                    details = "None existent local path " + poolLocalPath;

-                }

-                else

-                {

-                    // Compose name for downloaded file.

-                    string sourceUrl = cmd.url;

-                    if (sourceUrl.ToLower().EndsWith(".vhd"))

-                    {

-                        newCopyFileName = Guid.NewGuid() + ".vhd";

-                    }

-                    if (sourceUrl.ToLower().EndsWith(".vhdx"))

-                    {

-                        newCopyFileName = Guid.NewGuid() + ".vhdx";

-                    }

-

-                    // assert

-                    if (newCopyFileName == null)

-                    {

-                        details = CloudStackTypes.PrimaryStorageDownloadCommand + " Invalid file extension for hypervisor type in source URL " + sourceUrl;

-                        logger.Error(details);

-                    }

-                    else

-                    {

-                        try

-                        {

-                            FileInfo newFile;

-                            if (CopyURI(sourceUrl, newCopyFileName, poolLocalPath, out newFile, ref details))

-                            {

-                                size = newFile.Length;

-                                result = true;

-                            }

-                        }

-                        catch (System.Exception ex)

-                        {

-                            details = CloudStackTypes.PrimaryStorageDownloadCommand + " Cannot download source URL " + sourceUrl + " due to " + ex.Message;

-                            logger.Error(details, ex);

-                        }

-                    }

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    templateSize = size,

-                    installPath = newCopyFileName,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrimaryStorageDownloadAnswer);

-            }

-        }

-

-        private static bool ValidStoragePool(string poolTypeStr, string poolLocalPath, string poolUuid, ref string details)

-        {

-            StoragePoolType poolType;

-            if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem)

-            {

-                details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid StoragePoolType";

-                logger.Error(details);

-                return false;

-            }

-            else if (!Directory.Exists(poolLocalPath))

-            {

-                details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid local path";

-                logger.Error(details);

-                return false;

-            }

-            return true;

-        }

-

-        /// <summary>

-        /// Exceptions to watch out for:

-        /// Exceptions related to URI creation

-        /// System.SystemException

-        /// +-System.ArgumentNullException

-        /// +-System.FormatException

-        ///   +-System.UriFormatException

-        ///

-        /// Exceptions related to NFS URIs

-        /// System.SystemException

-        /// +-System.NotSupportedException

-        /// +-System.ArgumentException

-        /// +-System.ArgumentNullException

-        ///   +-System.Security.SecurityException;

-        /// +-System.UnauthorizedAccessException

-        /// +-System.IO.IOException

-        ///   +-System.IO.PathTooLongException

-        ///   

-        /// Exceptions related to HTTP URIs

-        /// System.SystemException

-        /// +-System.InvalidOperationException

-        ///    +-System.Net.WebException

-        /// +-System.NotSupportedException

-        /// +-System.ArgumentNullException

-        /// </summary>

-        /// <param name="sourceUri"></param>

-        /// <param name="newCopyFileName"></param>

-        /// <param name="poolLocalPath"></param>

-        /// <returns></returns>

-        private bool CopyURI(string sourceUri, string newCopyFileName, string poolLocalPath, out FileInfo newFile, ref string details)

-        {

-            Uri source = new Uri(sourceUri);

-            String destFilePath = Path.Combine(poolLocalPath, newCopyFileName);

-            string[] pathSegments = source.Segments;

-            String templateUUIDandExtension = pathSegments[pathSegments.Length - 1];

-            newFile = new FileInfo(destFilePath);

-

-            // NFS URI assumed to already be mounted locally.  Mount location given by settings.

-            if (source.Scheme.ToLower().Equals("nfs"))

-            {

-                String srcDiskPath = Path.Combine(HypervResourceController.config.LocalSecondaryStoragePath, templateUUIDandExtension);

-                String taskMsg = "Copy NFS url in " + sourceUri + " at " + srcDiskPath + " to pool " + poolLocalPath;

-                logger.Debug(taskMsg);

-                File.Copy(srcDiskPath, destFilePath);

-            }

-            else if (source.Scheme.ToLower().Equals("http") || source.Scheme.ToLower().Equals("https"))

-            {

-                System.Net.WebClient webclient = new WebClient();

-                webclient.DownloadFile(source, destFilePath);

-            }

-            else

-            {

-                details = "Unsupported URI scheme " + source.Scheme.ToLower() + " in source URI " + sourceUri;

-                logger.Error(details);

-                return false;

-            }

-

-            if (!File.Exists(destFilePath))

-            {

-                details = "Filed to copy " + sourceUri + " to primary pool destination " + destFilePath;

-                logger.Error(details);

-                return false;

-            }

-            return true;

-        }

-

-        // POST api/HypervResource/CheckHealthCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CheckHealthCommand)]

-        public JContainer CheckHealthCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                    VolumeObjectTO destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.data);
+
+                    if (destVolumeObjectTO.name == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+
+                    String path = destVolumeObjectTO.FullFileName;
+                    if (!File.Exists(path))
+                    {
+                        logger.Info(CloudStackTypes.DestroyCommand + ", but volume at pass already deleted " + path);
+                    }
+
+                    string vmName = (string)cmd.vmName;
+                    if (!string.IsNullOrEmpty(vmName) && File.Exists(path))
+                    {
+                        // Make sure that this resource is removed from the VM
+                        wmiCallsV2.DetachDisk(vmName, path);
+                    }
+
+                    File.Delete(path);
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.DestroyCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
+        
+        private static JArray ReturnCloudStackTypedJArray(object ansContent, string ansType)
+        {
+            JObject ansObj = Utils.CreateCloudStackObject(ansType, ansContent);
+            JArray answer = new JArray(ansObj);
+            logger.Info(Utils.CleanString(ansObj.ToString()));
+            return answer;
+        }
+
+        // POST api/HypervResource/CreateCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CreateCommand)]
+        public JContainer CreateCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.CreateCommand + Utils.CleanString(cmd.ToString()));
+
+                string details = null;
+                bool result = false;
+                VolumeInfo volume = new VolumeInfo();
+
+                try
+                {
+                    string diskType = cmd.diskCharacteristics.type;
+                    ulong disksize = cmd.diskCharacteristics.size;
+                    string templateUri = cmd.templateUrl;
+
+                    // assert: valid storagepool?
+                    string poolTypeStr = cmd.pool.type;
+                    string poolLocalPath = cmd.pool.path;
+                    string poolUuid = cmd.pool.uuid;
+                    string newVolPath = null;
+                    long volId = cmd.volId;
+                    string newVolName = null;
+
+                    if (ValidStoragePool(poolTypeStr, poolLocalPath, poolUuid, ref details))
+                    {
+                        // No template URI?  Its a blank disk.
+                        if (string.IsNullOrEmpty(templateUri))
+                        {
+                            // assert
+                            VolumeType volType;
+                            if (!Enum.TryParse<VolumeType>(diskType, out volType) && volType != VolumeType.DATADISK)
+                            {
+                                details = "Cannot create volumes of type " + (string.IsNullOrEmpty(diskType) ? "NULL" : diskType);
+                            }
+                            else
+                            {
+                                newVolName = cmd.diskCharacteristics.name;
+                                newVolPath = Path.Combine(poolLocalPath, newVolName, diskType.ToLower());
+                                // TODO: make volume format and block size configurable
+                                wmiCallsV2.CreateDynamicVirtualHardDisk(disksize, newVolPath);
+                                if (File.Exists(newVolPath))
+                                {
+                                    result = true;
+                                }
+                                else
+                                {
+                                    details = "Failed to create DATADISK with name " + newVolName;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            // TODO:  Does this always work, or do I need to download template at times?
+                            if (templateUri.Contains("/") || templateUri.Contains("\\"))
+                            {
+                                details = "Problem with templateURL " + templateUri +
+                                                " the URL should be volume UUID in primary storage created by previous PrimaryStorageDownloadCommand";
+                                logger.Error(details);
+                            }
+                            else
+                            {
+                                logger.Debug("Template's name in primary store should be " + templateUri);
+                                //            HypervPhysicalDisk BaseVol = primaryPool.getPhysicalDisk(tmplturl);
+                                FileInfo srcFileInfo = new FileInfo(templateUri);
+                                newVolName = Guid.NewGuid() + srcFileInfo.Extension;
+                                newVolPath = Path.Combine(poolLocalPath, newVolName);
+                                logger.Debug("New volume will be at " + newVolPath);
+                                string oldVolPath = Path.Combine(poolLocalPath, templateUri);
+                                File.Copy(oldVolPath, newVolPath);
+                                if (File.Exists(newVolPath))
+                                {
+                                    result = true;
+                                }
+                                else
+                                {
+                                    details = "Failed to create DATADISK with name " + newVolName;
+                                }
+                            }
+                            volume = new VolumeInfo(
+                                      volId, diskType,
+                                    poolTypeStr, poolUuid, newVolName,
+                                    newVolPath, newVolPath, (long)disksize, null);
+                        }
+                    }
+                }
+                catch (Exception sysEx)
+                {
+                    // TODO: consider this as model for error processing in all commands
+                    details = CloudStackTypes.CreateCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    volume = volume,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateAnswer);
+            }
+        }
+
+        // POST api/HypervResource/PrimaryStorageDownloadCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.PrimaryStorageDownloadCommand)]
+        public JContainer PrimaryStorageDownloadCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.PrimaryStorageDownloadCommand + Utils.CleanString(cmd.ToString()));
+                string details = null;
+                bool result = false;
+                long size = 0;
+                string newCopyFileName = null;
+
+                string poolLocalPath = cmd.localPath;
+                string poolUuid = cmd.poolUuid;
+                if (!Directory.Exists(poolLocalPath))
+                {
+                    details = "None existent local path " + poolLocalPath;
+                }
+                else
+                {
+                    // Compose name for downloaded file.
+                    string sourceUrl = cmd.url;
+                    if (sourceUrl.ToLower().EndsWith(".vhd"))
+                    {
+                        newCopyFileName = Guid.NewGuid() + ".vhd";
+                    }
+                    if (sourceUrl.ToLower().EndsWith(".vhdx"))
+                    {
+                        newCopyFileName = Guid.NewGuid() + ".vhdx";
+                    }
+
+                    // assert
+                    if (newCopyFileName == null)
+                    {
+                        details = CloudStackTypes.PrimaryStorageDownloadCommand + " Invalid file extension for hypervisor type in source URL " + sourceUrl;
+                        logger.Error(details);
+                    }
+                    else
+                    {
+                        try
+                        {
+                            FileInfo newFile;
+                            if (CopyURI(sourceUrl, newCopyFileName, poolLocalPath, out newFile, ref details))
+                            {
+                                size = newFile.Length;
+                                result = true;
+                            }
+                        }
+                        catch (System.Exception ex)
+                        {
+                            details = CloudStackTypes.PrimaryStorageDownloadCommand + " Cannot download source URL " + sourceUrl + " due to " + ex.Message;
+                            logger.Error(details, ex);
+                        }
+                    }
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    templateSize = size,
+                    installPath = newCopyFileName,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrimaryStorageDownloadAnswer);
+            }
+        }
+
+        private static bool ValidStoragePool(string poolTypeStr, string poolLocalPath, string poolUuid, ref string details)
+        {
+            StoragePoolType poolType;
+            if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType) || poolType != StoragePoolType.Filesystem)
+            {
+                details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid StoragePoolType";
+                logger.Error(details);
+                return false;
+            }
+            else if (!Directory.Exists(poolLocalPath))
+            {
+                details = "Primary storage pool " + poolUuid + " type " + poolType + " local path " + poolLocalPath + " has invalid local path";
+                logger.Error(details);
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Exceptions to watch out for:
+        /// Exceptions related to URI creation
+        /// System.SystemException
+        /// +-System.ArgumentNullException
+        /// +-System.FormatException
+        ///   +-System.UriFormatException
+        ///
+        /// Exceptions related to NFS URIs
+        /// System.SystemException
+        /// +-System.NotSupportedException
+        /// +-System.ArgumentException
+        /// +-System.ArgumentNullException
+        ///   +-System.Security.SecurityException;
+        /// +-System.UnauthorizedAccessException
+        /// +-System.IO.IOException
+        ///   +-System.IO.PathTooLongException
+        ///   
+        /// Exceptions related to HTTP URIs
+        /// System.SystemException
+        /// +-System.InvalidOperationException
+        ///    +-System.Net.WebException
+        /// +-System.NotSupportedException
+        /// +-System.ArgumentNullException
+        /// </summary>
+        /// <param name="sourceUri"></param>
+        /// <param name="newCopyFileName"></param>
+        /// <param name="poolLocalPath"></param>
+        /// <returns></returns>
+        private bool CopyURI(string sourceUri, string newCopyFileName, string poolLocalPath, out FileInfo newFile, ref string details)
+        {
+            Uri source = new Uri(sourceUri);
+            String destFilePath = Path.Combine(poolLocalPath, newCopyFileName);
+            string[] pathSegments = source.Segments;
+            String templateUUIDandExtension = pathSegments[pathSegments.Length - 1];
+            newFile = new FileInfo(destFilePath);
+
+            // NFS URI assumed to already be mounted locally.  Mount location given by settings.
+            if (source.Scheme.ToLower().Equals("nfs"))
+            {
+                String srcDiskPath = Path.Combine(HypervResourceController.config.LocalSecondaryStoragePath, templateUUIDandExtension);
+                String taskMsg = "Copy NFS url in " + sourceUri + " at " + srcDiskPath + " to pool " + poolLocalPath;
+                logger.Debug(taskMsg);
+                File.Copy(srcDiskPath, destFilePath);
+            }
+            else if (source.Scheme.ToLower().Equals("http") || source.Scheme.ToLower().Equals("https"))
+            {
+                System.Net.WebClient webclient = new WebClient();
+                webclient.DownloadFile(source, destFilePath);
+            }
+            else
+            {
+                details = "Unsupported URI scheme " + source.Scheme.ToLower() + " in source URI " + sourceUri;
+                logger.Error(details);
+                return false;
+            }
+
+            if (!File.Exists(destFilePath))
+            {
+                details = "Filed to copy " + sourceUri + " to primary pool destination " + destFilePath;
+                logger.Error(details);
+                return false;
+            }
+            return true;
+        }
+
+        // POST api/HypervResource/CheckHealthCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CheckHealthCommand)]
+        public JContainer CheckHealthCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.CheckHealthCommand + Utils.CleanString(cmd.ToString()));
-                object ansContent = new

-                {

-                    result = true,

-                    details = "resource is alive",

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckHealthAnswer);

-            }

-        }

-

-        // POST api/HypervResource/CheckOnHostCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CheckOnHostCommand)]

-        public JContainer CheckOnHostCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                object ansContent = new
+                {
+                    result = true,
+                    details = "resource is alive",
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckHealthAnswer);
+            }
+        }
+
+        // POST api/HypervResource/CheckOnHostCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CheckOnHostCommand)]
+        public JContainer CheckOnHostCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.CheckOnHostCommand + Utils.CleanString(cmd.ToString()));
                 string details = "host is not alive";
                 bool result = true;
@@ -809,16 +809,16 @@
                     logger.Error("Error Occurred in " + CloudStackTypes.CheckOnHostCommand + " : " + e.Message);
                 }
 
-                object ansContent = new

-                {

+                object ansContent = new
+                {
                     result = result,
                     details = details,
-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer);

-            }

-        }

-

+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckOnHostAnswer);
+            }
+        }
+
         private bool IsHostAlive(string poolPath, string privateIp)
         {
             bool hostAlive = false;
@@ -851,177 +851,177 @@
             return hostAlive;
         }
 
-        // POST api/HypervResource/CheckSshCommand

-        // TODO: create test

-        [HttpPost]

-        [ActionName(CloudStackTypes.CheckSshCommand)]

-        public JContainer CheckSshCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+        // POST api/HypervResource/CheckSshCommand
+        // TODO: create test
+        [HttpPost]
+        [ActionName(CloudStackTypes.CheckSshCommand)]
+        public JContainer CheckSshCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.CheckSshCommand + Utils.CleanString(cmd.ToString()));
-                object ansContent = new

-                {

-                    result = true,

-                    details = "NOP, TODO: implement properly",

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckSshAnswer);

-            }

-        }

-

-        // POST api/HypervResource/CheckVirtualMachineCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CheckVirtualMachineCommand)]

-        public JContainer CheckVirtualMachineCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                object ansContent = new
+                {
+                    result = true,
+                    details = "NOP, TODO: implement properly",
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckSshAnswer);
+            }
+        }
+
+        // POST api/HypervResource/CheckVirtualMachineCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CheckVirtualMachineCommand)]
+        public JContainer CheckVirtualMachineCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.CheckVirtualMachineCommand + Utils.CleanString(cmd.ToString()));
-                string details = null;

-                bool result = false;

-                string vmName = cmd.vmName;

-                string state = null;

-

-                // TODO: Look up the VM, convert Hyper-V state to CloudStack version.

-                var sys = wmiCallsV2.GetComputerSystem(vmName);

-                if (sys == null)

-                {

-                    details = CloudStackTypes.CheckVirtualMachineCommand + " requested unknown VM " + vmName;

-                    logger.Error(details);

-                }

-                else

-                {

-                    state = EnabledState.ToCloudStackState(sys.EnabledState); // TODO: V2 changes?

-                    result = true;

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    state = state,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckVirtualMachineAnswer);

-            }

-        }

-

-        // POST api/HypervResource/DeleteStoragePoolCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.DeleteStoragePoolCommand)]

-        public JContainer DeleteStoragePoolCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                string details = null;
+                bool result = false;
+                string vmName = cmd.vmName;
+                string state = null;
+
+                // TODO: Look up the VM, convert Hyper-V state to CloudStack version.
+                var sys = wmiCallsV2.GetComputerSystem(vmName);
+                if (sys == null)
+                {
+                    details = CloudStackTypes.CheckVirtualMachineCommand + " requested unknown VM " + vmName;
+                    logger.Error(details);
+                }
+                else
+                {
+                    state = EnabledState.ToCloudStackState(sys.EnabledState); // TODO: V2 changes?
+                    result = true;
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    state = state,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckVirtualMachineAnswer);
+            }
+        }
+
+        // POST api/HypervResource/DeleteStoragePoolCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.DeleteStoragePoolCommand)]
+        public JContainer DeleteStoragePoolCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.DeleteStoragePoolCommand + Utils.CleanString(cmd.ToString()));
-                object ansContent = new

-                {

-                    result = true,

-                    details = "Current implementation does not delete local path corresponding to storage pool!",

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

-        /// <summary>

-        /// NOP - legacy command -

-        /// POST api/HypervResource/CreateStoragePoolCommand

-        /// </summary>

-        /// <param name="cmd"></param>

-        /// <returns></returns>

-        [HttpPost]

-        [ActionName(CloudStackTypes.CreateStoragePoolCommand)]

-        public JContainer CreateStoragePoolCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.CreateStoragePoolCommand + Utils.CleanString(cmd.ToString()));

-                object ansContent = new

-                {

-                    result = true,

-                    details = "success - NOP",

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

-        // POST api/HypervResource/ModifyStoragePoolCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.ModifyStoragePoolCommand)]

-        public JContainer ModifyStoragePoolCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.ModifyStoragePoolCommand + Utils.CleanString(cmd.ToString()));

-                string details = null;

-                string localPath;

-                StoragePoolType poolType;

-                object ansContent;

-

-                bool result = ValidateStoragePoolCommand(cmd, out localPath, out poolType, ref details);

-                if (!result)

-                {

-                    ansContent = new

-                    {

-                        result = result,

-                        details = details,

-                        contextMap = contextMap

-                    };

-                    return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-                }

-

-                var tInfo = new Dictionary<string, string>();

-                long capacityBytes = 0;

-                long availableBytes = 0;

-                string hostPath = null;

-                if (poolType == StoragePoolType.Filesystem)

-                {

-                    GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes);

-                    hostPath = localPath;

-                }

-                else if (poolType == StoragePoolType.NetworkFilesystem ||

-                    poolType == StoragePoolType.SMB)

-                {

-                    NFSTO share = new NFSTO();

-                    String uriStr = "cifs://" + (string)cmd.pool.host + (string)cmd.pool.path;

-                    share.uri = new Uri(uriStr);

-                    hostPath = Utils.NormalizePath(share.UncPath);

-

-                    // Check access to share.

-                    Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);

-                    Utils.GetShareDetails(share.UncPath, out capacityBytes, out availableBytes);

-                    config.setPrimaryStorage((string)cmd.pool.uuid, hostPath);

-                }

-                else

-                {

-                    result = false;

-                }

-

-                String uuid = null;

-                var poolInfo = new

-                {

-                    uuid = uuid,

-                    host = cmd.pool.host,

-                    hostPath = cmd.pool.path,

-                    localPath = hostPath,

-                    poolType = cmd.pool.type,

-                    capacityBytes = capacityBytes,

-                    availableBytes = availableBytes

-                };

-

-                ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    localPath = hostPath,

-                    templateInfo = tInfo,

-                    poolInfo = poolInfo,

-                    contextMap = contextMap

-                };

-

+                object ansContent = new
+                {
+                    result = true,
+                    details = "Current implementation does not delete local path corresponding to storage pool!",
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
+        /// <summary>
+        /// NOP - legacy command -
+        /// POST api/HypervResource/CreateStoragePoolCommand
+        /// </summary>
+        /// <param name="cmd"></param>
+        /// <returns></returns>
+        [HttpPost]
+        [ActionName(CloudStackTypes.CreateStoragePoolCommand)]
+        public JContainer CreateStoragePoolCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.CreateStoragePoolCommand + Utils.CleanString(cmd.ToString()));
+                object ansContent = new
+                {
+                    result = true,
+                    details = "success - NOP",
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
+        // POST api/HypervResource/ModifyStoragePoolCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.ModifyStoragePoolCommand)]
+        public JContainer ModifyStoragePoolCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.ModifyStoragePoolCommand + Utils.CleanString(cmd.ToString()));
+                string details = null;
+                string localPath;
+                StoragePoolType poolType;
+                object ansContent;
+
+                bool result = ValidateStoragePoolCommand(cmd, out localPath, out poolType, ref details);
+                if (!result)
+                {
+                    ansContent = new
+                    {
+                        result = result,
+                        details = details,
+                        contextMap = contextMap
+                    };
+                    return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+                }
+
+                var tInfo = new Dictionary<string, string>();
+                long capacityBytes = 0;
+                long availableBytes = 0;
+                string hostPath = null;
+                if (poolType == StoragePoolType.Filesystem)
+                {
+                    GetCapacityForLocalPath(localPath, out capacityBytes, out availableBytes);
+                    hostPath = localPath;
+                }
+                else if (poolType == StoragePoolType.NetworkFilesystem ||
+                    poolType == StoragePoolType.SMB)
+                {
+                    NFSTO share = new NFSTO();
+                    String uriStr = "cifs://" + (string)cmd.pool.host + (string)cmd.pool.path;
+                    share.uri = new Uri(uriStr);
+                    hostPath = Utils.NormalizePath(share.UncPath);
+
+                    // Check access to share.
+                    Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);
+                    Utils.GetShareDetails(share.UncPath, out capacityBytes, out availableBytes);
+                    config.setPrimaryStorage((string)cmd.pool.uuid, hostPath);
+                }
+                else
+                {
+                    result = false;
+                }
+
+                String uuid = null;
+                var poolInfo = new
+                {
+                    uuid = uuid,
+                    host = cmd.pool.host,
+                    hostPath = cmd.pool.path,
+                    localPath = hostPath,
+                    poolType = cmd.pool.type,
+                    capacityBytes = capacityBytes,
+                    availableBytes = availableBytes
+                };
+
+                ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    localPath = hostPath,
+                    templateInfo = tInfo,
+                    poolInfo = poolInfo,
+                    contextMap = contextMap
+                };
+
                 if (result)
                 {
                     try
@@ -1043,34 +1043,34 @@
                     }
                 }
 
-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer);

-            }

-        }

-

-        private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, out StoragePoolType poolType, ref string details)

-        {

-            dynamic pool = cmd.pool;

-            string poolTypeStr = pool.type;

-            localPath = cmd.localPath;

-            if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType))

-            {

-                details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd);

-                logger.Error(details);

-                return false;

-            }

-

-            if (poolType != StoragePoolType.Filesystem &&

-                poolType != StoragePoolType.NetworkFilesystem &&

-                poolType != StoragePoolType.SMB)

-            {

-                details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd);

-                logger.Error(details);

-                return false;

-            }

-

-            return true;

-        }

-

+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ModifyStoragePoolAnswer);
+            }
+        }
+
+        private bool ValidateStoragePoolCommand(dynamic cmd, out string localPath, out StoragePoolType poolType, ref string details)
+        {
+            dynamic pool = cmd.pool;
+            string poolTypeStr = pool.type;
+            localPath = cmd.localPath;
+            if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType))
+            {
+                details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd);
+                logger.Error(details);
+                return false;
+            }
+
+            if (poolType != StoragePoolType.Filesystem &&
+                poolType != StoragePoolType.NetworkFilesystem &&
+                poolType != StoragePoolType.SMB)
+            {
+                details = "Request to create / modify unsupported pool type: " + (poolTypeStr == null ? "NULL" : poolTypeStr) + "in cmd " + JsonConvert.SerializeObject(cmd);
+                logger.Error(details);
+                return false;
+            }
+
+            return true;
+        }
+
         // POST api/HypervResource/PlugNicCommand
         [HttpPost]
         [ActionName(CloudStackTypes.PlugNicCommand)]
@@ -1079,312 +1079,311 @@
             using (log4net.NDC.Push(Guid.NewGuid().ToString()))
             {
                 logger.Info(CloudStackTypes.PlugNicCommand + Utils.CleanString(cmd.ToString()));
-
                 object ansContent = new
                 {
                     result = true,
-                    details = "instead of plug, change he network settings",
+                    details = "Hot Nic plug not supported, change any empty virtual network adapter network settings",
                     contextMap = contextMap
                 };
                 return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PlugNicAnswer);
             }
         }
 
-

-        // POST api/HypervResource/CleanupNetworkRulesCmd

-        [HttpPost]

-        [ActionName(CloudStackTypes.CleanupNetworkRulesCmd)]

-        public JContainer CleanupNetworkRulesCmd([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+        // POST api/HypervResource/CleanupNetworkRulesCmd
+        [HttpPost]
+        [ActionName(CloudStackTypes.CleanupNetworkRulesCmd)]
+        public JContainer CleanupNetworkRulesCmd([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.CleanupNetworkRulesCmd + Utils.CleanString(cmd.ToString()));
-                object ansContent = new

-                 {

-                     result = false,

-                     details = "nothing to cleanup in our current implementation",

-                     contextMap = contextMap

-                 };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

-        // POST api/HypervResource/CheckNetworkCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CheckNetworkCommand)]

-        public JContainer CheckNetworkCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                object ansContent = new
+                 {
+                     result = false,
+                     details = "nothing to cleanup in our current implementation",
+                     contextMap = contextMap
+                 };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
+        // POST api/HypervResource/CheckNetworkCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CheckNetworkCommand)]
+        public JContainer CheckNetworkCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.CheckNetworkCommand + Utils.CleanString(cmd.ToString()));
-                object ansContent = new

-                {

-                    result = true,

-                    details = (string)null,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckNetworkAnswer);

-            }

-        }

-

-        // POST api/HypervResource/ReadyCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.ReadyCommand)]

-        public JContainer ReadyCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                object ansContent = new
+                {
+                    result = true,
+                    details = (string)null,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CheckNetworkAnswer);
+            }
+        }
+
+        // POST api/HypervResource/ReadyCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.ReadyCommand)]
+        public JContainer ReadyCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.ReadyCommand + Utils.CleanString(cmd.ToString()));
-                object ansContent = new

-                {

-                    result = true,

-                    details = (string)null,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ReadyAnswer);

-            }

-

-        }

-

-        // POST api/HypervResource/StartCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.StartCommand)]

-        public JContainer StartCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.StartCommand + Utils.CleanString(cmd.ToString()));

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    string systemVmIsoPath = systemVmIso;

-                    lock (systemVmIso)

-                    {

-                        systemVmIsoPath = systemVmIso;

-                        String uriStr = (String)cmd.secondaryStorage;

-                        if (!String.IsNullOrEmpty(uriStr))

-                        {

-                            if (String.IsNullOrEmpty(systemVmIsoPath) || !File.Exists(systemVmIsoPath))

-                            {

-                                NFSTO share = new NFSTO();

-                                share.uri = new Uri(uriStr);

-                                string defaultDataPath = wmiCallsV2.GetDefaultDataRoot();

-

-                                string secondaryPath = Utils.NormalizePath(Path.Combine(share.UncPath, "systemvm"));

-                                string[] choices = choices = Directory.GetFiles(secondaryPath, "systemvm*.iso");

-                                if (choices.Length != 1)

-                                {

-                                    String errMsg = "Couldn't locate the systemvm iso on " + secondaryPath;

-                                    logger.Debug(errMsg);

-                                }

-                                else

-                                {

-                                    systemVmIsoPath = Utils.NormalizePath(Path.Combine(defaultDataPath, Path.GetFileName(choices[0])));

-                                    if (!File.Exists(systemVmIsoPath))

-                                    {

-                                        Utils.DownloadCifsFileToLocalFile(choices[0], share, systemVmIsoPath);

-                                    }

-                                    systemVmIso = systemVmIsoPath;

-                                }

-                            }

-                        }

-                    }

-

-                    wmiCallsV2.DeployVirtualMachine(cmd, systemVmIsoPath);

-                    result = true;

-                }

-                catch (Exception wmiEx)

-                {

-                    details = CloudStackTypes.StartCommand + " fail on exception" + wmiEx.Message;

-                    logger.Error(details, wmiEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    vm = cmd.vm,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StartAnswer);

-            }

-        }

-

-        // POST api/HypervResource/StopCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.StopCommand)]

-        public JContainer StopCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                object ansContent = new
+                {
+                    result = true,
+                    details = (string)null,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.ReadyAnswer);
+            }
+
+        }
+
+        // POST api/HypervResource/StartCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.StartCommand)]
+        public JContainer StartCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.StartCommand + Utils.CleanString(cmd.ToString()));
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string systemVmIsoPath = systemVmIso;
+                    lock (systemVmIso)
+                    {
+                        systemVmIsoPath = systemVmIso;
+                        String uriStr = (String)cmd.secondaryStorage;
+                        if (!String.IsNullOrEmpty(uriStr))
+                        {
+                            if (String.IsNullOrEmpty(systemVmIsoPath) || !File.Exists(systemVmIsoPath))
+                            {
+                                NFSTO share = new NFSTO();
+                                share.uri = new Uri(uriStr);
+                                string defaultDataPath = wmiCallsV2.GetDefaultDataRoot();
+
+                                string secondaryPath = Utils.NormalizePath(Path.Combine(share.UncPath, "systemvm"));
+                                string[] choices = choices = Directory.GetFiles(secondaryPath, "systemvm*.iso");
+                                if (choices.Length != 1)
+                                {
+                                    String errMsg = "Couldn't locate the systemvm iso on " + secondaryPath;
+                                    logger.Debug(errMsg);
+                                }
+                                else
+                                {
+                                    systemVmIsoPath = Utils.NormalizePath(Path.Combine(defaultDataPath, Path.GetFileName(choices[0])));
+                                    if (!File.Exists(systemVmIsoPath))
+                                    {
+                                        Utils.DownloadCifsFileToLocalFile(choices[0], share, systemVmIsoPath);
+                                    }
+                                    systemVmIso = systemVmIsoPath;
+                                }
+                            }
+                        }
+                    }
+
+                    wmiCallsV2.DeployVirtualMachine(cmd, systemVmIsoPath);
+                    result = true;
+                }
+                catch (Exception wmiEx)
+                {
+                    details = CloudStackTypes.StartCommand + " fail on exception" + wmiEx.Message;
+                    logger.Error(details, wmiEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    vm = cmd.vm,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StartAnswer);
+            }
+        }
+
+        // POST api/HypervResource/StopCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.StopCommand)]
+        public JContainer StopCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.StopCommand + Utils.CleanString(cmd.ToString()));
-                string details = null;

-                bool result = false;

-                bool checkBeforeCleanup = cmd.checkBeforeCleanup;

-                String vmName = cmd.vmName;

-

-                if (checkBeforeCleanup == true)

-                {

-                    ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName);

-                    if (vm == null || vm.EnabledState == 2)

-                    {

-                        // VM is not available or vm in running state

-                        return ReturnCloudStackTypedJArray(new { result = false, details = "VM is running on host, bailing out", vm = vmName, contextMap = contextMap }, CloudStackTypes.StopAnswer);

-                    }

-                }

-                try

-                {

-                    wmiCallsV2.DestroyVm(cmd);

-                    result = true;

-                }

-                catch (Exception wmiEx)

-                {

-                    details = CloudStackTypes.StopCommand + " fail on exception" + wmiEx.Message;

-                    logger.Error(details, wmiEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    vm = cmd.vm,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StopAnswer);

-            }

-        }

-

-        // POST api/HypervResource/CreateObjectCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CreateObjectCommand)]

-        public JContainer CreateObjectCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.CreateObjectCommand + Utils.CleanString(cmd.ToString()));

-

-                bool result = false;

-                string details = null;

+                string details = null;
+                bool result = false;
+                bool checkBeforeCleanup = cmd.checkBeforeCleanup;
+                String vmName = cmd.vmName;
+
+                if (checkBeforeCleanup == true)
+                {
+                    ComputerSystem vm = wmiCallsV2.GetComputerSystem(vmName);
+                    if (vm == null || vm.EnabledState == 2)
+                    {
+                        // VM is not available or vm in running state
+                        return ReturnCloudStackTypedJArray(new { result = false, details = "VM is running on host, bailing out", vm = vmName, contextMap = contextMap }, CloudStackTypes.StopAnswer);
+                    }
+                }
+                try
+                {
+                    wmiCallsV2.DestroyVm(cmd);
+                    result = true;
+                }
+                catch (Exception wmiEx)
+                {
+                    details = CloudStackTypes.StopCommand + " fail on exception" + wmiEx.Message;
+                    logger.Error(details, wmiEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    vm = cmd.vm,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.StopAnswer);
+            }
+        }
+
+        // POST api/HypervResource/CreateObjectCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CreateObjectCommand)]
+        public JContainer CreateObjectCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.CreateObjectCommand + Utils.CleanString(cmd.ToString()));
+
+                bool result = false;
+                string details = null;
                 object newData = null;
-                try

-                {

-                    VolumeObjectTO volume = VolumeObjectTO.ParseJson(cmd.data);

-                    PrimaryDataStoreTO primary = volume.primaryDataStore;

-                    ulong volumeSize = volume.size;

+                try
+                {
+                    VolumeObjectTO volume = VolumeObjectTO.ParseJson(cmd.data);
+                    PrimaryDataStoreTO primary = volume.primaryDataStore;
+                    ulong volumeSize = volume.size;
                     string volumeName = volume.uuid + ".vhdx";
-                    string volumePath = null;

-

-                    if (primary.isLocal)

-                    {

-                        volumePath = Path.Combine(primary.Path, volumeName);

-                    }

-                    else

-                    {

-                        volumePath = @"\\" + primary.uri.Host + primary.uri.LocalPath + @"\" + volumeName;

-                        volumePath = Utils.NormalizePath(volumePath);

-                        Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);

-                    }

+                    string volumePath = null;
+
+                    if (primary.isLocal)
+                    {
+                        volumePath = Path.Combine(primary.Path, volumeName);
+                    }
+                    else
+                    {
+                        volumePath = @"\\" + primary.uri.Host + primary.uri.LocalPath + @"\" + volumeName;
+                        volumePath = Utils.NormalizePath(volumePath);
+                        Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);
+                    }
                     volume.path = volume.uuid;
-                    wmiCallsV2.CreateDynamicVirtualHardDisk(volumeSize, volumePath);

-                    if (File.Exists(volumePath))

-                    {

-                        result = true;

+                    wmiCallsV2.CreateDynamicVirtualHardDisk(volumeSize, volumePath);
+                    if (File.Exists(volumePath))
+                    {
+                        result = true;
                         JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, volume);
                         newData = ansObj;
-                    }

-                    else

-                    {

-                        details = "Failed to create disk with name " + volumePath;

-                    }

-                }

-                catch (Exception ex)

-                {

-                    // Test by providing wrong key

-                    details = CloudStackTypes.CreateObjectCommand + " failed on exception, " + ex.Message;

-                    logger.Error(details, ex);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

+                    }
+                    else
+                    {
+                        details = "Failed to create disk with name " + volumePath;
+                    }
+                }
+                catch (Exception ex)
+                {
+                    // Test by providing wrong key
+                    details = CloudStackTypes.CreateObjectCommand + " failed on exception, " + ex.Message;
+                    logger.Error(details, ex);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
                     data = newData,
-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateObjectAnswer);

-            }

-        }

-

-        // POST api/HypervResource/MaintainCommand

-        // TODO: should this be a NOP?

-        [HttpPost]

-        [ActionName(CloudStackTypes.MaintainCommand)]

-        public JContainer MaintainCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CreateObjectAnswer);
+            }
+        }
+
+        // POST api/HypervResource/MaintainCommand
+        // TODO: should this be a NOP?
+        [HttpPost]
+        [ActionName(CloudStackTypes.MaintainCommand)]
+        public JContainer MaintainCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.MaintainCommand + Utils.CleanString(cmd.ToString()));
-

-                object ansContent = new

-                {

-                    result = true,

-                    willMigrate = true,

-                    details = "success - NOP for MaintainCommand",

-                    _reconnect = false,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MaintainAnswer);

-            }

-        }

-

-        // POST api/HypervResource/PingRoutingCommand

-        // TODO: should this be a NOP?

-        [HttpPost]

-        [ActionName(CloudStackTypes.PingRoutingCommand)]

-        public JContainer PingRoutingCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                object ansContent = new
+                {
+                    result = true,
+                    willMigrate = true,
+                    details = "success - NOP for MaintainCommand",
+                    _reconnect = false,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MaintainAnswer);
+            }
+        }
+
+        // POST api/HypervResource/PingRoutingCommand
+        // TODO: should this be a NOP?
+        [HttpPost]
+        [ActionName(CloudStackTypes.PingRoutingCommand)]
+        public JContainer PingRoutingCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.PingRoutingCommand + Utils.CleanString(cmd.ToString()));
-

-                object ansContent = new

-                {

-                    result = true,

-                    details = "success - NOP for PingRoutingCommand",

-                    _reconnect = false,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

-        // POST api/HypervResource/PingCommand

-        // TODO: should this be a NOP?

-        [HttpPost]

-        [ActionName(CloudStackTypes.PingCommand)]

-        public JContainer PingCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                object ansContent = new
+                {
+                    result = true,
+                    details = "success - NOP for PingRoutingCommand",
+                    _reconnect = false,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
+        // POST api/HypervResource/PingCommand
+        // TODO: should this be a NOP?
+        [HttpPost]
+        [ActionName(CloudStackTypes.PingCommand)]
+        public JContainer PingCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.PingCommand + Utils.CleanString(cmd.ToString()));
-

-                object ansContent = new

-                {

-                    result = true,

-                    details = "success - NOP for PingCommand",

-                    _reconnect = false,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);

-            }

-        }

-

+
+                object ansContent = new
+                {
+                    result = true,
+                    details = "success - NOP for PingCommand",
+                    _reconnect = false,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.Answer);
+            }
+        }
+
         // POST api/HypervResource/ModifyVmVnicVlanCommand
         [HttpPost]
         [ActionName(CloudStackTypes.ModifyVmNicConfigCommand)]
@@ -1396,18 +1395,21 @@
                 logger.Info(CloudStackTypes.ModifyVmNicConfigCommand + Utils.CleanString(cmd.ToString()));
                 bool result = false;
                 String vmName = cmd.vmName;
-                uint vlan = (uint)cmd.vlan;
+                String vlan = cmd.vlan;
                 string macAddress = cmd.macAddress;
                 uint pos = cmd.index;
+                bool enable = cmd.enable;
+                string switchLableName = cmd.switchLableName;
                 if (macAddress != null)
                 {
                     wmiCallsV2.ModifyVmVLan(vmName, vlan, macAddress);
-                }
-                else if (pos > 1)
-                {
-                    wmiCallsV2.ModifyVmVLan(vmName, vlan, pos);
-                }
                     result = true;
+                }
+                else if (pos >= 1)
+                {
+                    wmiCallsV2.ModifyVmVLan(vmName, vlan, pos, enable, switchLableName);
+                    result = true;
+                }
 
                 object ansContent = new
                 {
@@ -1434,16 +1436,12 @@
                 List<NicDetails> nicDetails = new List<NicDetails>();
                 var nicSettingsViaVm = wmiCallsV2.GetEthernetPortSettings(vm);
                 NicDetails nic = null;
-                String[] macAddress = new String[nicSettingsViaVm.Length];
                 int index = 0;
-                foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
-                {
-                    macAddress[index++] = item.Address;
-                }
-
-                index = 0;
-                var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm);
+                int[] nicStates = new int[8];
+                int[] nicVlan = new int[8];
                 int vlanid = 1;
+
+                var ethernetConnections = wmiCallsV2.GetEthernetConnections(vm);
                 foreach (EthernetPortAllocationSettingData item in ethernetConnections)
                 {
                     EthernetSwitchPortVlanSettingData vlanSettings = wmiCallsV2.GetVlanSettings(item);
@@ -1455,10 +1453,20 @@
                     {
                         vlanid = vlanSettings.AccessVlanId;
                     }
-                    nic = new NicDetails(macAddress[index++], vlanid);
+                    nicStates[index] = (Int32)(item.EnabledState);
+                    nicVlan[index] = vlanid;
+                    index++;
+                }
+
+                index = 0;
+                foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
+                {
+                    nic = new NicDetails(item.Address, nicVlan[index], nicStates[index]);
+                    index++;
                     nicDetails.Add(nic);
                 }
 
+
                 result = true;
 
                 object ansContent = new
@@ -1474,912 +1482,912 @@
 
 
 
-        // POST api/HypervResource/GetVmStatsCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.GetVmStatsCommand)]

-        public JContainer GetVmStatsCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+        // POST api/HypervResource/GetVmStatsCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.GetVmStatsCommand)]
+        public JContainer GetVmStatsCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.GetVmStatsCommand + Utils.CleanString(cmd.ToString()));
-                bool result = false;

-                JArray vmNamesJson = cmd.vmNames;

-                string[] vmNames = vmNamesJson.ToObject<string[]>();

-                Dictionary<string, VmStatsEntry> vmProcessorInfo = new Dictionary<string, VmStatsEntry>(vmNames.Length);

-

-                var vmsToInspect = new List<System.Management.ManagementPath>();

-                foreach (var vmName in vmNames)

-                {

-                    var sys = wmiCallsV2.GetComputerSystem(vmName);

-                    if (sys == null)

-                    {

-                        logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames);

-                        continue;

-                    }

-                    var sysInfo = wmiCallsV2.GetVmSettings(sys);

-                    vmsToInspect.Add(sysInfo.Path);

-                }

-

-                wmiCallsV2.GetSummaryInfo(vmProcessorInfo, vmsToInspect);

-

-                // TODO: Network usage comes from Performance Counter API; however it is only available in kb/s, and not in total terms.

-                // Curious about these?  Use perfmon to inspect them, e.g. http://msdn.microsoft.com/en-us/library/xhcx5a20%28v=vs.100%29.aspx

-                // Recent post on these counter at http://blogs.technet.com/b/cedward/archive/2011/07/19/hyper-v-networking-optimizations-part-6-of-6-monitoring-hyper-v-network-consumption.aspx

-                result = true;

-

-                object ansContent = new

-                {

-                    vmStatsMap = vmProcessorInfo,

-                    result = result,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmStatsAnswer);

-            }

-        }

-

-        // POST api/HypervResource/CopyCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.CopyCommand)]

-        public JContainer CopyCommand(dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                // Log command *after* we've removed security details from the command.

-                logger.Info(CloudStackTypes.CopyCommand + Utils.CleanString(cmd.ToString()));

-

-                bool result = false;

-                string details = null;

-                object newData = null;

-                TemplateObjectTO destTemplateObjectTO = null;

-                VolumeObjectTO destVolumeObjectTO = null;

-                VolumeObjectTO srcVolumeObjectTO = null;

-                TemplateObjectTO srcTemplateObjectTO = null;

-

-                try

-                {

-                    dynamic timeout = cmd.wait;  // TODO: Useful?

-

-                    srcTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.srcTO);

-                    destTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.destTO);

-                    srcVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.srcTO);

-                    destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.destTO);

-

-                    string destFile = null;

-                    if (destTemplateObjectTO != null)

-                    {

-                        if (destTemplateObjectTO.primaryDataStore != null)

-                        {

-                            destFile = destTemplateObjectTO.FullFileName;

-                            if (!destTemplateObjectTO.primaryDataStore.isLocal)

-                            {

-                                PrimaryDataStoreTO primary = destTemplateObjectTO.primaryDataStore;

-                                Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);

-                            }

-                        }

-                        else if (destTemplateObjectTO.nfsDataStoreTO != null)

-                        {

-                            destFile = destTemplateObjectTO.FullFileName;

-                            NFSTO store = destTemplateObjectTO.nfsDataStoreTO;

-                            Utils.ConnectToRemote(store.UncPath, store.Domain, store.User, store.Password);

-                        }

-                    }

-

-                    // Template already downloaded?

-                    if (destFile != null && File.Exists(destFile) &&

-                        !String.IsNullOrEmpty(destTemplateObjectTO.checksum))

-                    {

-                        // TODO: checksum fails us, because it is of the compressed image.

-                        // ASK: should we store the compressed or uncompressed version or is the checksum not calculated correctly?

-                        logger.Debug(CloudStackTypes.CopyCommand + " calling VerifyChecksum to see if we already have the file at " + destFile);

-                        result = VerifyChecksum(destFile, destTemplateObjectTO.checksum);

-                        if (!result)

-                        {

-                            result = true;

-                            logger.Debug(CloudStackTypes.CopyCommand + " existing file has different checksum " + destFile);

-                        }

-                    }

-

-                    // Do we have to create a new one?

-                    if (!result)

-                    {

-                        // Create local copy of a template?

-                        if (srcTemplateObjectTO != null && destTemplateObjectTO != null)

-                        {

-                            // S3 download to primary storage?

-                            // NFS provider download to primary storage?

-                            if ((srcTemplateObjectTO.s3DataStoreTO != null || srcTemplateObjectTO.nfsDataStoreTO != null) && destTemplateObjectTO.primaryDataStore != null)

-                            {

-                                if (File.Exists(destFile))

-                                {

-                                    logger.Info("Deleting existing file " + destFile);

-                                    File.Delete(destFile);

-                                }

-

-                                if (srcTemplateObjectTO.s3DataStoreTO != null)

-                                {

-                                    // Download from S3 to destination data storage

-                                    DownloadS3ObjectToFile(srcTemplateObjectTO.path, srcTemplateObjectTO.s3DataStoreTO, destFile);

-                                }

-                                else if (srcTemplateObjectTO.nfsDataStoreTO != null)

-                                {

-                                    // Download from S3 to destination data storage

-                                    Utils.DownloadCifsFileToLocalFile(srcTemplateObjectTO.path, srcTemplateObjectTO.nfsDataStoreTO, destFile);

-                                }

-

-                                // Uncompress, as required

-                                if (srcTemplateObjectTO.path.EndsWith(".bz2"))

-                                {

-                                    String uncompressedFile = destFile + ".tmp";

-                                    String compressedFile = destFile;

-                                    using (var uncompressedOutStrm = new FileStream(uncompressedFile, FileMode.CreateNew, FileAccess.Write))

-                                    {

-                                        using (var compressedInStrm = new FileStream(destFile, FileMode.Open, FileAccess.Read))

-                                        {

-                                            using (var bz2UncompressorStrm = new Ionic.BZip2.BZip2InputStream(compressedInStrm, true) /* outer 'using' statement will close FileStream*/ )

-                                            {

-                                                int count = 0;

-                                                int bufsize = 1024 * 1024;

-                                                byte[] buf = new byte[bufsize];

-

-                                                // EOF returns -1, see http://dotnetzip.codeplex.com/workitem/16069 

-                                                while (0 < (count = bz2UncompressorStrm.Read(buf, 0, bufsize)))

-                                                {

-                                                    uncompressedOutStrm.Write(buf, 0, count);

-                                                }

-                                            }

-                                        }

-                                    }

-                                    File.Delete(compressedFile);

-                                    File.Move(uncompressedFile, compressedFile);

-                                    if (File.Exists(uncompressedFile))

-                                    {

-                                        String errMsg = "Extra file left around called " + uncompressedFile + " when creating " + destFile;

-                                        logger.Error(errMsg);

-                                        throw new IOException(errMsg);

-                                    }

-                                }

-

-                                // assert

-                                if (!File.Exists(destFile))

-                                {

-                                    String errMsg = "Failed to create " + destFile + " , because the file is missing";

-                                    logger.Error(errMsg);

-                                    throw new IOException(errMsg);

-                                }

-

-                                newData = cmd.destTO;

-                                result = true;

-                            }

-                            else

-                            {

-                                details = "Data store combination not supported";

-                            }

-                        }

-                        // Create volume from a template?

-                        else if (srcTemplateObjectTO != null && destVolumeObjectTO != null)

-                        {

-                            // VolumeObjectTO guesses file extension based on existing files

-                            // this can be wrong if the previous file had a different file type

-                            var guessedDestFile = destVolumeObjectTO.FullFileName;

-                            if (File.Exists(guessedDestFile))

-                            {

-                                logger.Info("Deleting existing file " + guessedDestFile);

-                                File.Delete(guessedDestFile);

-                            }

-

-                            destVolumeObjectTO.format = srcTemplateObjectTO.format;

-                            destFile = destVolumeObjectTO.FullFileName;

-                            if (File.Exists(destFile))

-                            {

-                                logger.Info("Deleting existing file " + destFile);

-                                File.Delete(destFile);

-                            }

-

-                            string srcFile = srcTemplateObjectTO.FullFileName;

-                            if (!File.Exists(srcFile))

-                            {

-                                details = "Local template file missing from " + srcFile;

-                            }

-                            else

-                            {

-                                // TODO: thin provision instead of copying the full file.

-                                File.Copy(srcFile, destFile);

-                                destVolumeObjectTO.path = destVolumeObjectTO.uuid;

-                                JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO);

-                                newData = ansObj;

-                                result = true;

-                            }

-                        }

-                        else if (srcVolumeObjectTO != null && destVolumeObjectTO != null)

-                        {

-                            var guessedDestFile = destVolumeObjectTO.FullFileName;

-                            if (File.Exists(guessedDestFile))

-                            {

-                                logger.Info("Deleting existing file " + guessedDestFile);

-                                File.Delete(guessedDestFile);

-                            }

-

-                            destVolumeObjectTO.format = srcVolumeObjectTO.format;

-                            destFile = destVolumeObjectTO.FullFileName;

-                            if (File.Exists(destFile))

-                            {

-                                logger.Info("Deleting existing file " + destFile);

-                                File.Delete(destFile);

-                            }

-

-                            string srcFile = srcVolumeObjectTO.FullFileName;

-                            if (!File.Exists(srcFile))

-                            {

-                                details = "Local template file missing from " + srcFile;

-                            }

-                            else

-                            {

-                                // Create the directory before copying the files. CreateDirectory

-                                // doesn't do anything if the directory is already present.

-                                Directory.CreateDirectory(Path.GetDirectoryName(destFile));

-                                File.Copy(srcFile, destFile);

-

-                                if (srcVolumeObjectTO.nfsDataStore != null && srcVolumeObjectTO.primaryDataStore == null)

-                                {

-                                    logger.Info("Copied volume from secondary data store to primary. Path: " + destVolumeObjectTO.path);

-                                }

-                                else if (srcVolumeObjectTO.primaryDataStore != null && srcVolumeObjectTO.nfsDataStore == null)

-                                {

-                                    destVolumeObjectTO.path = destVolumeObjectTO.path + "/" + destVolumeObjectTO.uuid;

-                                    if (destVolumeObjectTO.format != null)

-                                    {

-                                        destVolumeObjectTO.path += "." + destVolumeObjectTO.format.ToLower();

-                                    }

-                                }

-                                else

-                                {

-                                    logger.Error("Destination volume path wasn't set. Unsupported source volume data store.");

-                                }

-

-                                // Create volumeto object deserialize and send it

-                                JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO);

-                                newData = ansObj;

-                                result = true;

-                            }

-                        }

-                        else if (srcVolumeObjectTO != null && destTemplateObjectTO != null)

-                        {

-                            var guessedDestFile = destTemplateObjectTO.FullFileName;

-                            if (File.Exists(guessedDestFile))

-                            {

-                                logger.Info("Deleting existing file " + guessedDestFile);

-                                File.Delete(guessedDestFile);

-                            }

-

-                            destTemplateObjectTO.format = srcVolumeObjectTO.format;

-                            destFile = destTemplateObjectTO.FullFileName;

-                            if (File.Exists(destFile))

-                            {

-                                logger.Info("Deleting existing file " + destFile);

-                                File.Delete(destFile);

-                            }

-

-                            string srcFile = srcVolumeObjectTO.FullFileName;

-                            if (!File.Exists(srcFile))

-                            {

-                                details = "Local template file missing from " + srcFile;

-                            }

-                            else

-                            {

-                                // Create the directory before copying the files. CreateDirectory

-                                // doesn't do anything if the directory is already present.

-                                Directory.CreateDirectory(Path.GetDirectoryName(destFile));

-                                File.Copy(srcFile, destFile);

-

-                                FileInfo destFileInfo = new FileInfo(destFile);

-                                // Write the template.properties file

-                                PostCreateTemplate(Path.GetDirectoryName(destFile), destTemplateObjectTO.id, destTemplateObjectTO.name,

-                                    destFileInfo.Length.ToString(), srcVolumeObjectTO.size.ToString(), destTemplateObjectTO.format);

-

-                                TemplateObjectTO destTemplateObject = new TemplateObjectTO();

-                                destTemplateObject.size = srcVolumeObjectTO.size.ToString();

-                                destTemplateObject.format = srcVolumeObjectTO.format;

-                                destTemplateObject.path = destTemplateObjectTO.path + "/" + destTemplateObjectTO.uuid;

-                                if (destTemplateObject.format != null)

-                                {

-                                    destTemplateObject.path += "." + destTemplateObject.format.ToLower();

-                                }

-                                destTemplateObject.nfsDataStoreTO = destTemplateObjectTO.nfsDataStoreTO;

-                                destTemplateObject.checksum = destTemplateObjectTO.checksum;

-                                newData = destTemplateObject;

-                                JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.TemplateObjectTO, destTemplateObject);

-                                newData = ansObj;

-                                result = true;

-                            }

-                        }

-                        else

-                        {

-                            details = "Data store combination not supported";

-                        }

-                    }

-                }

-                catch (Exception ex)

-                {

-                    // Test by providing wrong key

-                    details = CloudStackTypes.CopyCommand + " failed on exception, " + ex.Message;

-                    logger.Error(details, ex);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    newData = newData,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CopyCmdAnswer);

-            }

-        }

-

-        private static void PostCreateTemplate(string path, string templateId, string templateUuid, string physicalSize, string virtualSize, string format)

-        {

-            string templatePropFile = Path.Combine(path, "template.properties");

-            using (StreamWriter sw = new StreamWriter(File.Open(templatePropFile, FileMode.Create), Encoding.GetEncoding("iso-8859-1")))

-            {

-                if (format != null)

-                {

-                    format = format.ToLower();

-                }

-

-                sw.NewLine = "\n";

-                sw.WriteLine("id=" + templateId);

-                sw.WriteLine("filename=" + templateUuid + "." + format);

-                sw.WriteLine(format + ".filename=" + templateUuid + "." + format);

-                sw.WriteLine("uniquename=" + templateUuid);

-                sw.WriteLine(format + "=true");

-                sw.WriteLine("virtualsize=" + virtualSize);

-                sw.WriteLine(format + ".virtualsize=" + virtualSize);

-                sw.WriteLine("size=" + physicalSize);

-                sw.WriteLine(format + ".size=" + physicalSize);

-                sw.WriteLine("public=false");

-            }

-        }

-

-        private static bool VerifyChecksum(string destFile, string checksum)

-        {

-            string localChecksum = BitConverter.ToString(CalcFileChecksum(destFile)).Replace("-", "").ToLower();

-            logger.Debug("Checksum of " + destFile + " is " + checksum);

-            if (checksum.Equals(localChecksum))

-            {

-                return true;

-            }

-            return false;

-        }

-

-        /// <summary>

-        /// Match implmentation of DownloadManagerImpl.computeCheckSum

-        /// </summary>

-        /// <param name="destFile"></param>

-        /// <returns></returns>

-        private static byte[] CalcFileChecksum(string destFile)

-        {

-            // TODO:  Add unit test to verify that checksum algorithm has not changed.

-            using (MD5 md5 = MD5.Create())

-            {

-                using (FileStream stream = File.OpenRead(destFile))

-                {

-                    return md5.ComputeHash(stream);

-                }

-            }

-        }

-

-        private static void DownloadS3ObjectToFile(string srcObjectKey, S3TO srcS3TO, string destFile)

-        {

-            AmazonS3Config S3Config = new AmazonS3Config

-            {

-                ServiceURL = srcS3TO.endpoint,

-                CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP

-            };

-

-            if (srcS3TO.httpsFlag)

-            {

-                S3Config.CommunicationProtocol = Protocol.HTTPS;

-            }

-

-            try

-            {

-                using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(srcS3TO.accessKey, srcS3TO.secretKey, S3Config))

-                {

-                    GetObjectRequest getObjectRequest = new GetObjectRequest().WithBucketName(srcS3TO.bucketName).WithKey(srcObjectKey);

-

-                    using (S3Response getObjectResponse = client.GetObject(getObjectRequest))

-                    {

-                        using (Stream s = getObjectResponse.ResponseStream)

-                        {

-                            using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write))

-                            {

-                                byte[] data = new byte[524288];

-                                int bytesRead = 0;

-                                do

-                                {

-                                    bytesRead = s.Read(data, 0, data.Length);

-                                    fs.Write(data, 0, bytesRead);

-                                }

-                                while (bytesRead > 0);

-                                fs.Flush();

-                            }

-                        }

-                    }

-                }

-            }

-            catch (Exception ex)

-            {

-                string errMsg = "Download from S3 url" + srcS3TO.endpoint + " said: " + ex.Message;

-                logger.Error(errMsg, ex);

-                throw new Exception(errMsg, ex);

-            }

-        }

-

-        // POST api/HypervResource/GetStorageStatsCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.GetStorageStatsCommand)]

-        public JContainer GetStorageStatsCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(CloudStackTypes.GetStorageStatsCommand + Utils.CleanString(cmd.ToString()));

-                bool result = false;

-                string details = null;

-                long capacity = 0;

-                long available = 0;

-                long used = 0;

-                try

-                {

-                    StoragePoolType poolType;

-                    string poolId = (string)cmd.id;

-                    string hostPath = null;

-                    if (!Enum.TryParse<StoragePoolType>((string)cmd.pooltype, out poolType))

-                    {

-                        details = "Request to get unsupported pool type: " + ((string)cmd.pooltype == null ? "NULL" : (string)cmd.pooltype) + "in cmd " +

-                            JsonConvert.SerializeObject(cmd);

-                        logger.Error(details);

-                    }

-                    else if (poolType == StoragePoolType.Filesystem)

-                    {

-                        hostPath = (string)cmd.localPath;;

-                        GetCapacityForLocalPath(hostPath, out capacity, out available);

-                        used = capacity - available;

-                        result = true;

-                    }

-                    else if (poolType == StoragePoolType.NetworkFilesystem || poolType == StoragePoolType.SMB)

-                    {

-                        string sharePath = config.getPrimaryStorage((string)cmd.id);

-                        if (sharePath != null)

-                        {

-                            hostPath = sharePath;

-                            Utils.GetShareDetails(sharePath, out capacity, out available);

-                            used = capacity - available;

-                            result = true;

-                        }

-                    }

-                    else

-                    {

-                        result = false;

-                    }

-

-                    if (result)

-                    {

-                        logger.Debug(CloudStackTypes.GetStorageStatsCommand + " set used bytes for " + hostPath + " to " + used);

-                    }

-                }

-                catch (Exception ex)

-                {

-                    details = CloudStackTypes.GetStorageStatsCommand + " failed on exception" + ex.Message;

-                    logger.Error(details, ex);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    capacity = capacity,

-                    used = used,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetStorageStatsAnswer);

-            }

-        }

-

-        // POST api/HypervResource/GetHostStatsCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.GetHostStatsCommand)]

-        public JContainer GetHostStatsCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                bool result = false;
+                JArray vmNamesJson = cmd.vmNames;
+                string[] vmNames = vmNamesJson.ToObject<string[]>();
+                Dictionary<string, VmStatsEntry> vmProcessorInfo = new Dictionary<string, VmStatsEntry>(vmNames.Length);
+
+                var vmsToInspect = new List<System.Management.ManagementPath>();
+                foreach (var vmName in vmNames)
+                {
+                    var sys = wmiCallsV2.GetComputerSystem(vmName);
+                    if (sys == null)
+                    {
+                        logger.InfoFormat("GetVmStatsCommand requested unknown VM {0}", vmNames);
+                        continue;
+                    }
+                    var sysInfo = wmiCallsV2.GetVmSettings(sys);
+                    vmsToInspect.Add(sysInfo.Path);
+                }
+
+                wmiCallsV2.GetSummaryInfo(vmProcessorInfo, vmsToInspect);
+
+                // TODO: Network usage comes from Performance Counter API; however it is only available in kb/s, and not in total terms.
+                // Curious about these?  Use perfmon to inspect them, e.g. http://msdn.microsoft.com/en-us/library/xhcx5a20%28v=vs.100%29.aspx
+                // Recent post on these counter at http://blogs.technet.com/b/cedward/archive/2011/07/19/hyper-v-networking-optimizations-part-6-of-6-monitoring-hyper-v-network-consumption.aspx
+                result = true;
+
+                object ansContent = new
+                {
+                    vmStatsMap = vmProcessorInfo,
+                    result = result,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVmStatsAnswer);
+            }
+        }
+
+        // POST api/HypervResource/CopyCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.CopyCommand)]
+        public JContainer CopyCommand(dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                // Log command *after* we've removed security details from the command.
+                logger.Info(CloudStackTypes.CopyCommand + Utils.CleanString(cmd.ToString()));
+
+                bool result = false;
+                string details = null;
+                object newData = null;
+                TemplateObjectTO destTemplateObjectTO = null;
+                VolumeObjectTO destVolumeObjectTO = null;
+                VolumeObjectTO srcVolumeObjectTO = null;
+                TemplateObjectTO srcTemplateObjectTO = null;
+
+                try
+                {
+                    dynamic timeout = cmd.wait;  // TODO: Useful?
+
+                    srcTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.srcTO);
+                    destTemplateObjectTO = TemplateObjectTO.ParseJson(cmd.destTO);
+                    srcVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.srcTO);
+                    destVolumeObjectTO = VolumeObjectTO.ParseJson(cmd.destTO);
+
+                    string destFile = null;
+                    if (destTemplateObjectTO != null)
+                    {
+                        if (destTemplateObjectTO.primaryDataStore != null)
+                        {
+                            destFile = destTemplateObjectTO.FullFileName;
+                            if (!destTemplateObjectTO.primaryDataStore.isLocal)
+                            {
+                                PrimaryDataStoreTO primary = destTemplateObjectTO.primaryDataStore;
+                                Utils.ConnectToRemote(primary.UncPath, primary.Domain, primary.User, primary.Password);
+                            }
+                        }
+                        else if (destTemplateObjectTO.nfsDataStoreTO != null)
+                        {
+                            destFile = destTemplateObjectTO.FullFileName;
+                            NFSTO store = destTemplateObjectTO.nfsDataStoreTO;
+                            Utils.ConnectToRemote(store.UncPath, store.Domain, store.User, store.Password);
+                        }
+                    }
+
+                    // Template already downloaded?
+                    if (destFile != null && File.Exists(destFile) &&
+                        !String.IsNullOrEmpty(destTemplateObjectTO.checksum))
+                    {
+                        // TODO: checksum fails us, because it is of the compressed image.
+                        // ASK: should we store the compressed or uncompressed version or is the checksum not calculated correctly?
+                        logger.Debug(CloudStackTypes.CopyCommand + " calling VerifyChecksum to see if we already have the file at " + destFile);
+                        result = VerifyChecksum(destFile, destTemplateObjectTO.checksum);
+                        if (!result)
+                        {
+                            result = true;
+                            logger.Debug(CloudStackTypes.CopyCommand + " existing file has different checksum " + destFile);
+                        }
+                    }
+
+                    // Do we have to create a new one?
+                    if (!result)
+                    {
+                        // Create local copy of a template?
+                        if (srcTemplateObjectTO != null && destTemplateObjectTO != null)
+                        {
+                            // S3 download to primary storage?
+                            // NFS provider download to primary storage?
+                            if ((srcTemplateObjectTO.s3DataStoreTO != null || srcTemplateObjectTO.nfsDataStoreTO != null) && destTemplateObjectTO.primaryDataStore != null)
+                            {
+                                if (File.Exists(destFile))
+                                {
+                                    logger.Info("Deleting existing file " + destFile);
+                                    File.Delete(destFile);
+                                }
+
+                                if (srcTemplateObjectTO.s3DataStoreTO != null)
+                                {
+                                    // Download from S3 to destination data storage
+                                    DownloadS3ObjectToFile(srcTemplateObjectTO.path, srcTemplateObjectTO.s3DataStoreTO, destFile);
+                                }
+                                else if (srcTemplateObjectTO.nfsDataStoreTO != null)
+                                {
+                                    // Download from S3 to destination data storage
+                                    Utils.DownloadCifsFileToLocalFile(srcTemplateObjectTO.path, srcTemplateObjectTO.nfsDataStoreTO, destFile);
+                                }
+
+                                // Uncompress, as required
+                                if (srcTemplateObjectTO.path.EndsWith(".bz2"))
+                                {
+                                    String uncompressedFile = destFile + ".tmp";
+                                    String compressedFile = destFile;
+                                    using (var uncompressedOutStrm = new FileStream(uncompressedFile, FileMode.CreateNew, FileAccess.Write))
+                                    {
+                                        using (var compressedInStrm = new FileStream(destFile, FileMode.Open, FileAccess.Read))
+                                        {
+                                            using (var bz2UncompressorStrm = new Ionic.BZip2.BZip2InputStream(compressedInStrm, true) /* outer 'using' statement will close FileStream*/ )
+                                            {
+                                                int count = 0;
+                                                int bufsize = 1024 * 1024;
+                                                byte[] buf = new byte[bufsize];
+
+                                                // EOF returns -1, see http://dotnetzip.codeplex.com/workitem/16069 
+                                                while (0 < (count = bz2UncompressorStrm.Read(buf, 0, bufsize)))
+                                                {
+                                                    uncompressedOutStrm.Write(buf, 0, count);
+                                                }
+                                            }
+                                        }
+                                    }
+                                    File.Delete(compressedFile);
+                                    File.Move(uncompressedFile, compressedFile);
+                                    if (File.Exists(uncompressedFile))
+                                    {
+                                        String errMsg = "Extra file left around called " + uncompressedFile + " when creating " + destFile;
+                                        logger.Error(errMsg);
+                                        throw new IOException(errMsg);
+                                    }
+                                }
+
+                                // assert
+                                if (!File.Exists(destFile))
+                                {
+                                    String errMsg = "Failed to create " + destFile + " , because the file is missing";
+                                    logger.Error(errMsg);
+                                    throw new IOException(errMsg);
+                                }
+
+                                newData = cmd.destTO;
+                                result = true;
+                            }
+                            else
+                            {
+                                details = "Data store combination not supported";
+                            }
+                        }
+                        // Create volume from a template?
+                        else if (srcTemplateObjectTO != null && destVolumeObjectTO != null)
+                        {
+                            // VolumeObjectTO guesses file extension based on existing files
+                            // this can be wrong if the previous file had a different file type
+                            var guessedDestFile = destVolumeObjectTO.FullFileName;
+                            if (File.Exists(guessedDestFile))
+                            {
+                                logger.Info("Deleting existing file " + guessedDestFile);
+                                File.Delete(guessedDestFile);
+                            }
+
+                            destVolumeObjectTO.format = srcTemplateObjectTO.format;
+                            destFile = destVolumeObjectTO.FullFileName;
+                            if (File.Exists(destFile))
+                            {
+                                logger.Info("Deleting existing file " + destFile);
+                                File.Delete(destFile);
+                            }
+
+                            string srcFile = srcTemplateObjectTO.FullFileName;
+                            if (!File.Exists(srcFile))
+                            {
+                                details = "Local template file missing from " + srcFile;
+                            }
+                            else
+                            {
+                                // TODO: thin provision instead of copying the full file.
+                                File.Copy(srcFile, destFile);
+                                destVolumeObjectTO.path = destVolumeObjectTO.uuid;
+                                JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO);
+                                newData = ansObj;
+                                result = true;
+                            }
+                        }
+                        else if (srcVolumeObjectTO != null && destVolumeObjectTO != null)
+                        {
+                            var guessedDestFile = destVolumeObjectTO.FullFileName;
+                            if (File.Exists(guessedDestFile))
+                            {
+                                logger.Info("Deleting existing file " + guessedDestFile);
+                                File.Delete(guessedDestFile);
+                            }
+
+                            destVolumeObjectTO.format = srcVolumeObjectTO.format;
+                            destFile = destVolumeObjectTO.FullFileName;
+                            if (File.Exists(destFile))
+                            {
+                                logger.Info("Deleting existing file " + destFile);
+                                File.Delete(destFile);
+                            }
+
+                            string srcFile = srcVolumeObjectTO.FullFileName;
+                            if (!File.Exists(srcFile))
+                            {
+                                details = "Local template file missing from " + srcFile;
+                            }
+                            else
+                            {
+                                // Create the directory before copying the files. CreateDirectory
+                                // doesn't do anything if the directory is already present.
+                                Directory.CreateDirectory(Path.GetDirectoryName(destFile));
+                                File.Copy(srcFile, destFile);
+
+                                if (srcVolumeObjectTO.nfsDataStore != null && srcVolumeObjectTO.primaryDataStore == null)
+                                {
+                                    logger.Info("Copied volume from secondary data store to primary. Path: " + destVolumeObjectTO.path);
+                                }
+                                else if (srcVolumeObjectTO.primaryDataStore != null && srcVolumeObjectTO.nfsDataStore == null)
+                                {
+                                    destVolumeObjectTO.path = destVolumeObjectTO.path + "/" + destVolumeObjectTO.uuid;
+                                    if (destVolumeObjectTO.format != null)
+                                    {
+                                        destVolumeObjectTO.path += "." + destVolumeObjectTO.format.ToLower();
+                                    }
+                                }
+                                else
+                                {
+                                    logger.Error("Destination volume path wasn't set. Unsupported source volume data store.");
+                                }
+
+                                // Create volumeto object deserialize and send it
+                                JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.VolumeObjectTO, destVolumeObjectTO);
+                                newData = ansObj;
+                                result = true;
+                            }
+                        }
+                        else if (srcVolumeObjectTO != null && destTemplateObjectTO != null)
+                        {
+                            var guessedDestFile = destTemplateObjectTO.FullFileName;
+                            if (File.Exists(guessedDestFile))
+                            {
+                                logger.Info("Deleting existing file " + guessedDestFile);
+                                File.Delete(guessedDestFile);
+                            }
+
+                            destTemplateObjectTO.format = srcVolumeObjectTO.format;
+                            destFile = destTemplateObjectTO.FullFileName;
+                            if (File.Exists(destFile))
+                            {
+                                logger.Info("Deleting existing file " + destFile);
+                                File.Delete(destFile);
+                            }
+
+                            string srcFile = srcVolumeObjectTO.FullFileName;
+                            if (!File.Exists(srcFile))
+                            {
+                                details = "Local template file missing from " + srcFile;
+                            }
+                            else
+                            {
+                                // Create the directory before copying the files. CreateDirectory
+                                // doesn't do anything if the directory is already present.
+                                Directory.CreateDirectory(Path.GetDirectoryName(destFile));
+                                File.Copy(srcFile, destFile);
+
+                                FileInfo destFileInfo = new FileInfo(destFile);
+                                // Write the template.properties file
+                                PostCreateTemplate(Path.GetDirectoryName(destFile), destTemplateObjectTO.id, destTemplateObjectTO.name,
+                                    destFileInfo.Length.ToString(), srcVolumeObjectTO.size.ToString(), destTemplateObjectTO.format);
+
+                                TemplateObjectTO destTemplateObject = new TemplateObjectTO();
+                                destTemplateObject.size = srcVolumeObjectTO.size.ToString();
+                                destTemplateObject.format = srcVolumeObjectTO.format;
+                                destTemplateObject.path = destTemplateObjectTO.path + "/" + destTemplateObjectTO.uuid;
+                                if (destTemplateObject.format != null)
+                                {
+                                    destTemplateObject.path += "." + destTemplateObject.format.ToLower();
+                                }
+                                destTemplateObject.nfsDataStoreTO = destTemplateObjectTO.nfsDataStoreTO;
+                                destTemplateObject.checksum = destTemplateObjectTO.checksum;
+                                newData = destTemplateObject;
+                                JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.TemplateObjectTO, destTemplateObject);
+                                newData = ansObj;
+                                result = true;
+                            }
+                        }
+                        else
+                        {
+                            details = "Data store combination not supported";
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    // Test by providing wrong key
+                    details = CloudStackTypes.CopyCommand + " failed on exception, " + ex.Message;
+                    logger.Error(details, ex);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    newData = newData,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.CopyCmdAnswer);
+            }
+        }
+
+        private static void PostCreateTemplate(string path, string templateId, string templateUuid, string physicalSize, string virtualSize, string format)
+        {
+            string templatePropFile = Path.Combine(path, "template.properties");
+            using (StreamWriter sw = new StreamWriter(File.Open(templatePropFile, FileMode.Create), Encoding.GetEncoding("iso-8859-1")))
+            {
+                if (format != null)
+                {
+                    format = format.ToLower();
+                }
+
+                sw.NewLine = "\n";
+                sw.WriteLine("id=" + templateId);
+                sw.WriteLine("filename=" + templateUuid + "." + format);
+                sw.WriteLine(format + ".filename=" + templateUuid + "." + format);
+                sw.WriteLine("uniquename=" + templateUuid);
+                sw.WriteLine(format + "=true");
+                sw.WriteLine("virtualsize=" + virtualSize);
+                sw.WriteLine(format + ".virtualsize=" + virtualSize);
+                sw.WriteLine("size=" + physicalSize);
+                sw.WriteLine(format + ".size=" + physicalSize);
+                sw.WriteLine("public=false");
+            }
+        }
+
+        private static bool VerifyChecksum(string destFile, string checksum)
+        {
+            string localChecksum = BitConverter.ToString(CalcFileChecksum(destFile)).Replace("-", "").ToLower();
+            logger.Debug("Checksum of " + destFile + " is " + checksum);
+            if (checksum.Equals(localChecksum))
+            {
+                return true;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Match implmentation of DownloadManagerImpl.computeCheckSum
+        /// </summary>
+        /// <param name="destFile"></param>
+        /// <returns></returns>
+        private static byte[] CalcFileChecksum(string destFile)
+        {
+            // TODO:  Add unit test to verify that checksum algorithm has not changed.
+            using (MD5 md5 = MD5.Create())
+            {
+                using (FileStream stream = File.OpenRead(destFile))
+                {
+                    return md5.ComputeHash(stream);
+                }
+            }
+        }
+
+        private static void DownloadS3ObjectToFile(string srcObjectKey, S3TO srcS3TO, string destFile)
+        {
+            AmazonS3Config S3Config = new AmazonS3Config
+            {
+                ServiceURL = srcS3TO.endpoint,
+                CommunicationProtocol = Amazon.S3.Model.Protocol.HTTP
+            };
+
+            if (srcS3TO.httpsFlag)
+            {
+                S3Config.CommunicationProtocol = Protocol.HTTPS;
+            }
+
+            try
+            {
+                using (AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(srcS3TO.accessKey, srcS3TO.secretKey, S3Config))
+                {
+                    GetObjectRequest getObjectRequest = new GetObjectRequest().WithBucketName(srcS3TO.bucketName).WithKey(srcObjectKey);
+
+                    using (S3Response getObjectResponse = client.GetObject(getObjectRequest))
+                    {
+                        using (Stream s = getObjectResponse.ResponseStream)
+                        {
+                            using (FileStream fs = new FileStream(destFile, FileMode.Create, FileAccess.Write))
+                            {
+                                byte[] data = new byte[524288];
+                                int bytesRead = 0;
+                                do
+                                {
+                                    bytesRead = s.Read(data, 0, data.Length);
+                                    fs.Write(data, 0, bytesRead);
+                                }
+                                while (bytesRead > 0);
+                                fs.Flush();
+                            }
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                string errMsg = "Download from S3 url" + srcS3TO.endpoint + " said: " + ex.Message;
+                logger.Error(errMsg, ex);
+                throw new Exception(errMsg, ex);
+            }
+        }
+
+        // POST api/HypervResource/GetStorageStatsCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.GetStorageStatsCommand)]
+        public JContainer GetStorageStatsCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(CloudStackTypes.GetStorageStatsCommand + Utils.CleanString(cmd.ToString()));
+                bool result = false;
+                string details = null;
+                long capacity = 0;
+                long available = 0;
+                long used = 0;
+                try
+                {
+                    StoragePoolType poolType;
+                    string poolId = (string)cmd.id;
+                    string hostPath = null;
+                    if (!Enum.TryParse<StoragePoolType>((string)cmd.pooltype, out poolType))
+                    {
+                        details = "Request to get unsupported pool type: " + ((string)cmd.pooltype == null ? "NULL" : (string)cmd.pooltype) + "in cmd " +
+                            JsonConvert.SerializeObject(cmd);
+                        logger.Error(details);
+                    }
+                    else if (poolType == StoragePoolType.Filesystem)
+                    {
+                        hostPath = (string)cmd.localPath;;
+                        GetCapacityForLocalPath(hostPath, out capacity, out available);
+                        used = capacity - available;
+                        result = true;
+                    }
+                    else if (poolType == StoragePoolType.NetworkFilesystem || poolType == StoragePoolType.SMB)
+                    {
+                        string sharePath = config.getPrimaryStorage((string)cmd.id);
+                        if (sharePath != null)
+                        {
+                            hostPath = sharePath;
+                            Utils.GetShareDetails(sharePath, out capacity, out available);
+                            used = capacity - available;
+                            result = true;
+                        }
+                    }
+                    else
+                    {
+                        result = false;
+                    }
+
+                    if (result)
+                    {
+                        logger.Debug(CloudStackTypes.GetStorageStatsCommand + " set used bytes for " + hostPath + " to " + used);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    details = CloudStackTypes.GetStorageStatsCommand + " failed on exception" + ex.Message;
+                    logger.Error(details, ex);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    capacity = capacity,
+                    used = used,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetStorageStatsAnswer);
+            }
+        }
+
+        // POST api/HypervResource/GetHostStatsCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.GetHostStatsCommand)]
+        public JContainer GetHostStatsCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.GetHostStatsCommand + Utils.CleanString(cmd.ToString()));
-                bool result = false;

-                string details = null;

-                object hostStats = null;

-

-                var entityType = "host";

-                ulong totalMemoryKBs;

-                ulong freeMemoryKBs;

-                double networkReadKBs;

-                double networkWriteKBs;

-                double cpuUtilization;

-

-                try

-                {

-                    long hostId = (long)cmd.hostId;

-                    wmiCallsV2.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs);

-                    wmiCallsV2.GetProcessorUsageInfo(out cpuUtilization);

-

-                    // TODO: can we assume that the host has only one adaptor?

-                    string tmp;

-                    var privateNic = GetNicInfoFromIpAddress(config.PrivateIpAddress, out tmp);

-                    var nicStats = privateNic.GetIPv4Statistics();  //TODO: add IPV6 support, currentl

-                    networkReadKBs = nicStats.BytesReceived;

-                    networkWriteKBs = nicStats.BytesSent;

-

-                    // Generate GetHostStatsAnswer

-                    hostStats = new

-                    {

-                        hostId = hostId,

-                        entityType = entityType,

-                        cpuUtilization = cpuUtilization,

-                        networkReadKBs = networkReadKBs,

-                        networkWriteKBs = networkWriteKBs,

-                        totalMemoryKBs = (double)totalMemoryKBs,

-                        freeMemoryKBs = (double)freeMemoryKBs

-                    };

-                    result = true;

-                }

-                catch (Exception ex)

-                {

-                    details = CloudStackTypes.GetHostStatsCommand + " failed on exception" + ex.Message;

-                    logger.Error(details, ex);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    hostStats = hostStats,

-                    details = details,

-                    contextMap = contextMap

-                };

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetHostStatsAnswer);

-            }

-        }

-

-        // POST api/HypervResource/PrepareForMigrationCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.PrepareForMigrationCommand)]

-        public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                bool result = false;
+                string details = null;
+                object hostStats = null;
+
+                var entityType = "host";
+                ulong totalMemoryKBs;
+                ulong freeMemoryKBs;
+                double networkReadKBs;
+                double networkWriteKBs;
+                double cpuUtilization;
+
+                try
+                {
+                    long hostId = (long)cmd.hostId;
+                    wmiCallsV2.GetMemoryResources(out totalMemoryKBs, out freeMemoryKBs);
+                    wmiCallsV2.GetProcessorUsageInfo(out cpuUtilization);
+
+                    // TODO: can we assume that the host has only one adaptor?
+                    string tmp;
+                    var privateNic = GetNicInfoFromIpAddress(config.PrivateIpAddress, out tmp);
+                    var nicStats = privateNic.GetIPv4Statistics();  //TODO: add IPV6 support, currentl
+                    networkReadKBs = nicStats.BytesReceived;
+                    networkWriteKBs = nicStats.BytesSent;
+
+                    // Generate GetHostStatsAnswer
+                    hostStats = new
+                    {
+                        hostId = hostId,
+                        entityType = entityType,
+                        cpuUtilization = cpuUtilization,
+                        networkReadKBs = networkReadKBs,
+                        networkWriteKBs = networkWriteKBs,
+                        totalMemoryKBs = (double)totalMemoryKBs,
+                        freeMemoryKBs = (double)freeMemoryKBs
+                    };
+                    result = true;
+                }
+                catch (Exception ex)
+                {
+                    details = CloudStackTypes.GetHostStatsCommand + " failed on exception" + ex.Message;
+                    logger.Error(details, ex);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    hostStats = hostStats,
+                    details = details,
+                    contextMap = contextMap
+                };
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetHostStatsAnswer);
+            }
+        }
+
+        // POST api/HypervResource/PrepareForMigrationCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.PrepareForMigrationCommand)]
+        public JContainer PrepareForMigrationCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.PrepareForMigrationCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = true;

-

-                try

-                {

-                    details = "NOP - success";

-                }

-                catch (Exception sysEx)

-                {

-                    result = false;

-                    details = CloudStackTypes.PrepareForMigrationCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrepareForMigrationAnswer);

-            }

-        }

-

-        // POST api/HypervResource/MigrateCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.MigrateCommand)]

-        public JContainer MigrateCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                string details = null;
+                bool result = true;
+
+                try
+                {
+                    details = "NOP - success";
+                }
+                catch (Exception sysEx)
+                {
+                    result = false;
+                    details = CloudStackTypes.PrepareForMigrationCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.PrepareForMigrationAnswer);
+            }
+        }
+
+        // POST api/HypervResource/MigrateCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.MigrateCommand)]
+        public JContainer MigrateCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.MigrateCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    string vm = (string)cmd.vmName;

-                    string destination = (string)cmd.destIp;

-                    wmiCallsV2.MigrateVm(vm, destination);

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.MigrateCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateAnswer);

-            }

-        }

-

-        // POST api/HypervResource/MigrateVolumeCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.MigrateVolumeCommand)]

-        public JContainer MigrateVolumeCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string vm = (string)cmd.vmName;
+                    string destination = (string)cmd.destIp;
+                    wmiCallsV2.MigrateVm(vm, destination);
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.MigrateCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateAnswer);
+            }
+        }
+
+        // POST api/HypervResource/MigrateVolumeCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.MigrateVolumeCommand)]
+        public JContainer MigrateVolumeCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.MigrateVolumeCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-

-                try

-                {

-                    string vm = (string)cmd.attachedVmName;

-                    string volume = (string)cmd.volumePath;

-                    wmiCallsV2.MigrateVolume(vm, volume, GetStoragePoolPath(cmd.pool));

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.MigrateVolumeCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    volumePath = (string)cmd.volumePath,

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateVolumeAnswer);

-            }

-        }

-

-        // POST api/HypervResource/MigrateWithStorageCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.MigrateWithStorageCommand)]

-        public JContainer MigrateWithStorageCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+
+                string details = null;
+                bool result = false;
+
+                try
+                {
+                    string vm = (string)cmd.attachedVmName;
+                    string volume = (string)cmd.volumePath;
+                    wmiCallsV2.MigrateVolume(vm, volume, GetStoragePoolPath(cmd.pool));
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.MigrateVolumeCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    volumePath = (string)cmd.volumePath,
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateVolumeAnswer);
+            }
+        }
+
+        // POST api/HypervResource/MigrateWithStorageCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.MigrateWithStorageCommand)]
+        public JContainer MigrateWithStorageCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.MigrateWithStorageCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-                List<dynamic> volumeTos = new List<dynamic>();

-

-                try

-                {

-                    string vm = (string)cmd.vm.name;

-                    string destination = (string)cmd.tgtHost;

-                    var volumeToPoolList = cmd.volumeToFilerAsList;

-                    var volumeToPool = new Dictionary<string, string>();

-                    foreach (var item in volumeToPoolList)

-                    {

-                        volumeTos.Add(item.t);

-                        string poolPath = GetStoragePoolPath(item.u);

-                        volumeToPool.Add((string)item.t.path, poolPath);

-                    }

-

-                    wmiCallsV2.MigrateVmWithVolume(vm, destination, volumeToPool);

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.MigrateWithStorageCommand + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    volumeTos = JArray.FromObject(volumeTos),

-                    details = details,

-                    contextMap = contextMap

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateWithStorageAnswer);

-            }

-        }

-

-        private string GetStoragePoolPath(dynamic pool)

-        {

-            string poolTypeStr = pool.type;

-            StoragePoolType poolType;

-            if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType))

-            {

-                throw new ArgumentException("Invalid pool type " + poolTypeStr);

-            }

-            else if (poolType == StoragePoolType.SMB)

-            {

-                NFSTO share = new NFSTO();

-                String uriStr = "cifs://" + (string)pool.host + (string)pool.path;

-                share.uri = new Uri(uriStr);

-                return Utils.NormalizePath(share.UncPath);

-            }

-            else if (poolType == StoragePoolType.Filesystem)

-            {

-                return pool.path;

-            }

-

-            throw new ArgumentException("Couldn't parse path for pool type " + poolTypeStr);

-        }

-

-        // POST api/HypervResource/StartupCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.StartupCommand)]

-        public JContainer StartupCommand([FromBody]dynamic cmdArray)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

-                logger.Info(cmdArray.ToString());

-                // Log agent configuration

-                logger.Info("Agent StartupRoutingCommand received " + cmdArray.ToString());

-                dynamic strtRouteCmd = cmdArray[0][CloudStackTypes.StartupRoutingCommand];

-

-                // Insert networking details

-                string privateIpAddress = strtRouteCmd.privateIpAddress;

+
+                string details = null;
+                bool result = false;
+                List<dynamic> volumeTos = new List<dynamic>();
+
+                try
+                {
+                    string vm = (string)cmd.vm.name;
+                    string destination = (string)cmd.tgtHost;
+                    var volumeToPoolList = cmd.volumeToFilerAsList;
+                    var volumeToPool = new Dictionary<string, string>();
+                    foreach (var item in volumeToPoolList)
+                    {
+                        volumeTos.Add(item.t);
+                        string poolPath = GetStoragePoolPath(item.u);
+                        volumeToPool.Add((string)item.t.path, poolPath);
+                    }
+
+                    wmiCallsV2.MigrateVmWithVolume(vm, destination, volumeToPool);
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.MigrateWithStorageCommand + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    volumeTos = JArray.FromObject(volumeTos),
+                    details = details,
+                    contextMap = contextMap
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.MigrateWithStorageAnswer);
+            }
+        }
+
+        private string GetStoragePoolPath(dynamic pool)
+        {
+            string poolTypeStr = pool.type;
+            StoragePoolType poolType;
+            if (!Enum.TryParse<StoragePoolType>(poolTypeStr, out poolType))
+            {
+                throw new ArgumentException("Invalid pool type " + poolTypeStr);
+            }
+            else if (poolType == StoragePoolType.SMB)
+            {
+                NFSTO share = new NFSTO();
+                String uriStr = "cifs://" + (string)pool.host + (string)pool.path;
+                share.uri = new Uri(uriStr);
+                return Utils.NormalizePath(share.UncPath);
+            }
+            else if (poolType == StoragePoolType.Filesystem)
+            {
+                return pool.path;
+            }
+
+            throw new ArgumentException("Couldn't parse path for pool type " + poolTypeStr);
+        }
+
+        // POST api/HypervResource/StartupCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.StartupCommand)]
+        public JContainer StartupCommand([FromBody]dynamic cmdArray)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
+                logger.Info(cmdArray.ToString());
+                // Log agent configuration
+                logger.Info("Agent StartupRoutingCommand received " + cmdArray.ToString());
+                dynamic strtRouteCmd = cmdArray[0][CloudStackTypes.StartupRoutingCommand];
+
+                // Insert networking details
+                string privateIpAddress = strtRouteCmd.privateIpAddress;
                 config.PrivateIpAddress = privateIpAddress;
-                string subnet;

-                System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet);

-                strtRouteCmd.privateIpAddress = privateIpAddress;

-                strtRouteCmd.privateNetmask = subnet;

-                strtRouteCmd.privateMacAddress = privateNic.GetPhysicalAddress().ToString();

-                string storageip = strtRouteCmd.storageIpAddress;

-                System.Net.NetworkInformation.NetworkInterface storageNic = GetNicInfoFromIpAddress(storageip, out subnet);

-

-                strtRouteCmd.storageIpAddress = storageip;

-                strtRouteCmd.storageNetmask = subnet;

-                strtRouteCmd.storageMacAddress = storageNic.GetPhysicalAddress().ToString();

-                strtRouteCmd.gatewayIpAddress = storageNic.GetPhysicalAddress().ToString();

-                strtRouteCmd.hypervisorVersion = System.Environment.OSVersion.Version.Major.ToString() + "." +

+                string subnet;
+                System.Net.NetworkInformation.NetworkInterface privateNic = GetNicInfoFromIpAddress(privateIpAddress, out subnet);
+                strtRouteCmd.privateIpAddress = privateIpAddress;
+                strtRouteCmd.privateNetmask = subnet;
+                strtRouteCmd.privateMacAddress = privateNic.GetPhysicalAddress().ToString();
+                string storageip = strtRouteCmd.storageIpAddress;
+                System.Net.NetworkInformation.NetworkInterface storageNic = GetNicInfoFromIpAddress(storageip, out subnet);
+
+                strtRouteCmd.storageIpAddress = storageip;
+                strtRouteCmd.storageNetmask = subnet;
+                strtRouteCmd.storageMacAddress = storageNic.GetPhysicalAddress().ToString();
+                strtRouteCmd.gatewayIpAddress = storageNic.GetPhysicalAddress().ToString();
+                strtRouteCmd.hypervisorVersion = System.Environment.OSVersion.Version.Major.ToString() + "." +
                         System.Environment.OSVersion.Version.Minor.ToString();
-                strtRouteCmd.caps = "hvm";

-

-                dynamic details = strtRouteCmd.hostDetails;

-                if (details != null)

-                {

-                    string productVersion = System.Environment.OSVersion.Version.Major.ToString() + "." +

-                        System.Environment.OSVersion.Version.Minor.ToString();

-                    details.Add("product_version", productVersion);

+                strtRouteCmd.caps = "hvm";
+
+                dynamic details = strtRouteCmd.hostDetails;
+                if (details != null)
+                {
+                    string productVersion = System.Environment.OSVersion.Version.Major.ToString() + "." +
+                        System.Environment.OSVersion.Version.Minor.ToString();
+                    details.Add("product_version", productVersion);
                     details.Add("rdp.server.port", 2179);
-                }

-

-                // Detect CPUs, speed, memory

-                uint cores;

-                uint mhz;

-                uint sockets;

-                wmiCallsV2.GetProcessorResources(out sockets, out cores, out mhz);

-                strtRouteCmd.cpus = cores;

-                strtRouteCmd.speed = mhz;

-                strtRouteCmd.cpuSockets = sockets;

-                ulong memoryKBs;

-                ulong freeMemoryKBs;

-                wmiCallsV2.GetMemoryResources(out memoryKBs, out freeMemoryKBs);

-                strtRouteCmd.memory = memoryKBs * 1024;   // Convert to bytes

-

-                // Need 2 Gig for DOM0, see http://technet.microsoft.com/en-us/magazine/hh750394.aspx

-                strtRouteCmd.dom0MinMemory = config.ParentPartitionMinMemoryMb * 1024 * 1024;  // Convert to bytes

-

-                // Insert storage pool details.

-                //

-                // Read the localStoragePath for virtual disks from the Hyper-V configuration

-                // See http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/05/06/managing-the-default-virtual-machine-location-with-hyper-v.aspx

-                // for discussion of Hyper-V file locations paths.

-                string localStoragePath = wmiCallsV2.GetDefaultVirtualDiskFolder();

-                if (localStoragePath != null)

-                {

-                    // GUID arbitrary.  Host agents deals with storage pool in terms of localStoragePath.

-                    // We use HOST guid.

-                    string poolGuid = strtRouteCmd.guid;

-

-                    if (poolGuid == null)

-                    {

-                        poolGuid = Guid.NewGuid().ToString();

-                        logger.InfoFormat("Setting Startup StoragePool GUID to " + poolGuid);

-                    }

-                    else

-                    {

-                        logger.InfoFormat("Setting Startup StoragePool GUID same as HOST, i.e. " + poolGuid);

-                    }

-

-                    long capacity;

-                    long available;

-                    GetCapacityForLocalPath(localStoragePath, out capacity, out available);

-

-                    logger.Debug(CloudStackTypes.StartupStorageCommand + " set available bytes to " + available);

-

-                    string ipAddr = strtRouteCmd.privateIpAddress;

-                    var vmStates = wmiCallsV2.GetVmSync(config.PrivateIpAddress);

-                    strtRouteCmd.vms = Utils.CreateCloudStackMapObject(vmStates);

-

-                    StoragePoolInfo pi = new StoragePoolInfo(

-                        poolGuid.ToString(),

-                        ipAddr,

-                        localStoragePath,

-                        localStoragePath,

-                        StoragePoolType.Filesystem.ToString(),

-                        capacity,

-                        available);

-

-                    // Build StartupStorageCommand using an anonymous type

-                    // See http://stackoverflow.com/a/6029228/939250

-                    object ansContent = new

-                    {

-                        poolInfo = pi,

-                        guid = pi.uuid,

-                        dataCenter = strtRouteCmd.dataCenter,

-                        resourceType = StorageResourceType.STORAGE_POOL.ToString(),  // TODO: check encoding

-                        contextMap = contextMap

-                    };

-                    JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.StartupStorageCommand, ansContent);

-                    cmdArray.Add(ansObj);

-                }

-

-                // Convert result to array for type correctness?

-                logger.Info(CloudStackTypes.StartupCommand + " result is " + cmdArray.ToString());

-                return cmdArray;

-            }

-        }

-

-        // POST api/HypervResource/GetVncPortCommand

-        [HttpPost]

-        [ActionName(CloudStackTypes.GetVncPortCommand)]

-        public JContainer GetVncPortCommand([FromBody]dynamic cmd)

-        {

-            using (log4net.NDC.Push(Guid.NewGuid().ToString()))

-            {

+                }
+
+                // Detect CPUs, speed, memory
+                uint cores;
+                uint mhz;
+                uint sockets;
+                wmiCallsV2.GetProcessorResources(out sockets, out cores, out mhz);
+                strtRouteCmd.cpus = cores;
+                strtRouteCmd.speed = mhz;
+                strtRouteCmd.cpuSockets = sockets;
+                ulong memoryKBs;
+                ulong freeMemoryKBs;
+                wmiCallsV2.GetMemoryResources(out memoryKBs, out freeMemoryKBs);
+                strtRouteCmd.memory = memoryKBs * 1024;   // Convert to bytes
+
+                // Need 2 Gig for DOM0, see http://technet.microsoft.com/en-us/magazine/hh750394.aspx
+                strtRouteCmd.dom0MinMemory = config.ParentPartitionMinMemoryMb * 1024 * 1024;  // Convert to bytes
+
+                // Insert storage pool details.
+                //
+                // Read the localStoragePath for virtual disks from the Hyper-V configuration
+                // See http://blogs.msdn.com/b/virtual_pc_guy/archive/2010/05/06/managing-the-default-virtual-machine-location-with-hyper-v.aspx
+                // for discussion of Hyper-V file locations paths.
+                string localStoragePath = wmiCallsV2.GetDefaultVirtualDiskFolder();
+                if (localStoragePath != null)
+                {
+                    // GUID arbitrary.  Host agents deals with storage pool in terms of localStoragePath.
+                    // We use HOST guid.
+                    string poolGuid = strtRouteCmd.guid;
+
+                    if (poolGuid == null)
+                    {
+                        poolGuid = Guid.NewGuid().ToString();
+                        logger.InfoFormat("Setting Startup StoragePool GUID to " + poolGuid);
+                    }
+                    else
+                    {
+                        logger.InfoFormat("Setting Startup StoragePool GUID same as HOST, i.e. " + poolGuid);
+                    }
+
+                    long capacity;
+                    long available;
+                    GetCapacityForLocalPath(localStoragePath, out capacity, out available);
+
+                    logger.Debug(CloudStackTypes.StartupStorageCommand + " set available bytes to " + available);
+
+                    string ipAddr = strtRouteCmd.privateIpAddress;
+                    var vmStates = wmiCallsV2.GetVmSync(config.PrivateIpAddress);
+                    strtRouteCmd.vms = Utils.CreateCloudStackMapObject(vmStates);
+
+                    StoragePoolInfo pi = new StoragePoolInfo(
+                        poolGuid.ToString(),
+                        ipAddr,
+                        localStoragePath,
+                        localStoragePath,
+                        StoragePoolType.Filesystem.ToString(),
+                        capacity,
+                        available);
+
+                    // Build StartupStorageCommand using an anonymous type
+                    // See http://stackoverflow.com/a/6029228/939250
+                    object ansContent = new
+                    {
+                        poolInfo = pi,
+                        guid = pi.uuid,
+                        dataCenter = strtRouteCmd.dataCenter,
+                        resourceType = StorageResourceType.STORAGE_POOL.ToString(),  // TODO: check encoding
+                        contextMap = contextMap
+                    };
+                    JObject ansObj = Utils.CreateCloudStackObject(CloudStackTypes.StartupStorageCommand, ansContent);
+                    cmdArray.Add(ansObj);
+                }
+
+                // Convert result to array for type correctness?
+                logger.Info(CloudStackTypes.StartupCommand + " result is " + cmdArray.ToString());
+                return cmdArray;
+            }
+        }
+
+        // POST api/HypervResource/GetVncPortCommand
+        [HttpPost]
+        [ActionName(CloudStackTypes.GetVncPortCommand)]
+        public JContainer GetVncPortCommand([FromBody]dynamic cmd)
+        {
+            using (log4net.NDC.Push(Guid.NewGuid().ToString()))
+            {
                 logger.Info(CloudStackTypes.GetVncPortCommand + Utils.CleanString(cmd.ToString()));
-

-                string details = null;

-                bool result = false;

-                string address = null;

-                int port = -9;

-

-                try

-                {

-                    string vmName = (string)cmd.name;

-                    var sys = wmiCallsV2.GetComputerSystem(vmName);

-                    address = "instanceId=" + sys.Name ;

-                    result = true;

-                }

-                catch (Exception sysEx)

-                {

-                    details = CloudStackTypes.GetVncPortAnswer + " failed due to " + sysEx.Message;

-                    logger.Error(details, sysEx);

-                }

-

-                object ansContent = new

-                {

-                    result = result,

-                    details = details,

-                    address = address,

-                    port = port

-                };

-

-                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVncPortAnswer);

-            }

-        }

-

+
+                string details = null;
+                bool result = false;
+                string address = null;
+                int port = -9;
+
+                try
+                {
+                    string vmName = (string)cmd.name;
+                    var sys = wmiCallsV2.GetComputerSystem(vmName);
+                    address = "instanceId=" + sys.Name ;
+                    result = true;
+                }
+                catch (Exception sysEx)
+                {
+                    details = CloudStackTypes.GetVncPortAnswer + " failed due to " + sysEx.Message;
+                    logger.Error(details, sysEx);
+                }
+
+                object ansContent = new
+                {
+                    result = result,
+                    details = details,
+                    address = address,
+                    port = port
+                };
+
+                return ReturnCloudStackTypedJArray(ansContent, CloudStackTypes.GetVncPortAnswer);
+            }
+        }
+
         // POST api/HypervResource/HostVmStateReportCommand
         [HttpPost]
         [ActionName(CloudStackTypes.HostVmStateReportCommand)]
@@ -2439,53 +2447,53 @@
             }
         }
 
-        public static System.Net.NetworkInformation.NetworkInterface GetNicInfoFromIpAddress(string ipAddress, out string subnet)

-        {

-            System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();

-            System.Net.NetworkInformation.NetworkInterface defaultnic = null;

-            foreach (var nic in nics)

-            {

-                subnet = null;

-                defaultnic = nic;

-                // TODO: use to remove NETMASK and MAC from the config file, and to validate the IPAddress.

-                var nicProps = nic.GetIPProperties();

-                bool found = false;

-                foreach (var addr in nicProps.UnicastAddresses)

-                {

-                    if (addr.Address.Equals(IPAddress.Parse(ipAddress)))

-                    {

-                        subnet = addr.IPv4Mask.ToString();

-                        found = true;

-                    }

-                }

-                if (!found)

-                {

-                    continue;

-                }

-                return nic;

-            }

-            var defaultSubnet = defaultnic.GetIPProperties().UnicastAddresses[0];

-            subnet = defaultSubnet.IPv4Mask.ToString();

-            return defaultnic;

-        }

-

-        public static void GetCapacityForLocalPath(string localStoragePath, out long capacityBytes, out long availableBytes)

-        {

-            // NB: DriveInfo does not work for remote folders (http://stackoverflow.com/q/1799984/939250)

-            // DriveInfo requires a driver letter...

-            string fullPath = Path.GetFullPath(localStoragePath);

-            System.IO.DriveInfo poolInfo = new System.IO.DriveInfo(fullPath);

-            capacityBytes = poolInfo.TotalSize;

-            availableBytes = poolInfo.AvailableFreeSpace;

-

-            // Don't allow all of the Root Device to be used for virtual disks

-            if (poolInfo.RootDirectory.Name.ToLower().Equals(config.RootDeviceName))

-            {

-                availableBytes -= config.RootDeviceReservedSpaceBytes;

-                availableBytes = availableBytes > 0 ? availableBytes : 0;

-                capacityBytes -= config.RootDeviceReservedSpaceBytes;

-                capacityBytes = capacityBytes > 0 ? capacityBytes : 0;

-            }

-        }

-    }

-}

+        public static System.Net.NetworkInformation.NetworkInterface GetNicInfoFromIpAddress(string ipAddress, out string subnet)
+        {
+            System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
+            System.Net.NetworkInformation.NetworkInterface defaultnic = null;
+            foreach (var nic in nics)
+            {
+                subnet = null;
+                defaultnic = nic;
+                // TODO: use to remove NETMASK and MAC from the config file, and to validate the IPAddress.
+                var nicProps = nic.GetIPProperties();
+                bool found = false;
+                foreach (var addr in nicProps.UnicastAddresses)
+                {
+                    if (addr.Address.Equals(IPAddress.Parse(ipAddress)))
+                    {
+                        subnet = addr.IPv4Mask.ToString();
+                        found = true;
+                    }
+                }
+                if (!found)
+                {
+                    continue;
+                }
+                return nic;
+            }
+            var defaultSubnet = defaultnic.GetIPProperties().UnicastAddresses[0];
+            subnet = defaultSubnet.IPv4Mask.ToString();
+            return defaultnic;
+        }
+
+        public static void GetCapacityForLocalPath(string localStoragePath, out long capacityBytes, out long availableBytes)
+        {
+            // NB: DriveInfo does not work for remote folders (http://stackoverflow.com/q/1799984/939250)
+            // DriveInfo requires a driver letter...
+            string fullPath = Path.GetFullPath(localStoragePath);
+            System.IO.DriveInfo poolInfo = new System.IO.DriveInfo(fullPath);
+            capacityBytes = poolInfo.TotalSize;
+            availableBytes = poolInfo.AvailableFreeSpace;
+
+            // Don't allow all of the Root Device to be used for virtual disks
+            if (poolInfo.RootDirectory.Name.ToLower().Equals(config.RootDeviceName))
+            {
+                availableBytes -= config.RootDeviceReservedSpaceBytes;
+                availableBytes = availableBytes > 0 ? availableBytes : 0;
+                capacityBytes -= config.RootDeviceReservedSpaceBytes;
+                capacityBytes = capacityBytes > 0 ? capacityBytes : 0;
+            }
+        }
+    }
+}
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
index c5e5bf3..0a64f4b 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/IWmiCallsV2.cs
@@ -1,76 +1,78 @@
-// Licensed to the Apache Software Foundation (ASF) under one

-// or more contributor license agreements.  See the NOTICE file

-// distributed with this work for additional information

-// regarding copyright ownership.  The ASF licenses this file

-// to you under the Apache License, Version 2.0 (the

-// "License"); you may not use this file except in compliance

-// with the License.  You may obtain a copy of the License at

-//

-//   http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing,

-// software distributed under the License is distributed on an

-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

-// KIND, either express or implied.  See the License for the

-// specific language governing permissions and limitations

-// under the License.

-

-using System;

-using System.Collections.Generic;

-using System.Linq;

-using System.Text;

-using System.Threading.Tasks;

-using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;

-using System.Management;

-

-namespace HypervResource

-{

-    public interface IWmiCallsV2

-    {

-        System.Management.ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType);

-        ComputerSystem AddUserData(ComputerSystem vm, string userData);

-        void AttachIso(string displayName, string iso);

-        void AttachDisk(string vmName, string diskPath, string addressOnController);

-        void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path);

-        SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac);

-        ComputerSystem CreateVM(string name, long memory_mb, int vcpus);

-        void DeleteHostKvpItem(ComputerSystem vm, string key);

-        void DeleteSwitchPort(string elementName);

-        ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso);

-        void DestroyVm(dynamic jsonObj);

-        void DestroyVm(string displayName);

-        void MigrateVm(string vmName, string destination);

-        void MigrateVolume(string vmName, string volume, string destination);

-        void MigrateVmWithVolume(string vmName, string destination, Dictionary<string, string> volumeToPool);

-        void DetachDisk(string displayName, string diskFileName);

-        ComputerSystem GetComputerSystem(string displayName);

+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;
+using System.Management;
+
+namespace HypervResource
+{
+    public interface IWmiCallsV2
+    {
+        System.Management.ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType);
+        ComputerSystem AddUserData(ComputerSystem vm, string userData);
+        void AttachIso(string displayName, string iso);
+        void AttachDisk(string vmName, string diskPath, string addressOnController);
+        void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path);
+        SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac);
+        ComputerSystem CreateVM(string name, long memory_mb, int vcpus);
+        void DeleteHostKvpItem(ComputerSystem vm, string key);
+        void DeleteSwitchPort(string elementName);
+        ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso);
+        void DestroyVm(dynamic jsonObj);
+        void DestroyVm(string displayName);
+        void MigrateVm(string vmName, string destination);
+        void MigrateVolume(string vmName, string volume, string destination);
+        void MigrateVmWithVolume(string vmName, string destination, Dictionary<string, string> volumeToPool);
+        void DetachDisk(string displayName, string diskFileName);
+        ComputerSystem GetComputerSystem(string displayName);
         ComputerSystem.ComputerSystemCollection GetComputerSystemCollection();
-        string GetDefaultDataRoot();

-        string GetDefaultVirtualDiskFolder();

-        ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings);

-        EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm);

-        SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm);

-        ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr);

-        ImageManagementService GetImageManagementService();

-        KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings);

-        void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs);

-        MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings);

-        void GetProcessorResources(out uint sockets, out uint cores, out uint mhz);

-        void GetProcessorUsageInfo(out double cpuUtilization);

-        ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings);

-        ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings);

-        void GetSummaryInfo(System.Collections.Generic.Dictionary<string, VmStatsEntry> vmProcessorInfo, System.Collections.Generic.List<System.Management.ManagementPath> vmsToInspect);

-        SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port);

-        VirtualSystemManagementService GetVirtualisationSystemManagementService();

-        VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService();

-        EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection);

-        System.Collections.Generic.List<string> GetVmElementNames();

-        VirtualSystemSettingData GetVmSettings(ComputerSystem vm);

-        void patchSystemVmIso(string vmName, string systemVmIso);

-        void SetState(ComputerSystem vm, ushort requiredState);

-        Dictionary<String, VmState> GetVmSync(String privateIpAddress);

+        string GetDefaultDataRoot();
+        string GetDefaultVirtualDiskFolder();
+        ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings);
+        EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm);
+        SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm);
+        ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr);
+        ImageManagementService GetImageManagementService();
+        KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings);
+        void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs);
+        MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings);
+        void GetProcessorResources(out uint sockets, out uint cores, out uint mhz);
+        void GetProcessorUsageInfo(out double cpuUtilization);
+        ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings);
+        ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings);
+        void GetSummaryInfo(System.Collections.Generic.Dictionary<string, VmStatsEntry> vmProcessorInfo, System.Collections.Generic.List<System.Management.ManagementPath> vmsToInspect);
+        SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port);
+        VirtualSystemManagementService GetVirtualisationSystemManagementService();
+        VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService();
+        EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection);
+        System.Collections.Generic.List<string> GetVmElementNames();
+        VirtualSystemSettingData GetVmSettings(ComputerSystem vm);
+        void patchSystemVmIso(string vmName, string systemVmIso);
+        void SetState(ComputerSystem vm, ushort requiredState);
+        Dictionary<String, VmState> GetVmSync(String privateIpAddress);
         string GetVmNote(System.Management.ManagementPath sysPath);
-        void ModifyVmVLan(string vmName, uint vlanid, string mac);
-        void ModifyVmVLan(string vmName, uint vlanid, uint pos);
-    }

-}

+        void ModifyVmVLan(string vmName, String vlanid, string mac);
+        void ModifyVmVLan(string vmName, String vlanid, uint pos, bool enable, string switchLabelName);
+        void DisableVmNics();
+        void DisableNicVlan(String mac, String vmName);
+    }
+}
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
index 4795073..d8dd3bb 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCallsV2.cs
@@ -1,262 +1,261 @@
-// Licensed to the Apache Software Foundation (ASF) under one

-// or more contributor license agreements.  See the NOTICE file

-// distributed with this work for additional information

-// regarding copyright ownership.  The ASF licenses this file

-// to you under the Apache License, Version 2.0 (the

-// "License"); you may not use this file except in compliance

-// with the License.  You may obtain a copy of the License at

-//

-//   http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing,

-// software distributed under the License is distributed on an

-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

-// KIND, either express or implied.  See the License for the

-// specific language governing permissions and limitations

-// under the License.

-using System;

-using System.Collections.Generic;

-using System.Linq;

-using System.Text;

-using System.Threading.Tasks;

-using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;

-using log4net;

-using System.Globalization;

-using System.Management;

-using Newtonsoft.Json;

-using Newtonsoft.Json.Linq;

-using CloudStack.Plugin.WmiWrappers.ROOT.CIMV2;

-using System.IO;

-using System.Net.NetworkInformation;

-using System.Net;

-

-namespace HypervResource

-{

-    public class WmiCallsV2 : IWmiCallsV2

-    {

-        public static String CloudStackUserDataKey = "cloudstack-vm-userdata";

-

-        /// <summary>

-        /// Defines the migration types.

-        /// </summary>

-        public enum MigrationType

-        {

-            VirtualSystem = 32768,

-            Storage = 32769,

-            Staged = 32770,

-            VirtualSystemAndStorage = 32771

-        };

-

-        /// <summary>

-        /// Defines migration transport types.

-        /// </summary>

-        public enum TransportType

-        {

-            TCP = 5,

-            SMB = 32768

-        };

-

-        public static void Initialize()

-        {

-            // Trigger assembly load into curren appdomain

-        }

-

-        private static ILog logger = LogManager.GetLogger(typeof(WmiCallsV2));

-

-        /// <summary>

-        /// Returns ping status of the given ip

-        /// </summary>

-        public static String PingHost(String ip)

-        {

-            return "Success";

-        }

-

-        /// <summary>

-        /// Returns ComputerSystem lacking any NICs and VOLUMEs

-        /// </summary>

-        public ComputerSystem AddUserData(ComputerSystem vm, string userData)

-        {

-            // Obtain controller for Hyper-V virtualisation subsystem

-            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();

-

-            // Create object to hold the data.

-            KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance();

-            kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey;

-            kvpItem.LateBoundObject["Data"] = userData;

-            kvpItem.LateBoundObject["Source"] = 0;

-            logger.Debug("VM " + vm.Name + " gets userdata " + userData);

-

-            // Update the resource settings for the VM.

-            System.Management.ManagementBaseObject kvpMgmtObj = kvpItem.LateBoundObject;

-            System.Management.ManagementPath jobPath;

-            String kvpStr = kvpMgmtObj.GetText(System.Management.TextFormat.CimDtd20);

-            uint ret_val = vmMgmtSvc.AddKvpItems(new String[] { kvpStr }, vm.Path, out jobPath);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return vm;

-        }

-		

-        /// <summary>

-        /// Returns ComputerSystem lacking any NICs and VOLUMEs

-        /// </summary>

-        public ComputerSystem CreateVM(string name, long memory_mb, int vcpus)

-        {

-            // Obtain controller for Hyper-V virtualisation subsystem

-            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();

-

-            // Create VM with correct name and default resources

-            ComputerSystem vm = CreateDefaultVm(vmMgmtSvc, name);

-

-            // Update the resource settings for the VM.

-

-            // Resource settings are referenced through the Msvm_VirtualSystemSettingData object.

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-

-            // For memory settings, there is no Dynamic Memory, so reservation, limit and quantity are identical.

-            MemorySettingData memSettings = GetMemSettings(vmSettings);

-            memSettings.LateBoundObject["VirtualQuantity"] = memory_mb;

-            memSettings.LateBoundObject["Reservation"] = memory_mb;

-            memSettings.LateBoundObject["Limit"] = memory_mb;

-

-            // Update the processor settings for the VM, static assignment of 100% for CPU limit

-            ProcessorSettingData procSettings = GetProcSettings(vmSettings);

-            procSettings.LateBoundObject["VirtualQuantity"] = vcpus;

-            procSettings.LateBoundObject["Reservation"] = vcpus;

-            procSettings.LateBoundObject["Limit"] = 100000;

-

-            ModifyVmResources(vmMgmtSvc, vm, new String[] {

-                memSettings.LateBoundObject.GetText(TextFormat.CimDtd20),

-                procSettings.LateBoundObject.GetText(TextFormat.CimDtd20)

-                });

-            logger.InfoFormat("VM with display name {0} has GUID {1}", vm.ElementName, vm.Name);

-            logger.DebugFormat("Resources for vm {0}: {1} MB memory, {2} vcpus", name, memory_mb, vcpus);

-

-            return vm;

-        }

-

-        /// <summary>

-        /// Create a (synthetic) nic, and attach it to the vm

-        /// </summary>

-        /// <param name="vm"></param>

-        /// <param name="mac"></param>

-        /// <param name="vlan"></param>

-        /// <returns></returns>

-        public SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac)

-        {

-            logger.DebugFormat("Creating nic for VM {0} (GUID {1})", vm.ElementName, vm.Name);

-

-            // Obtain controller for Hyper-V networking subsystem

-            var vmNetMgmtSvc = GetVirtualSwitchManagementService();

-

-            // Create NIC resource by cloning the default NIC 

-            var synthNICsSettings = SyntheticEthernetPortSettingData.GetInstances(vmNetMgmtSvc.Scope, "InstanceID LIKE \"%Default\"");

-

-            // Assert

-            if (synthNICsSettings.Count != 1)

-            {

-                var errMsg = string.Format("Internal error, coudl not find default SyntheticEthernetPort instance");

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            var defaultSynthNICSettings = synthNICsSettings.OfType<SyntheticEthernetPortSettingData>().First();

-

-            var newSynthNICSettings = new SyntheticEthernetPortSettingData((ManagementBaseObject)defaultSynthNICSettings.LateBoundObject.Clone());

-

-            //  Assign configuration to new NIC

-            string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));

-            newSynthNICSettings.LateBoundObject["ElementName"] = vm.ElementName;

-            newSynthNICSettings.LateBoundObject["Address"] = normalisedMAC;

-            newSynthNICSettings.LateBoundObject["StaticMacAddress"] = "TRUE";

-            newSynthNICSettings.LateBoundObject["VirtualSystemIdentifiers"] = new string[] { "{" + Guid.NewGuid().ToString() + "}" };

-            newSynthNICSettings.CommitObject();

-

-            // Insert NIC into vm

-            string[] newResources = new string[] { newSynthNICSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20)};

-            ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm );

-

-            // assert

-            if (newResourcePaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    newResourcePaths.Length);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return new SyntheticEthernetPortSettingData(newResourcePaths[0]);

-        }

-

-        public const string IDE_CONTROLLER = "Microsoft:Hyper-V:Emulated IDE Controller";

-        public const string SCSI_CONTROLLER = "Microsoft:Hyper-V:Synthetic SCSI Controller";

-        public const string HARDDISK_DRIVE = "Microsoft:Hyper-V:Synthetic Disk Drive";

-        public const string ISO_DRIVE = "Microsoft:Hyper-V:Synthetic DVD Drive";

-

-        // TODO: names harvested from Msvm_ResourcePool, not clear how to create new instances

-        public const string ISO_DISK = "Microsoft:Hyper-V:Virtual CD/DVD Disk"; // For IDE_ISO_DRIVE

-        public const string HARDDISK_DISK = "Microsoft:Hyper-V:Virtual Hard Disk"; // For IDE_HARDDISK_DRIVE

-

-        /// <summary>

-        /// Create new VM.  By default we start it. 

-        /// </summary>

-        public ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso)

-        {

-            var vmInfo = jsonObj.vm;

-            string vmName = vmInfo.name;

-            var nicInfo = vmInfo.nics;

-            int vcpus = vmInfo.cpus;

-            int memSize = vmInfo.maxRam / 1048576;

-            string errMsg = vmName;

-            var diskDrives = vmInfo.disks;

-            var bootArgs = vmInfo.bootArgs;

-            string defaultvlan = "4094"; 

-

-            // assert

-            errMsg = vmName + ": missing disk information, array empty or missing, agent expects *at least* one disk for a VM";

-            if (diskDrives == null)

-            {

-                logger.Error(errMsg);

-                throw new ArgumentException(errMsg);

-            }

-            // assert

-            errMsg = vmName + ": missing NIC information, array empty or missing, agent expects at least an empty array.";

-            if (nicInfo == null )

-            {

-                logger.Error(errMsg);

-                throw new ArgumentException(errMsg);

-            }

-

-

-            // For existing VMs, return when we spot one of this name not stopped.  In the meantime, remove any existing VMs of same name.

-            ComputerSystem vmWmiObj = null;

-            while ((vmWmiObj = GetComputerSystem(vmName)) != null)

-            {

-                logger.WarnFormat("Create request for existing vm, name {0}", vmName);

-                if (vmWmiObj.EnabledState == EnabledState.Disabled)

-                {

-                    logger.InfoFormat("Deleting existing VM with name {0}, before we go on to create a VM with the same name", vmName);

-                    DestroyVm(vmName);

-                }

+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using CloudStack.Plugin.WmiWrappers.ROOT.VIRTUALIZATION.V2;
+using log4net;
+using System.Globalization;
+using System.Management;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using CloudStack.Plugin.WmiWrappers.ROOT.CIMV2;
+using System.IO;
+using System.Net.NetworkInformation;
+using System.Net;
+
+namespace HypervResource
+{
+    public class WmiCallsV2 : IWmiCallsV2
+    {
+        public static String CloudStackUserDataKey = "cloudstack-vm-userdata";
+
+        /// <summary>
+        /// Defines the migration types.
+        /// </summary>
+        public enum MigrationType
+        {
+            VirtualSystem = 32768,
+            Storage = 32769,
+            Staged = 32770,
+            VirtualSystemAndStorage = 32771
+        };
+
+        /// <summary>
+        /// Defines migration transport types.
+        /// </summary>
+        public enum TransportType
+        {
+            TCP = 5,
+            SMB = 32768
+        };
+
+        public static void Initialize()
+        {
+            // Trigger assembly load into curren appdomain
+        }
+
+        private static ILog logger = LogManager.GetLogger(typeof(WmiCallsV2));
+
+        /// <summary>
+        /// Returns ping status of the given ip
+        /// </summary>
+        public static String PingHost(String ip)
+        {
+            return "Success";
+        }
+
+        /// <summary>
+        /// Returns ComputerSystem lacking any NICs and VOLUMEs
+        /// </summary>
+        public ComputerSystem AddUserData(ComputerSystem vm, string userData)
+        {
+            // Obtain controller for Hyper-V virtualisation subsystem
+            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
+
+            // Create object to hold the data.
+            KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance();
+            kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey;
+            kvpItem.LateBoundObject["Data"] = userData;
+            kvpItem.LateBoundObject["Source"] = 0;
+            logger.Debug("VM " + vm.Name + " gets userdata " + userData);
+
+            // Update the resource settings for the VM.
+            System.Management.ManagementBaseObject kvpMgmtObj = kvpItem.LateBoundObject;
+            System.Management.ManagementPath jobPath;
+            String kvpStr = kvpMgmtObj.GetText(System.Management.TextFormat.CimDtd20);
+            uint ret_val = vmMgmtSvc.AddKvpItems(new String[] { kvpStr }, vm.Path, out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return vm;
+        }
+		
+        /// <summary>
+        /// Returns ComputerSystem lacking any NICs and VOLUMEs
+        /// </summary>
+        public ComputerSystem CreateVM(string name, long memory_mb, int vcpus)
+        {
+            // Obtain controller for Hyper-V virtualisation subsystem
+            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
+
+            // Create VM with correct name and default resources
+            ComputerSystem vm = CreateDefaultVm(vmMgmtSvc, name);
+
+            // Update the resource settings for the VM.
+
+            // Resource settings are referenced through the Msvm_VirtualSystemSettingData object.
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+
+            // For memory settings, there is no Dynamic Memory, so reservation, limit and quantity are identical.
+            MemorySettingData memSettings = GetMemSettings(vmSettings);
+            memSettings.LateBoundObject["VirtualQuantity"] = memory_mb;
+            memSettings.LateBoundObject["Reservation"] = memory_mb;
+            memSettings.LateBoundObject["Limit"] = memory_mb;
+
+            // Update the processor settings for the VM, static assignment of 100% for CPU limit
+            ProcessorSettingData procSettings = GetProcSettings(vmSettings);
+            procSettings.LateBoundObject["VirtualQuantity"] = vcpus;
+            procSettings.LateBoundObject["Reservation"] = vcpus;
+            procSettings.LateBoundObject["Limit"] = 100000;
+
+            ModifyVmResources(vmMgmtSvc, vm, new String[] {
+                memSettings.LateBoundObject.GetText(TextFormat.CimDtd20),
+                procSettings.LateBoundObject.GetText(TextFormat.CimDtd20)
+                });
+            logger.InfoFormat("VM with display name {0} has GUID {1}", vm.ElementName, vm.Name);
+            logger.DebugFormat("Resources for vm {0}: {1} MB memory, {2} vcpus", name, memory_mb, vcpus);
+
+            return vm;
+        }
+
+        /// <summary>
+        /// Create a (synthetic) nic, and attach it to the vm
+        /// </summary>
+        /// <param name="vm"></param>
+        /// <param name="mac"></param>
+        /// <param name="vlan"></param>
+        /// <returns></returns>
+        public SyntheticEthernetPortSettingData CreateNICforVm(ComputerSystem vm, string mac)
+        {
+            logger.DebugFormat("Creating nic for VM {0} (GUID {1})", vm.ElementName, vm.Name);
+
+            // Obtain controller for Hyper-V networking subsystem
+            var vmNetMgmtSvc = GetVirtualSwitchManagementService();
+
+            // Create NIC resource by cloning the default NIC 
+            var synthNICsSettings = SyntheticEthernetPortSettingData.GetInstances(vmNetMgmtSvc.Scope, "InstanceID LIKE \"%Default\"");
+
+            // Assert
+            if (synthNICsSettings.Count != 1)
+            {
+                var errMsg = string.Format("Internal error, coudl not find default SyntheticEthernetPort instance");
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            var defaultSynthNICSettings = synthNICsSettings.OfType<SyntheticEthernetPortSettingData>().First();
+
+            var newSynthNICSettings = new SyntheticEthernetPortSettingData((ManagementBaseObject)defaultSynthNICSettings.LateBoundObject.Clone());
+
+            //  Assign configuration to new NIC
+            string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));
+            newSynthNICSettings.LateBoundObject["ElementName"] = vm.ElementName;
+            newSynthNICSettings.LateBoundObject["Address"] = normalisedMAC;
+            newSynthNICSettings.LateBoundObject["StaticMacAddress"] = "TRUE";
+            newSynthNICSettings.LateBoundObject["VirtualSystemIdentifiers"] = new string[] { "{" + Guid.NewGuid().ToString() + "}" };
+            newSynthNICSettings.CommitObject();
+
+            // Insert NIC into vm
+            string[] newResources = new string[] { newSynthNICSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20)};
+            ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm );
+
+            // assert
+            if (newResourcePaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    newResourcePaths.Length);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return new SyntheticEthernetPortSettingData(newResourcePaths[0]);
+        }
+
+        public const string IDE_CONTROLLER = "Microsoft:Hyper-V:Emulated IDE Controller";
+        public const string SCSI_CONTROLLER = "Microsoft:Hyper-V:Synthetic SCSI Controller";
+        public const string HARDDISK_DRIVE = "Microsoft:Hyper-V:Synthetic Disk Drive";
+        public const string ISO_DRIVE = "Microsoft:Hyper-V:Synthetic DVD Drive";
+
+        // TODO: names harvested from Msvm_ResourcePool, not clear how to create new instances
+        public const string ISO_DISK = "Microsoft:Hyper-V:Virtual CD/DVD Disk"; // For IDE_ISO_DRIVE
+        public const string HARDDISK_DISK = "Microsoft:Hyper-V:Virtual Hard Disk"; // For IDE_HARDDISK_DRIVE
+
+        /// <summary>
+        /// Create new VM.  By default we start it. 
+        /// </summary>
+        public ComputerSystem DeployVirtualMachine(dynamic jsonObj, string systemVmIso)
+        {
+            var vmInfo = jsonObj.vm;
+            string vmName = vmInfo.name;
+            var nicInfo = vmInfo.nics;
+            int vcpus = vmInfo.cpus;
+            int memSize = vmInfo.maxRam / 1048576;
+            string errMsg = vmName;
+            var diskDrives = vmInfo.disks;
+            var bootArgs = vmInfo.bootArgs;
+
+            // assert
+            errMsg = vmName + ": missing disk information, array empty or missing, agent expects *at least* one disk for a VM";
+            if (diskDrives == null)
+            {
+                logger.Error(errMsg);
+                throw new ArgumentException(errMsg);
+            }
+            // assert
+            errMsg = vmName + ": missing NIC information, array empty or missing, agent expects at least an empty array.";
+            if (nicInfo == null )
+            {
+                logger.Error(errMsg);
+                throw new ArgumentException(errMsg);
+            }
+
+
+            // For existing VMs, return when we spot one of this name not stopped.  In the meantime, remove any existing VMs of same name.
+            ComputerSystem vmWmiObj = null;
+            while ((vmWmiObj = GetComputerSystem(vmName)) != null)
+            {
+                logger.WarnFormat("Create request for existing vm, name {0}", vmName);
+                if (vmWmiObj.EnabledState == EnabledState.Disabled)
+                {
+                    logger.InfoFormat("Deleting existing VM with name {0}, before we go on to create a VM with the same name", vmName);
+                    DestroyVm(vmName);
+                }
                 else if (vmWmiObj.EnabledState == EnabledState.Enabled)
                 {
                     string infoMsg = string.Format("Create VM discovered there exists a VM with name {0}, state {1}",
@@ -265,672 +264,755 @@
                     logger.Info(infoMsg);
                     return vmWmiObj;
                 }
-                else

-                {

+                else
+                {
                     errMsg = string.Format("Create VM failing, because there exists a VM with name {0}, state {1}",
-                        vmName,

-                        EnabledState.ToString(vmWmiObj.EnabledState));

-                    var ex = new WmiException(errMsg);

-                    logger.Error(errMsg, ex);

-                    throw ex;

-                }

-            }

-

-            // Create vm carcase

-            logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize);

-            var newVm = CreateVM(vmName, memSize, vcpus);

-

-            // Add a SCSI controller for attaching/detaching data volumes.

-            AddScsiController(newVm);

-

-            foreach (var diskDrive in diskDrives)

-            {

-                string vhdFile = null;

-                string diskName = null;

-                string isoPath = null;

-                VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data);

-                TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data);

-

-                if (volInfo != null)

-                {

-                    // assert

-                    errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString();

-                    if (volInfo.primaryDataStore == null)

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-                    diskName = volInfo.name;

-

-                    // assert

-                    errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString();

-                    if (volInfo.primaryDataStore == null)

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-                    errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString();

-                    if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path))

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-                    errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " +  volInfo.primaryDataStore.Path;

-                    if (!Directory.Exists(volInfo.primaryDataStore.Path))

-                    {

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-

-                    vhdFile = volInfo.FullFileName;

-                    if (!System.IO.File.Exists(vhdFile))

-                    {

-                        errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString();

-                        logger.Error(errMsg);

-                        throw new ArgumentException(errMsg);

-                    }

-                    logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile);

-                }

-                else if (templateInfo != null && templateInfo.nfsDataStoreTO != null)

-                {

-                    NFSTO share = templateInfo.nfsDataStoreTO;

-                    Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);

-                    // The share is mapped, now attach the iso

-                    isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path));

-                }

-

-                string driveType = diskDrive.type;

-                string ideCtrllr = "0";

-                string driveResourceType = null;

-                switch (driveType) {

-                    case "ROOT":

-                        ideCtrllr = "0";

-                        driveResourceType = HARDDISK_DRIVE;

-                        break;

-                    case "ISO":

-                        ideCtrllr = "1";

-                        driveResourceType = ISO_DRIVE;

-                        break;

-                    case "DATADISK":

-                        break;

-                    default: 

-                        // TODO: double check exception type

-                        errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", 

-                                string.IsNullOrEmpty(driveType) ? "NULL" : driveType,

-                                string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName);

-                        var ex = new WmiException(errMsg);

-                        logger.Error(errMsg, ex);

-                        throw ex;

-                }

-

-                logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName,

-                        string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile);

-                if (driveType.Equals("DATADISK"))

-                {

-                    AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq);

-                }

-                else

-                {

-                    AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType);

-                    if (isoPath != null)

-                    {

-                        AttachIso(vmName, isoPath);

-                    }

-                }

-            }

-

-            String publicIpAddress = "";

-            int nicCount = 0;

-            // Add the Nics to the VM in the deviceId order.

-            foreach (var nc in nicInfo)

-            {

-                foreach (var nic in nicInfo)

-                {

-

-                    int nicid = nic.deviceId;

+                        vmName,
+                        EnabledState.ToString(vmWmiObj.EnabledState));
+                    var ex = new WmiException(errMsg);
+                    logger.Error(errMsg, ex);
+                    throw ex;
+                }
+            }
+
+            // Create vm carcase
+            logger.DebugFormat("Going ahead with create VM {0}, {1} vcpus, {2}MB RAM", vmName, vcpus, memSize);
+            var newVm = CreateVM(vmName, memSize, vcpus);
+
+            // Add a SCSI controller for attaching/detaching data volumes.
+            AddScsiController(newVm);
+
+            foreach (var diskDrive in diskDrives)
+            {
+                string vhdFile = null;
+                string diskName = null;
+                string isoPath = null;
+                VolumeObjectTO volInfo = VolumeObjectTO.ParseJson(diskDrive.data);
+                TemplateObjectTO templateInfo = TemplateObjectTO.ParseJson(diskDrive.data);
+
+                if (volInfo != null)
+                {
+                    // assert
+                    errMsg = vmName + ": volume missing primaryDataStore for disk " + diskDrive.ToString();
+                    if (volInfo.primaryDataStore == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    diskName = volInfo.name;
+
+                    // assert
+                    errMsg = vmName + ": can't deal with DataStore type for disk " + diskDrive.ToString();
+                    if (volInfo.primaryDataStore == null)
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    errMsg = vmName + ": Malformed PrimaryDataStore for disk " + diskDrive.ToString();
+                    if (String.IsNullOrEmpty(volInfo.primaryDataStore.Path))
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    errMsg = vmName + ": Missing folder PrimaryDataStore for disk " + diskDrive.ToString() + ", missing path: " +  volInfo.primaryDataStore.Path;
+                    if (!Directory.Exists(volInfo.primaryDataStore.Path))
+                    {
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+
+                    vhdFile = volInfo.FullFileName;
+                    if (!System.IO.File.Exists(vhdFile))
+                    {
+                        errMsg = vmName + ": non-existent volume, missing " + vhdFile + " for drive " + diskDrive.ToString();
+                        logger.Error(errMsg);
+                        throw new ArgumentException(errMsg);
+                    }
+                    logger.Debug("Going to create " + vmName + " with attached voluem " + diskName + " at " + vhdFile);
+                }
+                else if (templateInfo != null && templateInfo.nfsDataStoreTO != null)
+                {
+                    NFSTO share = templateInfo.nfsDataStoreTO;
+                    Utils.ConnectToRemote(share.UncPath, share.Domain, share.User, share.Password);
+                    // The share is mapped, now attach the iso
+                    isoPath = Utils.NormalizePath(Path.Combine(share.UncPath, templateInfo.path));
+                }
+
+                string driveType = diskDrive.type;
+                string ideCtrllr = "0";
+                string driveResourceType = null;
+                switch (driveType) {
+                    case "ROOT":
+                        ideCtrllr = "0";
+                        driveResourceType = HARDDISK_DRIVE;
+                        break;
+                    case "ISO":
+                        ideCtrllr = "1";
+                        driveResourceType = ISO_DRIVE;
+                        break;
+                    case "DATADISK":
+                        break;
+                    default: 
+                        // TODO: double check exception type
+                        errMsg = string.Format("Unknown disk type {0} for disk {1}, vm named {2}", 
+                                string.IsNullOrEmpty(driveType) ? "NULL" : driveType,
+                                string.IsNullOrEmpty(diskName) ? "NULL" : diskName, vmName);
+                        var ex = new WmiException(errMsg);
+                        logger.Error(errMsg, ex);
+                        throw ex;
+                }
+
+                logger.DebugFormat("Create disk type {1} (Named: {0}), on vm {2} {3}", diskName, driveResourceType, vmName,
+                        string.IsNullOrEmpty(vhdFile) ? " no disk to insert" : ", inserting disk" + vhdFile);
+                if (driveType.Equals("DATADISK"))
+                {
+                    AttachDisk(vmName, vhdFile, (string)diskDrive.diskSeq);
+                }
+                else
+                {
+                    AddDiskDriveToIdeController(newVm, vhdFile, ideCtrllr, driveResourceType);
+                    if (isoPath != null)
+                    {
+                        AttachIso(vmName, isoPath);
+                    }
+                }
+            }
+
+            String publicIpAddress = "";
+            int nicCount = 0;
+            int enableState = 2;
+
+            // Add the Nics to the VM in the deviceId order.
+            foreach (var nc in nicInfo)
+            {
+                foreach (var nic in nicInfo)
+                {
+
+                    int nicid = nic.deviceId;
                     Int32 networkRateMbps = nic.networkRateMbps;
-                    string mac = nic.mac;

-                    string vlan = null;

-                    string isolationUri = nic.isolationUri;

-                    string broadcastUri = nic.broadcastUri;

+                    string mac = nic.mac;
+                    string vlan = null;
+                    string isolationUri = nic.isolationUri;
+                    string broadcastUri = nic.broadcastUri;
                     string nicIp = nic.ip;
                     string nicNetmask = nic.netmask;
-                    if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://")))

-                    {

-                        if (broadcastUri != null && broadcastUri.StartsWith("storage"))

-                        {

-                            vlan = broadcastUri.Substring("storage://".Length);

-                        }

-                        else

-                        {

-                            vlan = isolationUri.Substring("vlan://".Length);

-                        }

-                        int tmp;

+                    if ( (broadcastUri != null ) || (isolationUri != null && isolationUri.StartsWith("vlan://")))
+                    {
+                        if (broadcastUri != null && broadcastUri.StartsWith("storage"))
+                        {
+                            vlan = broadcastUri.Substring("storage://".Length);
+                        }
+                        else
+                        {
+                            vlan = isolationUri.Substring("vlan://".Length);
+                        }
+                        int tmp;
                         if (vlan.Equals("untagged", StringComparison.CurrentCultureIgnoreCase) ) {
                             // recevied vlan is untagged, don't parse for the vlan in the isolation uri
                             vlan = null;
                         }
-                        else if (!int.TryParse(vlan, out tmp))

-                        {

-                            // TODO: double check exception type

-                            errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid);

-                            var ex = new WmiException(errMsg);

-                            logger.Error(errMsg, ex);

-                            throw ex;

-                        }

-                    }

-                    if(nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255") ) {
-                        // this is the extra nic added to VR.
-                        vlan = defaultvlan;
+                        else if (!int.TryParse(vlan, out tmp))
+                        {
+                            // TODO: double check exception type
+                            errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid);
+                            var ex = new WmiException(errMsg);
+                            logger.Error(errMsg, ex);
+                            throw ex;
+                        }
                     }
-

-                    if (nicCount == 2)

-                    {

-                         publicIpAddress = nic.ip;

-                    }

-

-                    if (nicid == nicCount)

-                    {

-                        // Create network adapter

-                        var newAdapter = CreateNICforVm(newVm, mac);

-                        String switchName ="";

-                        if (nic.name != null)

-                        {

-                            switchName =  nic.name;

-                        }

-

-                        // connection to vswitch

-                        var portSettings = AttachNicToPort(newVm, newAdapter, switchName);

-

-                        // set vlan

-                        if (vlan != null)

-                        {

-                            SetPortVlan(vlan, portSettings);

-                        }

-

+
+                    if (nicid == nicCount)
+                    {
+                        if (nicIp.Equals("0.0.0.0") && nicNetmask.Equals("255.255.255.255"))
+                        {
+                            // this is the extra nic added to VR.
+                            vlan = null;
+                            enableState = 3;
+                        }
+
+                        // Create network adapter
+                        var newAdapter = CreateNICforVm(newVm, mac);
+                        String switchName ="";
+                        if (nic.name != null)
+                        {
+                            switchName =  nic.name;
+                        }
+                        EthernetPortAllocationSettingData portSettings = null;
+                        // connection to vswitch
+                        portSettings = AttachNicToPort(newVm, newAdapter, switchName, enableState);
+                        //reset the flag for other nics
+                        enableState = 2;
+                        // set vlan
+                        if (vlan != null)
+                        {
+                            SetPortVlan(vlan, portSettings);
+                        }
+
                         if (networkRateMbps > 0)
                         {
                             SetBandWidthLimit((ulong)networkRateMbps, portSettings);
                         }
 
-                        logger.DebugFormat("Created adapter {0} on port {1}, {2}", 

-                            newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan));

-                    }

-                }

-                nicCount++;

-            }

-

+                        logger.DebugFormat("Created adapter {0} on port {1}, {2}", 
+                            newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan));
+                     //   logger.DebugFormat("Created adapter {0} on port {1}, {2}", 
+                    //       newAdapter.Path, portSettings.Path, (vlan == null ? "No VLAN" : "VLAN " + vlan));
+                    }
+                }
+                nicCount++;
+            }
 
-            // pass the boot args for the VM using KVP component.

-            // We need to pass the boot args to system vm's to get them configured with cloudstack configuration.

-            // Add new user data

-            var vm = GetComputerSystem(vmName);

-            if (bootArgs != null && !String.IsNullOrEmpty((string)bootArgs))

-            {

-               

-                String bootargs = bootArgs;

-                AddUserData(vm, bootargs);

-

-                // Verify key added to subsystem

-                //kvpInfo = GetKvpSettings(vmSettings);

-

-                // HostExchangesItems are embedded objects in the sense that the object value is stored and not a reference to the object.

-                //kvpProps = kvpInfo.HostExchangeItems;

-

-            }

-            // call patch systemvm iso only for systemvms

-            if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))

-            {

-                if (systemVmIso != null && systemVmIso.Length != 0)

-                {

-                    patchSystemVmIso(vmName, systemVmIso);

-                }

-            }

-

-            logger.DebugFormat("Starting VM {0}", vmName);

-            SetState(newVm, RequiredState.Enabled);

+
+            // pass the boot args for the VM using KVP component.
+            // We need to pass the boot args to system vm's to get them configured with cloudstack configuration.
+            // Add new user data
+            var vm = GetComputerSystem(vmName);
+            if (bootArgs != null && !String.IsNullOrEmpty((string)bootArgs))
+            {
+               
+                String bootargs = bootArgs;
+                AddUserData(vm, bootargs);
+            }
+
+            // call patch systemvm iso only for systemvms
+            if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))
+            {
+                if (systemVmIso != null && systemVmIso.Length != 0)
+                {
+                    patchSystemVmIso(vmName, systemVmIso);
+                }
+            }
+
+            logger.DebugFormat("Starting VM {0}", vmName);
+            SetState(newVm, RequiredState.Enabled);
             // Mark the VM as created by cloudstack tag
             TagVm(newVm);
-

-            // we need to reboot to get the hv kvp daemon get started vr gets configured.

-            if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))

-            {

-                System.Threading.Thread.Sleep(90000);

-                // wait for the second boot and then return with sucesss

-                //if publicIPAddress is empty or null don't ping the ip

-              /*if (publicIpAddress.Equals("") == true)

-                {

-                    System.Threading.Thread.Sleep(90000);

-                }

-                else

-                {

-                    pingResource(publicIpAddress);

-                }*/

-            }

-            logger.InfoFormat("Started VM {0}", vmName);

-            return newVm;

-        }

-

-        public static Boolean pingResource(String ip)

-        {

-            PingOptions pingOptions = null;

-            PingReply pingReply = null;

-            IPAddress ipAddress = null;

-            Ping pingSender = new Ping();

-            int numberOfPings = 6;

-            int pingTimeout = 1000;

-            int byteSize = 32;

-            byte[] buffer = new byte[byteSize];

-            ipAddress = IPAddress.Parse(ip);

-            pingOptions = new PingOptions();

-            for (int i = 0; i < numberOfPings; i++)

-            {

-                pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions);

-                if (pingReply.Status == IPStatus.Success)

-                {

-                    System.Threading.Thread.Sleep(30000);

-                    return true;

-                }

-                else

-                {

-                    // wait for the second boot and then return with suces

-                    System.Threading.Thread.Sleep(30000);

-                }

-            }

-            return false;

-        }

-

-        private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName)

-        {

-            // Get the virtual switch

-            VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName);

-            //check the the recevied vSwitch is the same as vSwitchName.

-            if (!vSwitchName.Equals("")  && !vSwitch.ElementName.Equals(vSwitchName))

-            {

-               var errMsg = string.Format("Internal error, coudl not find Virtual Switch with the name : " +vSwitchName);

-               var ex = new WmiException(errMsg);

-               logger.Error(errMsg, ex);

-               throw ex;

-            }

-

-            // Create port for adapter

-            var defaultEthernetPortSettings = EthernetPortAllocationSettingData.GetInstances(vSwitch.Scope, "InstanceID LIKE \"%Default\"");

-

-            // assert

-            if (defaultEthernetPortSettings.Count != 1)

-            {

-                var errMsg = string.Format("Internal error, coudl not find default EthernetPortAllocationSettingData instance");

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            var defaultEthernetPortSettingsObj = defaultEthernetPortSettings.OfType<EthernetPortAllocationSettingData>().First();

-            var newEthernetPortSettings = new EthernetPortAllocationSettingData((ManagementBaseObject)defaultEthernetPortSettingsObj.LateBoundObject.Clone());

-            newEthernetPortSettings.LateBoundObject["Parent"] = newAdapter.Path.Path;

-            newEthernetPortSettings.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path };

-

-            // Insert NIC into vm

-            string[] newResources = new string[] { newEthernetPortSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };

-            ManagementPath[] newResourcePaths = AddVirtualResource(newResources, newVm);

-

-            // assert

-            if (newResourcePaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}",

-                    newVm.ElementName,

-                    newVm.Name,

-                    newResourcePaths.Length);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return new EthernetPortAllocationSettingData(newResourcePaths[0]);

-        }

-

-        /// this method is to add a dvd drive and attach the systemvm iso.

-        /// 

-        public void patchSystemVmIso(String vmName, String systemVmIso)

-        {

-            ComputerSystem vmObject = GetComputerSystem(vmName);

-            AddDiskDriveToIdeController(vmObject, "", "1", ISO_DRIVE);

-            AttachIso(vmName, systemVmIso);

-        }

-

-        public void AttachDisk(string vmName, string diskPath, string addressOnController)

-        {

-            logger.DebugFormat("Got request to attach disk {0} to vm {1}", diskPath, vmName);

-

-            ComputerSystem vm = GetComputerSystem(vmName);

-            if (vm == null)

-            {

-                logger.DebugFormat("VM {0} not found", vmName);

-                return;

-            }

-            else

-            {

-                ManagementPath newDrivePath = GetDiskDriveOnScsiController(vm, addressOnController);

-                if (newDrivePath == null)

-                {

-                    newDrivePath = AttachDiskDriveToScsiController(vm, addressOnController);

-                }

-                InsertDiskImage(vm, diskPath, HARDDISK_DISK, newDrivePath);

-            }

-        }

-

-        /// </summary>

-        /// <param name="vm"></param>

-        /// <param name="cntrllerAddr"></param>

-        /// <param name="driveResourceType">IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE</param>

-        public ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType)

-        {

-            logger.DebugFormat("Creating DISK for VM {0} (GUID {1}) by attaching {2}", 

-                        vm.ElementName,

-                        vm.Name,

-                        vhdfile);

-

-            // Determine disk type for drive and assert drive type valid

-            string diskResourceSubType = null;

-            switch(driveResourceType) {

-                case HARDDISK_DRIVE:

-                    diskResourceSubType = HARDDISK_DISK;

-                    break;

-                case ISO_DRIVE: 

-                    diskResourceSubType = ISO_DISK;

-                    break;

-                default:

-                    var errMsg = string.Format(

-                        "Unrecognised disk drive type {0} for VM {1} (GUID {2})",

-                        string.IsNullOrEmpty(driveResourceType) ? "NULL": driveResourceType, 

-                        vm.ElementName,

-                        vm.Name);

-                    var ex = new WmiException(errMsg);

-                    logger.Error(errMsg, ex);

-                    throw ex;

-            }

-

-            ManagementPath newDrivePath = AttachNewDrive(vm, cntrllerAddr, driveResourceType);

-

-            // If there's not disk to insert, we are done.

-            if (String.IsNullOrEmpty(vhdfile))

-            {

-                logger.DebugFormat("No disk to be added to drive, disk drive {0} is complete", newDrivePath.Path);

-            }

-            else

-            {

-                InsertDiskImage(vm, vhdfile, diskResourceSubType, newDrivePath);

-            }

-            return newDrivePath;

-        }

-

-

-        public void DetachDisk(string displayName, string diskFileName)

-        {

-            logger.DebugFormat("Got request to detach virtual disk {0} from vm {1}", diskFileName, displayName);

-

-            ComputerSystem vm = GetComputerSystem(displayName);

-            if (vm == null)

-            {

-                logger.DebugFormat("VM {0} not found", displayName);

-                return;

-            }

-            else

-            {

-                RemoveStorageImage(vm, diskFileName);

-            }

-        }

-

-        /// <summary>

-        /// Removes a disk image from a drive, but does not remove the drive itself.

-        /// </summary>

-        /// <param name="vm"></param>

-        /// <param name="diskFileName"></param>

-        private void RemoveStorageImage(ComputerSystem vm, string diskFileName)

-        {

-            // Obtain StorageAllocationSettingData for disk

-            StorageAllocationSettingData.StorageAllocationSettingDataCollection storageSettingsObjs = StorageAllocationSettingData.GetInstances();

-

-            StorageAllocationSettingData imageToRemove = null;

-            foreach (StorageAllocationSettingData item in storageSettingsObjs)

-            {

-                if (item.HostResource == null || item.HostResource.Length != 1)

-                {

-                    continue;

-                }

-

-                string hostResource = item.HostResource[0];

-                if (Path.Equals(hostResource, diskFileName))

-                {

-                    imageToRemove = item;

-                    break;

-                }

-            }

-

-            // assert

-            if (imageToRemove  == null)

-            {

-                var errMsg = string.Format(

-                    "Failed to remove disk image {0} from VM {1} (GUID {2}): the disk image is not attached.",

-                    diskFileName,

-                    vm.ElementName,

-                    vm.Name);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            RemoveStorageResource(imageToRemove.Path, vm);

-

-            logger.InfoFormat("Removed disk image {0} from VM {1} (GUID {2}): the disk image is not attached.",

-                    diskFileName,

-                    vm.ElementName,

-                    vm.Name);

-        }

-

-        private ManagementPath AttachNewDrive(ComputerSystem vm, string cntrllerAddr, string driveType)

-        {

-            // Disk drives are attached to a 'Parent' IDE controller.  We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it.

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-            var ctrller = GetIDEControllerSettings(vmSettings, cntrllerAddr);

-

-            // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type

-            string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", driveType);

-            var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery);

-

-            // Set IDE controller and address on the controller for the new drive

-            newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString();

-            newDiskDriveSettings.LateBoundObject["AddressOnParent"] = "0";

-            newDiskDriveSettings.CommitObject();

-

-            // Add this new disk drive to the VM

-            logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}",

-                newDiskDriveSettings.ResourceSubType,

-                newDiskDriveSettings.Parent,

-                newDiskDriveSettings.AddressOnParent);

-            string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };

-            ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm);

-

-            // assert

-            if (newDrivePaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    newDrivePaths.Length,

-                    driveType);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            logger.DebugFormat("New disk drive type {0} WMI path is {1}s",

-                newDiskDriveSettings.ResourceSubType,

-                newDrivePaths[0].Path);

-            return newDrivePaths[0];

-        }

-

-        private ManagementPath AddScsiController(ComputerSystem vm)

-        {

-            // A description of the controller is created by modifying a clone of the default ResourceAllocationSettingData for scsi controller

-            string scsiQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", SCSI_CONTROLLER);

-            var scsiSettings = CloneResourceAllocationSetting(scsiQuery);

-

-            scsiSettings.LateBoundObject["ElementName"] = "SCSI Controller";

-            scsiSettings.CommitObject();

-

-            // Insert SCSI controller into vm

-            string[] newResources = new string[] { scsiSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };

-            ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm);

-

-            // assert

-            if (newResourcePaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to add scsi controller to VM {0} (GUID {1}): number of resource created {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    newResourcePaths.Length);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            logger.DebugFormat("New controller type {0} WMI path is {1}s",

-                scsiSettings.ResourceSubType,

-                newResourcePaths[0].Path);

-            return newResourcePaths[0];

-        }

-

-        private ManagementPath GetDiskDriveOnScsiController(ComputerSystem vm, string addrOnController)

-        {

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);

-            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)

-            {

-                if (wmiObj.ResourceSubType == HARDDISK_DRIVE)

-                {

-                    ResourceAllocationSettingData parent = new ResourceAllocationSettingData(new ManagementObject(wmiObj.Parent));

-                    if (parent.ResourceSubType == SCSI_CONTROLLER && wmiObj.AddressOnParent == addrOnController)

-                    {

-                        return wmiObj.Path;

-                    }

-                }

-            }

-            return null;

-        }

-

-        private ManagementPath AttachDiskDriveToScsiController(ComputerSystem vm, string addrOnController)

-        {

-            // Disk drives are attached to a 'Parent' Scsi controller.

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-            var ctrller = GetScsiControllerSettings(vmSettings);

-

-            // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type

-            string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", HARDDISK_DRIVE);

-            var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery);

-

-            // Set IDE controller and address on the controller for the new drive

-            newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString();

-            newDiskDriveSettings.LateBoundObject["AddressOnParent"] = addrOnController;

-            newDiskDriveSettings.CommitObject();

-

-            // Add this new disk drive to the VM

-            logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}",

-                newDiskDriveSettings.ResourceSubType,

-                newDiskDriveSettings.Parent,

-                newDiskDriveSettings.AddressOnParent);

-            string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };

-            ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm);

-

-            // assert

-            if (newDrivePaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    newDrivePaths.Length,

-                    HARDDISK_DRIVE);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            logger.DebugFormat("New disk drive type {0} WMI path is {1}s",

-                newDiskDriveSettings.ResourceSubType,

-                newDrivePaths[0].Path);

-            return newDrivePaths[0];

-        }

-

-

-        private void InsertDiskImage(ComputerSystem vm, string diskImagePath, string diskResourceSubType, ManagementPath drivePath)

-        {

-            // A description of the disk is created by modifying a clone of the default ResourceAllocationSettingData for that disk type

-            string defaultDiskQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", diskResourceSubType);

-            var newDiskSettings = CloneStorageAllocationSetting(defaultDiskQuery);

-

-            // Set file containing the disk image

-            newDiskSettings.LateBoundObject["Parent"] = drivePath.Path;

-

-            // V2 API uses HostResource to specify image, see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx

-            newDiskSettings.LateBoundObject["HostResource"] = new string[] { diskImagePath };

-            newDiskSettings.CommitObject();

-

-            // Add the new Msvm_StorageAllocationSettingData object as a virtual hard disk to the vm.

-            string[] newDiskResource = new string[] { newDiskSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };

-            ManagementPath[] newDiskPaths = AddStorageResource(newDiskResource, vm);

-            // assert

-            if (newDiskPaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to add disk image type {3} to VM {0} (GUID {1}): number of resource created {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    newDiskPaths.Length,

-                    diskResourceSubType);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            logger.InfoFormat("Created disk {2} for VM {0} (GUID {1}), image {3} ",

-                    vm.ElementName,

-                    vm.Name,

-                    newDiskPaths[0].Path,

-                    diskImagePath);

-        }

-

-        /// <summary>

-        /// Create Msvm_StorageAllocationSettingData corresponding to the ISO image, and 

-        /// associate this with the VM's DVD drive.

-        /// </summary>

-        private void AttachIso(ComputerSystem vm, string isoPath)

-        {

-            // Disk drives are attached to a 'Parent' IDE controller.  We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it.

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-            var driveWmiObj = GetDvdDriveSettings(vmSettings);

-            InsertDiskImage(vm, isoPath, ISO_DISK, driveWmiObj.Path);

-        }

-

-        private static ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery)

-        {

-            var defaultDiskDriveSettingsObjs = ResourceAllocationSettingData.GetInstances(wmiQuery);

-

-            // assert

-            if (defaultDiskDriveSettingsObjs.Count != 1)

-            {

-                var errMsg = string.Format("Failed to find Msvm_ResourceAllocationSettingData for the query {0}", wmiQuery);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            ResourceAllocationSettingData defaultDiskDriveSettings = defaultDiskDriveSettingsObjs.OfType<ResourceAllocationSettingData>().First();

-            return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());

-        }

+
+            // we need to reboot to get the hv kvp daemon get started vr gets configured.
+            if (vmName.StartsWith("r-") || vmName.StartsWith("s-") || vmName.StartsWith("v-"))
+            {
+                System.Threading.Thread.Sleep(90000);
+                // wait for the second boot and then return with sucesss
+                //if publicIPAddress is empty or null don't ping the ip
+              /*if (publicIpAddress.Equals("") == true)
+                {
+                    System.Threading.Thread.Sleep(90000);
+                }
+                else
+                {
+                    pingResource(publicIpAddress);
+                }*/
+            }
+            logger.InfoFormat("Started VM {0}", vmName);
+            return newVm;
+        }
+
+        public static Boolean pingResource(String ip)
+        {
+            PingOptions pingOptions = null;
+            PingReply pingReply = null;
+            IPAddress ipAddress = null;
+            Ping pingSender = new Ping();
+            int numberOfPings = 6;
+            int pingTimeout = 1000;
+            int byteSize = 32;
+            byte[] buffer = new byte[byteSize];
+            ipAddress = IPAddress.Parse(ip);
+            pingOptions = new PingOptions();
+            for (int i = 0; i < numberOfPings; i++)
+            {
+                pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions);
+                if (pingReply.Status == IPStatus.Success)
+                {
+                    System.Threading.Thread.Sleep(30000);
+                    return true;
+                }
+                else
+                {
+                    // wait for the second boot and then return with suces
+                    System.Threading.Thread.Sleep(30000);
+                }
+            }
+            return false;
+        }
+
+        private EthernetPortAllocationSettingData AttachNicToPort(ComputerSystem newVm, SyntheticEthernetPortSettingData newAdapter, String vSwitchName, int enableState)
+        {
+            // Get the virtual switch
+            VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName);
+            //check the the recevied vSwitch is the same as vSwitchName.
+            if (!vSwitchName.Equals("")  && !vSwitch.ElementName.Equals(vSwitchName))
+            {
+               var errMsg = string.Format("Internal error, coudl not find Virtual Switch with the name : " +vSwitchName);
+               var ex = new WmiException(errMsg);
+               logger.Error(errMsg, ex);
+               throw ex;
+            }
+
+            // Create port for adapter
+            var defaultEthernetPortSettings = EthernetPortAllocationSettingData.GetInstances(vSwitch.Scope, "InstanceID LIKE \"%Default\"");
+
+            // assert
+            if (defaultEthernetPortSettings.Count != 1)
+            {
+                var errMsg = string.Format("Internal error, coudl not find default EthernetPortAllocationSettingData instance");
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            var defaultEthernetPortSettingsObj = defaultEthernetPortSettings.OfType<EthernetPortAllocationSettingData>().First();
+            var newEthernetPortSettings = new EthernetPortAllocationSettingData((ManagementBaseObject)defaultEthernetPortSettingsObj.LateBoundObject.Clone());
+            newEthernetPortSettings.LateBoundObject["Parent"] = newAdapter.Path.Path;
+            newEthernetPortSettings.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path };
+            newEthernetPortSettings.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled
+            // Insert NIC into vm
+            string[] newResources = new string[] { newEthernetPortSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newResourcePaths = AddVirtualResource(newResources, newVm);
+
+            // assert
+            if (newResourcePaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to properly insert a single NIC on VM {0} (GUID {1}): number of resource created {2}",
+                    newVm.ElementName,
+                    newVm.Name,
+                    newResourcePaths.Length);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return new EthernetPortAllocationSettingData(newResourcePaths[0]);
+        }
+
+        /// this method is to add a dvd drive and attach the systemvm iso.
+        /// 
+        public void patchSystemVmIso(String vmName, String systemVmIso)
+        {
+            ComputerSystem vmObject = GetComputerSystem(vmName);
+            AddDiskDriveToIdeController(vmObject, "", "1", ISO_DRIVE);
+            AttachIso(vmName, systemVmIso);
+        }
+
+        public void AttachDisk(string vmName, string diskPath, string addressOnController)
+        {
+            logger.DebugFormat("Got request to attach disk {0} to vm {1}", diskPath, vmName);
+
+            ComputerSystem vm = GetComputerSystem(vmName);
+            if (vm == null)
+            {
+                logger.DebugFormat("VM {0} not found", vmName);
+                return;
+            }
+            else
+            {
+                ManagementPath newDrivePath = GetDiskDriveOnScsiController(vm, addressOnController);
+                if (newDrivePath == null)
+                {
+                    newDrivePath = AttachDiskDriveToScsiController(vm, addressOnController);
+                }
+                InsertDiskImage(vm, diskPath, HARDDISK_DISK, newDrivePath);
+            }
+        }
+
+        /// </summary>
+        /// <param name="vm"></param>
+        /// <param name="cntrllerAddr"></param>
+        /// <param name="driveResourceType">IDE_HARDDISK_DRIVE or IDE_ISO_DRIVE</param>
+        public ManagementPath AddDiskDriveToIdeController(ComputerSystem vm, string vhdfile, string cntrllerAddr, string driveResourceType)
+        {
+            logger.DebugFormat("Creating DISK for VM {0} (GUID {1}) by attaching {2}", 
+                        vm.ElementName,
+                        vm.Name,
+                        vhdfile);
+
+            // Determine disk type for drive and assert drive type valid
+            string diskResourceSubType = null;
+            switch(driveResourceType) {
+                case HARDDISK_DRIVE:
+                    diskResourceSubType = HARDDISK_DISK;
+                    break;
+                case ISO_DRIVE: 
+                    diskResourceSubType = ISO_DISK;
+                    break;
+                default:
+                    var errMsg = string.Format(
+                        "Unrecognised disk drive type {0} for VM {1} (GUID {2})",
+                        string.IsNullOrEmpty(driveResourceType) ? "NULL": driveResourceType, 
+                        vm.ElementName,
+                        vm.Name);
+                    var ex = new WmiException(errMsg);
+                    logger.Error(errMsg, ex);
+                    throw ex;
+            }
+
+            ManagementPath newDrivePath = AttachNewDrive(vm, cntrllerAddr, driveResourceType);
+
+            // If there's not disk to insert, we are done.
+            if (String.IsNullOrEmpty(vhdfile))
+            {
+                logger.DebugFormat("No disk to be added to drive, disk drive {0} is complete", newDrivePath.Path);
+            }
+            else
+            {
+                InsertDiskImage(vm, vhdfile, diskResourceSubType, newDrivePath);
+            }
+            return newDrivePath;
+        }
+
+
+        public void DetachDisk(string displayName, string diskFileName)
+        {
+            logger.DebugFormat("Got request to detach virtual disk {0} from vm {1}", diskFileName, displayName);
+
+            ComputerSystem vm = GetComputerSystem(displayName);
+            if (vm == null)
+            {
+                logger.DebugFormat("VM {0} not found", displayName);
+                return;
+            }
+            else
+            {
+                RemoveStorageImage(vm, diskFileName);
+            }
+        }
+
+        /// <summary>
+        /// Removes a disk image from a drive, but does not remove the drive itself.
+        /// </summary>
+        /// <param name="vm"></param>
+        /// <param name="diskFileName"></param>
+        private void RemoveStorageImage(ComputerSystem vm, string diskFileName)
+        {
+            // Obtain StorageAllocationSettingData for disk
+            StorageAllocationSettingData.StorageAllocationSettingDataCollection storageSettingsObjs = StorageAllocationSettingData.GetInstances();
+
+            StorageAllocationSettingData imageToRemove = null;
+            foreach (StorageAllocationSettingData item in storageSettingsObjs)
+            {
+                if (item.HostResource == null || item.HostResource.Length != 1)
+                {
+                    continue;
+                }
+
+                string hostResource = item.HostResource[0];
+                if (Path.Equals(hostResource, diskFileName))
+                {
+                    imageToRemove = item;
+                    break;
+                }
+            }
+
+            // assert
+            if (imageToRemove  == null)
+            {
+                var errMsg = string.Format(
+                    "Failed to remove disk image {0} from VM {1} (GUID {2}): the disk image is not attached.",
+                    diskFileName,
+                    vm.ElementName,
+                    vm.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            RemoveStorageResource(imageToRemove.Path, vm);
+
+            logger.InfoFormat("Removed disk image {0} from VM {1} (GUID {2}): the disk image is not attached.",
+                    diskFileName,
+                    vm.ElementName,
+                    vm.Name);
+        }
+
+        private ManagementPath AttachNewDrive(ComputerSystem vm, string cntrllerAddr, string driveType)
+        {
+            // Disk drives are attached to a 'Parent' IDE controller.  We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it.
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+            var ctrller = GetIDEControllerSettings(vmSettings, cntrllerAddr);
+
+            // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type
+            string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", driveType);
+            var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery);
+
+            // Set IDE controller and address on the controller for the new drive
+            newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString();
+            newDiskDriveSettings.LateBoundObject["AddressOnParent"] = "0";
+            newDiskDriveSettings.CommitObject();
+
+            // Add this new disk drive to the VM
+            logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}",
+                newDiskDriveSettings.ResourceSubType,
+                newDiskDriveSettings.Parent,
+                newDiskDriveSettings.AddressOnParent);
+            string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm);
+
+            // assert
+            if (newDrivePaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    newDrivePaths.Length,
+                    driveType);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            logger.DebugFormat("New disk drive type {0} WMI path is {1}s",
+                newDiskDriveSettings.ResourceSubType,
+                newDrivePaths[0].Path);
+            return newDrivePaths[0];
+        }
+
+        private ManagementPath AddScsiController(ComputerSystem vm)
+        {
+            // A description of the controller is created by modifying a clone of the default ResourceAllocationSettingData for scsi controller
+            string scsiQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", SCSI_CONTROLLER);
+            var scsiSettings = CloneResourceAllocationSetting(scsiQuery);
+
+            scsiSettings.LateBoundObject["ElementName"] = "SCSI Controller";
+            scsiSettings.CommitObject();
+
+            // Insert SCSI controller into vm
+            string[] newResources = new string[] { scsiSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newResourcePaths = AddVirtualResource(newResources, vm);
+
+            // assert
+            if (newResourcePaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to add scsi controller to VM {0} (GUID {1}): number of resource created {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    newResourcePaths.Length);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            logger.DebugFormat("New controller type {0} WMI path is {1}s",
+                scsiSettings.ResourceSubType,
+                newResourcePaths[0].Path);
+            return newResourcePaths[0];
+        }
+
+        private ManagementPath GetDiskDriveOnScsiController(ComputerSystem vm, string addrOnController)
+        {
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
+            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
+            {
+                if (wmiObj.ResourceSubType == HARDDISK_DRIVE)
+                {
+                    ResourceAllocationSettingData parent = new ResourceAllocationSettingData(new ManagementObject(wmiObj.Parent));
+                    if (parent.ResourceSubType == SCSI_CONTROLLER && wmiObj.AddressOnParent == addrOnController)
+                    {
+                        return wmiObj.Path;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private ManagementPath AttachDiskDriveToScsiController(ComputerSystem vm, string addrOnController)
+        {
+            // Disk drives are attached to a 'Parent' Scsi controller.
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+            var ctrller = GetScsiControllerSettings(vmSettings);
+
+            // A description of the drive is created by modifying a clone of the default ResourceAllocationSettingData for that drive type
+            string defaultDriveQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", HARDDISK_DRIVE);
+            var newDiskDriveSettings = CloneResourceAllocationSetting(defaultDriveQuery);
+
+            // Set IDE controller and address on the controller for the new drive
+            newDiskDriveSettings.LateBoundObject["Parent"] = ctrller.Path.ToString();
+            newDiskDriveSettings.LateBoundObject["AddressOnParent"] = addrOnController;
+            newDiskDriveSettings.CommitObject();
+
+            // Add this new disk drive to the VM
+            logger.DebugFormat("Creating disk drive type {0}, parent IDE controller is {1} and address on controller is {2}",
+                newDiskDriveSettings.ResourceSubType,
+                newDiskDriveSettings.Parent,
+                newDiskDriveSettings.AddressOnParent);
+            string[] newDriveResource = new string[] { newDiskDriveSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newDrivePaths = AddVirtualResource(newDriveResource, vm);
+
+            // assert
+            if (newDrivePaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to add disk drive type {3} to VM {0} (GUID {1}): number of resource created {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    newDrivePaths.Length,
+                    HARDDISK_DRIVE);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            logger.DebugFormat("New disk drive type {0} WMI path is {1}s",
+                newDiskDriveSettings.ResourceSubType,
+                newDrivePaths[0].Path);
+            return newDrivePaths[0];
+        }
+
+
+        private void InsertDiskImage(ComputerSystem vm, string diskImagePath, string diskResourceSubType, ManagementPath drivePath)
+        {
+            // A description of the disk is created by modifying a clone of the default ResourceAllocationSettingData for that disk type
+            string defaultDiskQuery = String.Format("ResourceSubType LIKE \"{0}\" AND InstanceID LIKE \"%Default\"", diskResourceSubType);
+            var newDiskSettings = CloneStorageAllocationSetting(defaultDiskQuery);
+
+            // Set file containing the disk image
+            newDiskSettings.LateBoundObject["Parent"] = drivePath.Path;
+
+            // V2 API uses HostResource to specify image, see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx
+            newDiskSettings.LateBoundObject["HostResource"] = new string[] { diskImagePath };
+            newDiskSettings.CommitObject();
+
+            // Add the new Msvm_StorageAllocationSettingData object as a virtual hard disk to the vm.
+            string[] newDiskResource = new string[] { newDiskSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newDiskPaths = AddStorageResource(newDiskResource, vm);
+            // assert
+            if (newDiskPaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to add disk image type {3} to VM {0} (GUID {1}): number of resource created {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    newDiskPaths.Length,
+                    diskResourceSubType);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            logger.InfoFormat("Created disk {2} for VM {0} (GUID {1}), image {3} ",
+                    vm.ElementName,
+                    vm.Name,
+                    newDiskPaths[0].Path,
+                    diskImagePath);
+        }
+
+        /// <summary>
+        /// Create Msvm_StorageAllocationSettingData corresponding to the ISO image, and 
+        /// associate this with the VM's DVD drive.
+        /// </summary>
+        private void AttachIso(ComputerSystem vm, string isoPath)
+        {
+            // Disk drives are attached to a 'Parent' IDE controller.  We IDE Controller's settings for the 'Path', which our new Disk drive will use to reference it.
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+            var driveWmiObj = GetDvdDriveSettings(vmSettings);
+            InsertDiskImage(vm, isoPath, ISO_DISK, driveWmiObj.Path);
+        }
+
+        private static ResourceAllocationSettingData CloneResourceAllocationSetting(string wmiQuery)
+        {
+            var defaultDiskDriveSettingsObjs = ResourceAllocationSettingData.GetInstances(wmiQuery);
+
+            // assert
+            if (defaultDiskDriveSettingsObjs.Count != 1)
+            {
+                var errMsg = string.Format("Failed to find Msvm_ResourceAllocationSettingData for the query {0}", wmiQuery);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            ResourceAllocationSettingData defaultDiskDriveSettings = defaultDiskDriveSettingsObjs.OfType<ResourceAllocationSettingData>().First();
+            return new ResourceAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());
+        }
 
         // Modify the systemvm nic's VLAN id
-        public void ModifyVmVLan(string vmName, uint vlanid, String mac)
+        public void ModifyVmVLan(string vmName, String vlanid, String mac)
+        {
+            int enableState = 2;
+            bool enable = true;
+            ComputerSystem vm = GetComputerSystem(vmName);
+            SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm);
+            // Obtain controller for Hyper-V virtualisation subsystem
+            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
+            EthernetPortAllocationSettingData networkAdapter = null;
+            string normalisedMAC = string.Join("", (mac.Split(new char[] { ':' })));
+            int index = 0;
+            foreach (SyntheticEthernetPortSettingData item in nicSettingsViaVm)
+            {
+                if (normalisedMAC.ToLower().Equals(item.Address.ToLower()))
+                {
+                    break;
+                }
+                index++;
+            }
+            String vSwitchName = "";
+            VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName);
+            EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
+            networkAdapter = ethernetConnections[index];
+            networkAdapter.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled
+            networkAdapter.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path };
+
+            ModifyVmResources(vmMgmtSvc, vm, new String[] {
+                networkAdapter.LateBoundObject.GetText(TextFormat.CimDtd20)
+                });
+
+            EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]);
+
+            if (vlanSettings == null)
+            {
+                // when modifying  nic to not connected dont create vlan
+                if (enable)
+                {
+                    if (vlanid != null)
+                    {
+                        SetPortVlan(vlanid, networkAdapter);
+                    }
+                }
+            }
+            else
+            {
+                if (enable)
+                {
+                    if (vlanid != null)
+                    {
+                        //Assign vlan configuration to nic
+                        vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
+                        vlanSettings.LateBoundObject["OperationMode"] = 1;
+                        ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
+                            vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
+                    }
+                }
+                else
+                {
+                    var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+                    // This method will remove the vlan settings present on the Nic
+                    ManagementPath jobPath;
+                    var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path },
+                        out jobPath);
+
+                    // If the Job is done asynchronously
+                    if (ret_val == ReturnCode.Started)
+                    {
+                        JobCompleted(jobPath);
+                    }
+                    else if (ret_val != ReturnCode.Completed)
+                    {
+                        var errMsg = string.Format(
+                            "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}",
+                            vlanSettings.Path,
+                            vm.ElementName,
+                            vm.Name,
+                            ReturnCode.ToString(ret_val));
+                        var ex = new WmiException(errMsg);
+                        logger.Error(errMsg, ex);
+                    }
+                }
+            }
+        }
+
+        // This is disabling the VLAN settings on the specified nic. It works Awesome.
+        public void DisableNicVlan(String mac, String vmName)
         {
             ComputerSystem vm = GetComputerSystem(vmName);
             SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm);
@@ -952,565 +1034,675 @@
             EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
             EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[index]);
 
-            //Assign configuration to new NIC
-            vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
-            vlanSettings.LateBoundObject["OperationMode"] = 1;
-            ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
-                vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
+            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+            // This method will remove the vlan settings present on the Nic
+            ManagementPath jobPath;
+            var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[]{ vlanSettings.Path},
+                out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}",
+                    vlanSettings.Path,
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        // Modify All VM Nics to disable
+        public void DisableVmNics()
+        {
+            ComputerSystem vm = GetComputerSystem("test");
+            EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
+            // Get the virtual switch
+            VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch("vswitch2");
+
+            foreach (EthernetPortAllocationSettingData epasd in ethernetConnections)
+            {
+                epasd.LateBoundObject["EnabledState"] = 2; //3 disabled 2 Enabled
+                epasd.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path };
+
+                VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
+                ModifyVmResources(vmMgmtSvc, vm, new String[] {
+                epasd.LateBoundObject.GetText(TextFormat.CimDtd20)
+                });
+            }
         }
 
         // Modify the systemvm nic's VLAN id
-        public void ModifyVmVLan(string vmName, uint vlanid, uint pos)
+        public void ModifyVmVLan(string vmName, String vlanid, uint pos, bool enable, string switchLabelName)
         {
+            // This if to modify the VPC VR nics
+            // 1. Enable the network adapter and connect to a switch
+            // 2. modify the vlan id
+            int enableState = 2;
             ComputerSystem vm = GetComputerSystem(vmName);
-            SyntheticEthernetPortSettingData[] nicSettingsViaVm = GetEthernetPortSettings(vm);
+                EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
             // Obtain controller for Hyper-V virtualisation subsystem
+            EthernetPortAllocationSettingData networkAdapter = null;
             VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
 
-            EthernetPortAllocationSettingData[] ethernetConnections = GetEthernetConnections(vm);
-            EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(ethernetConnections[pos]);
+            String vSwitchName = "";
+            if (switchLabelName != null)
+                vSwitchName = switchLabelName;
+            VirtualEthernetSwitch vSwitch = GetExternalVirtSwitch(vSwitchName);
+            if (pos <= ethernetConnections.Length)
+            {
+                if (enable == false)
+                {
+                    enableState = 3;
+                }
 
-            //Assign configuration to new NIC
-            vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
-            vlanSettings.LateBoundObject["OperationMode"] = 1;
-            ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
-                vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
+                networkAdapter = ethernetConnections[pos];
+                networkAdapter.LateBoundObject["EnabledState"] = enableState; //3 disabled 2 Enabled
+                networkAdapter.LateBoundObject["HostResource"] = new string[] { vSwitch.Path.Path };
+                ModifyVmResources(vmMgmtSvc, vm, new String[] {
+                networkAdapter.LateBoundObject.GetText(TextFormat.CimDtd20)
+                });
+            }
+
+            // check when nic is disabled, removing vlan is required or not.
+            EthernetPortAllocationSettingData[] vmEthernetConnections = GetEthernetConnections(vm);
+            EthernetSwitchPortVlanSettingData vlanSettings = GetVlanSettings(vmEthernetConnections[pos]);
+
+            if (vlanSettings == null)
+            {
+                // when modifying  nic to not connected dont create vlan
+                if (enable)
+                {
+                    if (vlanid != null)
+                    {
+                        SetPortVlan(vlanid, networkAdapter);
+                    }
+                }
+            }
+            else
+            {
+                if (enable)
+                {
+                    if (vlanid != null)
+                    {
+                        //Assign vlan configuration to nic
+                        vlanSettings.LateBoundObject["AccessVlanId"] = vlanid;
+                        vlanSettings.LateBoundObject["OperationMode"] = 1;
+                        ModifyFeatureVmResources(vmMgmtSvc, vm, new String[] {
+                            vlanSettings.LateBoundObject.GetText(TextFormat.CimDtd20)});
+                    }
+                }
+                else
+                {
+                    var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+                    // This method will remove the vlan settings present on the Nic
+                    ManagementPath jobPath;
+                    var ret_val = virtSysMgmtSvc.RemoveFeatureSettings(new ManagementPath[] { vlanSettings.Path },
+                        out jobPath);
+
+                    // If the Job is done asynchronously
+                    if (ret_val == ReturnCode.Started)
+                    {
+                        JobCompleted(jobPath);
+                    }
+                    else if (ret_val != ReturnCode.Completed)
+                    {
+                        var errMsg = string.Format(
+                            "Failed to remove vlan resource {0} from VM {1} (GUID {2}) due to {3}",
+                            vlanSettings.Path,
+                            vm.ElementName,
+                            vm.Name,
+                            ReturnCode.ToString(ret_val));
+                        var ex = new WmiException(errMsg);
+                        logger.Error(errMsg, ex);
+                    }
+                }
+            }
         }
 
-        public void AttachIso(string displayName, string iso)

-        {

-            logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName);

-

-            ComputerSystem vm = GetComputerSystem(displayName);

-            if (vm == null)

-            {

-                logger.DebugFormat("VM {0} not found", displayName);

-                return;

-            }

-            else

-            {

-                AttachIso(vm, iso);

-            }

-        }

-

-        public void DestroyVm(dynamic jsonObj)

-        {

-            string vmToDestroy = jsonObj.vmName;

-            DestroyVm(vmToDestroy);

-        }

-        

-        /// <summary>

-        /// Remove all VMs and all SwitchPorts with the displayName.  VHD gets deleted elsewhere.

-        /// </summary>

-        /// <param name="displayName"></param>

-        public void DestroyVm(string displayName)

-        {

-            logger.DebugFormat("Got request to destroy vm {0}", displayName);

-

-            var vm = GetComputerSystem(displayName);

-            if ( vm  == null )

-            {

-                logger.DebugFormat("VM {0} already destroyed (or never existed)", displayName);

-                return;

-            }

-

-            // Stop VM

-            logger.DebugFormat("Stop VM {0} (GUID {1})", vm.ElementName, vm.Name);

-            SetState(vm, RequiredState.Disabled);

-

-            // Delete SwitchPort

-            logger.DebugFormat("Remove associated switch ports for VM {0} (GUID {1})", vm.ElementName, vm.Name);

-            DeleteSwitchPort(vm.ElementName);

-

-            // Delete VM

-            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();

-            ManagementPath jobPath;

-

-            do

-            {

-                logger.DebugFormat("Delete VM {0} (GUID {1})", vm.ElementName, vm.Name);

-                var ret_val = virtSysMgmtSvc.DestroySystem(vm.Path, out jobPath);

-

-                if (ret_val == ReturnCode.Started)

-                {

-                    JobCompleted(jobPath);

-                }

-                else if (ret_val != ReturnCode.Completed)

-                {

-                    var errMsg = string.Format(

-                        "Failed Delete VM {0} (GUID {1}) due to {2}",

-                        vm.ElementName,

-                        vm.Name,

-                        ReturnCode.ToString(ret_val));

-                    var ex = new WmiException(errMsg);

-                    logger.Error(errMsg, ex);

-                    throw ex;

-                }

-                vm = GetComputerSystem(displayName);

-            }

-            while (vm != null);

-        }

-

-        /// <summary>

-        /// Migrates a vm to the given destination host

-        /// </summary>

-        /// <param name="desplayName"></param>

-        /// <param name="destination host"></param>

-        public void MigrateVm(string vmName, string destination)

-        {

-            ComputerSystem vm = GetComputerSystem(vmName);

-            VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();

-            VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();

-

-            IPAddress addr = IPAddress.Parse(destination);

-            IPHostEntry entry = Dns.GetHostEntry(addr);

-            string[] destinationHost = new string[] { destination };

-

-            migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystem;

-            migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;

-            migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost;

-            string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);

-

-            ManagementPath jobPath;

-            var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, null, null, out jobPath);

-            if (ret_val == ReturnCode.Started)

-            {

-                MigrationJobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed migrating VM {0} (GUID {1}) due to {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        /// <summary>

-        /// Migrates the volume of a vm to a given destination storage

-        /// </summary>

-        /// <param name="displayName"></param>

-        /// <param name="volume"></param>

-        /// <param name="destination storage pool"></param>

-        public void MigrateVolume(string vmName, string volume, string destination)

-        {

-            ComputerSystem vm = GetComputerSystem(vmName);

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-            VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();

-            VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();

-            StorageAllocationSettingData[] sasd = GetStorageSettings(vm);

-

-            string[] rasds = null;

-            if (sasd != null)

-            {

+        public void AttachIso(string displayName, string iso)
+        {
+            logger.DebugFormat("Got request to attach iso {0} to vm {1}", iso, displayName);
+
+            ComputerSystem vm = GetComputerSystem(displayName);
+            if (vm == null)
+            {
+                logger.DebugFormat("VM {0} not found", displayName);
+                return;
+            }
+            else
+            {
+                AttachIso(vm, iso);
+            }
+        }
+
+        public void DestroyVm(dynamic jsonObj)
+        {
+            string vmToDestroy = jsonObj.vmName;
+            DestroyVm(vmToDestroy);
+        }
+        
+        /// <summary>
+        /// Remove all VMs and all SwitchPorts with the displayName.  VHD gets deleted elsewhere.
+        /// </summary>
+        /// <param name="displayName"></param>
+        public void DestroyVm(string displayName)
+        {
+            logger.DebugFormat("Got request to destroy vm {0}", displayName);
+
+            var vm = GetComputerSystem(displayName);
+            if ( vm  == null )
+            {
+                logger.DebugFormat("VM {0} already destroyed (or never existed)", displayName);
+                return;
+            }
+
+            // Stop VM
+            logger.DebugFormat("Stop VM {0} (GUID {1})", vm.ElementName, vm.Name);
+            SetState(vm, RequiredState.Disabled);
+
+            // Delete SwitchPort
+            logger.DebugFormat("Remove associated switch ports for VM {0} (GUID {1})", vm.ElementName, vm.Name);
+            DeleteSwitchPort(vm.ElementName);
+
+            // Delete VM
+            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+            ManagementPath jobPath;
+
+            do
+            {
+                logger.DebugFormat("Delete VM {0} (GUID {1})", vm.ElementName, vm.Name);
+                var ret_val = virtSysMgmtSvc.DestroySystem(vm.Path, out jobPath);
+
+                if (ret_val == ReturnCode.Started)
+                {
+                    JobCompleted(jobPath);
+                }
+                else if (ret_val != ReturnCode.Completed)
+                {
+                    var errMsg = string.Format(
+                        "Failed Delete VM {0} (GUID {1}) due to {2}",
+                        vm.ElementName,
+                        vm.Name,
+                        ReturnCode.ToString(ret_val));
+                    var ex = new WmiException(errMsg);
+                    logger.Error(errMsg, ex);
+                    throw ex;
+                }
+                vm = GetComputerSystem(displayName);
+            }
+            while (vm != null);
+        }
+
+        /// <summary>
+        /// Migrates a vm to the given destination host
+        /// </summary>
+        /// <param name="desplayName"></param>
+        /// <param name="destination host"></param>
+        public void MigrateVm(string vmName, string destination)
+        {
+            ComputerSystem vm = GetComputerSystem(vmName);
+            VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();
+            VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();
+
+            IPAddress addr = IPAddress.Parse(destination);
+            IPHostEntry entry = Dns.GetHostEntry(addr);
+            string[] destinationHost = new string[] { destination };
+
+            migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystem;
+            migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;
+            migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost;
+            string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
+
+            ManagementPath jobPath;
+            var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, null, null, out jobPath);
+            if (ret_val == ReturnCode.Started)
+            {
+                MigrationJobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed migrating VM {0} (GUID {1}) due to {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// Migrates the volume of a vm to a given destination storage
+        /// </summary>
+        /// <param name="displayName"></param>
+        /// <param name="volume"></param>
+        /// <param name="destination storage pool"></param>
+        public void MigrateVolume(string vmName, string volume, string destination)
+        {
+            ComputerSystem vm = GetComputerSystem(vmName);
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+            VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();
+            VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();
+            StorageAllocationSettingData[] sasd = GetStorageSettings(vm);
+
+            string[] rasds = null;
+            if (sasd != null)
+            {
                 rasds = new string[1];
-                foreach (StorageAllocationSettingData item in sasd)

-                {

-                    string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]);

-                    if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume))

-                    {

-                        string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0]));

-                        item.LateBoundObject["HostResource"] = new string[] { newVhdPath };

-                        item.LateBoundObject["PoolId"] = "";

+                foreach (StorageAllocationSettingData item in sasd)
+                {
+                    string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]);
+                    if (!String.IsNullOrEmpty(vhdFileName) && vhdFileName.Equals(volume))
+                    {
+                        string newVhdPath = Path.Combine(destination, Path.GetFileName(item.HostResource[0]));
+                        item.LateBoundObject["HostResource"] = new string[] { newVhdPath };
+                        item.LateBoundObject["PoolId"] = "";
                         rasds[0] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
                         break;
-                    }

-                }

-            }

-

-            migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.Storage;

-            migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;

-            string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);

-

-            ManagementPath jobPath;

-            var ret_val = service.MigrateVirtualSystemToHost(vm.Path, null, migrationSettings, rasds, null, out jobPath);

-            if (ret_val == ReturnCode.Started)

-            {

-                MigrationJobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed migrating volume {0} of VM {1} (GUID {2}) due to {3}",

-                    volume,

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        /// <summary>

-        /// Migrates the volume of a vm to a given destination storage

-        /// </summary>

-        /// <param name="displayName"></param>

-        /// <param name="destination host"></param>

-        /// <param name="volumeToPool"> volume to me migrated to which pool</param>

-        public void MigrateVmWithVolume(string vmName, string destination, Dictionary<string, string> volumeToPool)

-        {

-            ComputerSystem vm = GetComputerSystem(vmName);

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-            VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();

-            VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();

-            StorageAllocationSettingData[] sasd = GetStorageSettings(vm);

-

-            string[] rasds = null;

-            if (sasd != null)

-            {

-                rasds = new string[sasd.Length];

-                uint index = 0;

-                foreach (StorageAllocationSettingData item in sasd)

-                {

-                    string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]);

-                    if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName))

-                    {

-                        string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0]));

-                        item.LateBoundObject["HostResource"] = new string[] { newVhdPath };

-                        item.LateBoundObject["PoolId"] = "";

-                    }

-

-                    rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);

-                }

-            }

-

-            IPAddress addr = IPAddress.Parse(destination);

-            IPHostEntry entry = Dns.GetHostEntry(addr);

-            string[] destinationHost = new string[] { destination };

-

-            migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage;

-            migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;

-            migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost;

-            string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);

-

-            ManagementPath jobPath;

-            var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath);

-            if (ret_val == ReturnCode.Started)

-            {

-                MigrationJobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}",

-                    vm.ElementName,

-                    destination,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        /// <summary>

-        /// Create new storage media resources, e.g. hard disk images and ISO disk images

-        /// see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx

-        /// </summary>

-        /// <param name="wmiQuery"></param>

-        /// <returns></returns>

-        private static StorageAllocationSettingData CloneStorageAllocationSetting(string wmiQuery)

-        {

-            var defaultDiskImageSettingsObjs = StorageAllocationSettingData.GetInstances(wmiQuery);

-

-            // assert

-            if (defaultDiskImageSettingsObjs.Count != 1)

-            {

-                var errMsg = string.Format("Failed to find Msvm_StorageAllocationSettingData for the query {0}", wmiQuery);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            StorageAllocationSettingData defaultDiskDriveSettings = defaultDiskImageSettingsObjs.OfType<StorageAllocationSettingData>().First();

-            return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());

-        }

-

-        /// < summary>

-        /// Removes a storage resource from a computer system.

-        /// </summary>

-        /// <param name="storageSettings">Path that uniquely identifies the resource.</param>

-        /// <param name="vm">VM to which the disk image will be attached.</param>

-        // Add new 

-        private void RemoveNetworkResource(ManagementPath resourcePath)

-        {

-            var virtSwitchMgmtSvc = GetVirtualSwitchManagementService();

-            ManagementPath jobPath;

-            var ret_val = virtSwitchMgmtSvc.RemoveResourceSettings(

-                new ManagementPath[] { resourcePath },

-                out jobPath);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to remove network resources {0} from switch due to {1}",

-                    resourcePath.Path,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        /// < summary>

-        /// Removes a storage resource from a computer system.

-        /// </summary>

-        /// <param name="storageSettings">Path that uniquely identifies the resource.</param>

-        /// <param name="vm">VM to which the disk image will be attached.</param>

-        private void RemoveStorageResource(ManagementPath resourcePath, ComputerSystem vm)

-        {

-            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();

-

-            ManagementPath jobPath;

-            var ret_val = virtSysMgmtSvc.RemoveResourceSettings(

-                new ManagementPath[] { resourcePath },

-                out jobPath);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to remove resource {0} from VM {1} (GUID {2}) due to {3}",

-                    resourcePath.Path,

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        public void SetState(ComputerSystem vm, ushort requiredState)

-        {

-            logger.InfoFormat(

-                "Changing state of {0} (GUID {1}) to {2}", 

-                vm.ElementName, 

-                vm.Name,  

-                RequiredState.ToString(requiredState));

-

-            ManagementPath jobPath;

-            // DateTime is unused

-            var ret_val = vm.RequestStateChange(requiredState, new DateTime(), out jobPath);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val == 32775)

-            {   // TODO: check

-                logger.InfoFormat("RequestStateChange returned 32775, which means vm in wrong state for requested state change.  Treating as if requested state was reached");

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to change state of VM {0} (GUID {1}) to {2} due to {3}",

-                    vm.ElementName,

-                    vm.Name,

-                    RequiredState.ToString(requiredState),

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            logger.InfoFormat(

-                "Successfully changed vm state of {0} (GUID {1} to requested state {2}", 

-                vm.ElementName, 

-                vm.Name,  

-                requiredState);

-        }

-

-

-        //TODO:  Write method to delete SwitchPort based on Name

-        /// <summary>

-        /// Delete switch port by removing settings from the switch

-        /// </summary>

-        /// <param name="elementName"></param>

-        /// <returns></returns>

-        public void DeleteSwitchPort(string elementName)

-        {

-            // Get NIC path

-            var condition = string.Format("ElementName=\"{0}\"", elementName);

-            var virtSwitchMgmtSvc = GetVirtualSwitchManagementService();

-

-            var switchPortCollection = EthernetSwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition);

-            if (switchPortCollection.Count == 0)

-            {

-                return;

-            }

-

-            foreach (EthernetSwitchPort port in switchPortCollection)

-            {

-                var settings = GetSyntheticEthernetPortSettings(port);

-                RemoveNetworkResource(settings.Path);

-            }

-        }

-

-        public SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port)

-        {

-            // An ASSOCIATOR object provides the cross reference from the EthernetSwitchPort and the 

-            // SyntheticEthernetPortSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(port.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(port.Scope, wmiObjQuery);

-            var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get());

-

-            // When snapshots are taken into account, there can be multiple settings objects

-            // take the first one that isn't a snapshot

-            foreach (SyntheticEthernetPortSettingData wmiObj in wmiObjCollection)

-            {

-                return wmiObj;

-            }

-

-            var errMsg = string.Format("No SyntheticEthernetPortSettingData for port {0}, path {1}", port.ElementName, port.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        /// <summary>

-        /// Adds storage images to coputer system (disk image, iso image).

-        /// </summary>

-        /// <param name="storageSettings">Msvm_StorageAllocationSettings with HostResource configured with image

-        /// file and Parent set to a controller associated with the ComputerSystem</param>

-        /// <param name="vm">VM to which the disk image will be attached.</param>

-        // Add new 

-        private ManagementPath[] AddStorageResource(string[] storageSettings, ComputerSystem vm)

-        {

-            return AddVirtualResource(storageSettings, vm);

-        }

-

-        private ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm )

-        {

-            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();

-

-            ManagementPath jobPath;

-            ManagementPath[] resourcePaths;

-            var ret_val = virtSysMgmtSvc.AddResourceSettings(

-                vm.Path,

-                resourceSettings,

-                out jobPath,

-                out resourcePaths);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to add resources to VM {0} (GUID {1}) due to {2}",

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return resourcePaths;

-        }

-

-        private ManagementPath[] AddFeatureSettings(string[] featureSettings, ManagementPath affectedConfiguration)

-        {

-            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();

-

-            ManagementPath jobPath;

-            ManagementPath[] resultSettings;

-            var ret_val = virtSysMgmtSvc.AddFeatureSettings(

-                affectedConfiguration,

-                featureSettings,

-                out jobPath,

-                out resultSettings);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to add features settings {0} to resource {1} due to {2}",

-                    featureSettings,

-                    affectedConfiguration,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return resultSettings;

-        }

-

-        private ManagementPath SetPortVlan(string vlan, EthernetPortAllocationSettingData portPath)

-        {

-            logger.DebugFormat("Setting VLAN to {0}", vlan);

-

-            var vmVirtMgmtSvc = GetVirtualisationSystemManagementService();

-            EthernetSwitchPortVlanSettingData.GetInstances();

-

-            // Create NIC resource by cloning the default NIC 

-            var vlanSettings = EthernetSwitchPortVlanSettingData.GetInstances(vmVirtMgmtSvc.Scope, "InstanceID LIKE \"%Default\"");

-

-            // Assert

-            if (vlanSettings.Count != 1)

-            {

-                var errMsg = string.Format("Internal error, could not find default EthernetSwitchPortVlanSettingData instance");

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            var defaultVlanSettings = vlanSettings.OfType<EthernetSwitchPortVlanSettingData>().First();

-

-            var newVlanSettings = new EthernetSwitchPortVlanSettingData((ManagementBaseObject)defaultVlanSettings.LateBoundObject.Clone());

-

-            //  Assign configuration to new NIC

-            newVlanSettings.LateBoundObject["AccessVlanId"] = vlan;

-            newVlanSettings.LateBoundObject["OperationMode"] = 1; // Access=1, trunk=2, private=3 ;

-            newVlanSettings.CommitObject();

-

-            // Insert NIC into vm

-            string[] newResources = new string[] { newVlanSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };

-            ManagementPath[] newResourcePaths = AddFeatureSettings(newResources, portPath.Path);

-

-            // assert

-            if (newResourcePaths.Length != 1)

-            {

-                var errMsg = string.Format(

-                    "Failed to properly set VLAN to {0} for NIC on port {1}",

-                    vlan,

-                    portPath.Path);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return newResourcePaths[0];

-        }

-

+                    }
+                }
+            }
+
+            migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.Storage;
+            migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;
+            string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
+
+            ManagementPath jobPath;
+            var ret_val = service.MigrateVirtualSystemToHost(vm.Path, null, migrationSettings, rasds, null, out jobPath);
+            if (ret_val == ReturnCode.Started)
+            {
+                MigrationJobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed migrating volume {0} of VM {1} (GUID {2}) due to {3}",
+                    volume,
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// Migrates the volume of a vm to a given destination storage
+        /// </summary>
+        /// <param name="displayName"></param>
+        /// <param name="destination host"></param>
+        /// <param name="volumeToPool"> volume to me migrated to which pool</param>
+        public void MigrateVmWithVolume(string vmName, string destination, Dictionary<string, string> volumeToPool)
+        {
+            ComputerSystem vm = GetComputerSystem(vmName);
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+            VirtualSystemMigrationSettingData migrationSettingData = VirtualSystemMigrationSettingData.CreateInstance();
+            VirtualSystemMigrationService service = GetVirtualisationSystemMigrationService();
+            StorageAllocationSettingData[] sasd = GetStorageSettings(vm);
+
+            string[] rasds = null;
+            if (sasd != null)
+            {
+                rasds = new string[sasd.Length];
+                uint index = 0;
+                foreach (StorageAllocationSettingData item in sasd)
+                {
+                    string vhdFileName = Path.GetFileNameWithoutExtension(item.HostResource[0]);
+                    if (!String.IsNullOrEmpty(vhdFileName) && volumeToPool.ContainsKey(vhdFileName))
+                    {
+                        string newVhdPath = Path.Combine(volumeToPool[vhdFileName], Path.GetFileName(item.HostResource[0]));
+                        item.LateBoundObject["HostResource"] = new string[] { newVhdPath };
+                        item.LateBoundObject["PoolId"] = "";
+                    }
+
+                    rasds[index++] = item.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
+                }
+            }
+
+            IPAddress addr = IPAddress.Parse(destination);
+            IPHostEntry entry = Dns.GetHostEntry(addr);
+            string[] destinationHost = new string[] { destination };
+
+            migrationSettingData.LateBoundObject["MigrationType"] = MigrationType.VirtualSystemAndStorage;
+            migrationSettingData.LateBoundObject["TransportType"] = TransportType.TCP;
+            migrationSettingData.LateBoundObject["DestinationIPAddressList"] = destinationHost;
+            string migrationSettings = migrationSettingData.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
+
+            ManagementPath jobPath;
+            var ret_val = service.MigrateVirtualSystemToHost(vm.Path, entry.HostName, migrationSettings, rasds, null, out jobPath);
+            if (ret_val == ReturnCode.Started)
+            {
+                MigrationJobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed migrating VM {0} and its volumes to destination {1} (GUID {2}) due to {3}",
+                    vm.ElementName,
+                    destination,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// Create new storage media resources, e.g. hard disk images and ISO disk images
+        /// see http://msdn.microsoft.com/en-us/library/hh859775(v=vs.85).aspx
+        /// </summary>
+        /// <param name="wmiQuery"></param>
+        /// <returns></returns>
+        private static StorageAllocationSettingData CloneStorageAllocationSetting(string wmiQuery)
+        {
+            var defaultDiskImageSettingsObjs = StorageAllocationSettingData.GetInstances(wmiQuery);
+
+            // assert
+            if (defaultDiskImageSettingsObjs.Count != 1)
+            {
+                var errMsg = string.Format("Failed to find Msvm_StorageAllocationSettingData for the query {0}", wmiQuery);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            StorageAllocationSettingData defaultDiskDriveSettings = defaultDiskImageSettingsObjs.OfType<StorageAllocationSettingData>().First();
+            return new StorageAllocationSettingData((ManagementBaseObject)defaultDiskDriveSettings.LateBoundObject.Clone());
+        }
+
+        /// < summary>
+        /// Removes a storage resource from a computer system.
+        /// </summary>
+        /// <param name="storageSettings">Path that uniquely identifies the resource.</param>
+        /// <param name="vm">VM to which the disk image will be attached.</param>
+        // Add new 
+        private void RemoveNetworkResource(ManagementPath resourcePath)
+        {
+            var virtSwitchMgmtSvc = GetVirtualSwitchManagementService();
+            ManagementPath jobPath;
+            var ret_val = virtSwitchMgmtSvc.RemoveResourceSettings(
+                new ManagementPath[] { resourcePath },
+                out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to remove network resources {0} from switch due to {1}",
+                    resourcePath.Path,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        /// < summary>
+        /// Removes a storage resource from a computer system.
+        /// </summary>
+        /// <param name="storageSettings">Path that uniquely identifies the resource.</param>
+        /// <param name="vm">VM to which the disk image will be attached.</param>
+        private void RemoveStorageResource(ManagementPath resourcePath, ComputerSystem vm)
+        {
+            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+            ManagementPath jobPath;
+            var ret_val = virtSysMgmtSvc.RemoveResourceSettings(
+                new ManagementPath[] { resourcePath },
+                out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to remove resource {0} from VM {1} (GUID {2}) due to {3}",
+                    resourcePath.Path,
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        public void SetState(ComputerSystem vm, ushort requiredState)
+        {
+            logger.InfoFormat(
+                "Changing state of {0} (GUID {1}) to {2}", 
+                vm.ElementName, 
+                vm.Name,  
+                RequiredState.ToString(requiredState));
+
+            ManagementPath jobPath;
+            // DateTime is unused
+            var ret_val = vm.RequestStateChange(requiredState, new DateTime(), out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val == 32775)
+            {   // TODO: check
+                logger.InfoFormat("RequestStateChange returned 32775, which means vm in wrong state for requested state change.  Treating as if requested state was reached");
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to change state of VM {0} (GUID {1}) to {2} due to {3}",
+                    vm.ElementName,
+                    vm.Name,
+                    RequiredState.ToString(requiredState),
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            logger.InfoFormat(
+                "Successfully changed vm state of {0} (GUID {1} to requested state {2}", 
+                vm.ElementName, 
+                vm.Name,  
+                requiredState);
+        }
+
+
+        //TODO:  Write method to delete SwitchPort based on Name
+        /// <summary>
+        /// Delete switch port by removing settings from the switch
+        /// </summary>
+        /// <param name="elementName"></param>
+        /// <returns></returns>
+        public void DeleteSwitchPort(string elementName)
+        {
+            // Get NIC path
+            var condition = string.Format("ElementName=\"{0}\"", elementName);
+            var virtSwitchMgmtSvc = GetVirtualSwitchManagementService();
+
+            var switchPortCollection = EthernetSwitchPort.GetInstances(virtSwitchMgmtSvc.Scope, condition);
+            if (switchPortCollection.Count == 0)
+            {
+                return;
+            }
+
+            foreach (EthernetSwitchPort port in switchPortCollection)
+            {
+                var settings = GetSyntheticEthernetPortSettings(port);
+                RemoveNetworkResource(settings.Path);
+            }
+        }
+
+        public SyntheticEthernetPortSettingData GetSyntheticEthernetPortSettings(EthernetSwitchPort port)
+        {
+            // An ASSOCIATOR object provides the cross reference from the EthernetSwitchPort and the 
+            // SyntheticEthernetPortSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(port.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(port.Scope, wmiObjQuery);
+            var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get());
+
+            // When snapshots are taken into account, there can be multiple settings objects
+            // take the first one that isn't a snapshot
+            foreach (SyntheticEthernetPortSettingData wmiObj in wmiObjCollection)
+            {
+                return wmiObj;
+            }
+
+            var errMsg = string.Format("No SyntheticEthernetPortSettingData for port {0}, path {1}", port.ElementName, port.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        /// <summary>
+        /// Adds storage images to coputer system (disk image, iso image).
+        /// </summary>
+        /// <param name="storageSettings">Msvm_StorageAllocationSettings with HostResource configured with image
+        /// file and Parent set to a controller associated with the ComputerSystem</param>
+        /// <param name="vm">VM to which the disk image will be attached.</param>
+        // Add new 
+        private ManagementPath[] AddStorageResource(string[] storageSettings, ComputerSystem vm)
+        {
+            return AddVirtualResource(storageSettings, vm);
+        }
+
+        private ManagementPath[] AddVirtualResource(string[] resourceSettings, ComputerSystem vm )
+        {
+            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+            ManagementPath jobPath;
+            ManagementPath[] resourcePaths;
+            var ret_val = virtSysMgmtSvc.AddResourceSettings(
+                vm.Path,
+                resourceSettings,
+                out jobPath,
+                out resourcePaths);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to add resources to VM {0} (GUID {1}) due to {2}",
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return resourcePaths;
+        }
+
+        private ManagementPath[] AddFeatureSettings(string[] featureSettings, ManagementPath affectedConfiguration)
+        {
+            var virtSysMgmtSvc = GetVirtualisationSystemManagementService();
+
+            ManagementPath jobPath;
+            ManagementPath[] resultSettings;
+            var ret_val = virtSysMgmtSvc.AddFeatureSettings(
+                affectedConfiguration,
+                featureSettings,
+                out jobPath,
+                out resultSettings);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to add features settings {0} to resource {1} due to {2}",
+                    featureSettings,
+                    affectedConfiguration,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return resultSettings;
+        }
+
+        private ManagementPath SetPortVlan(string vlan, EthernetPortAllocationSettingData portPath)
+        {
+            logger.DebugFormat("Setting VLAN to {0}", vlan);
+
+            var vmVirtMgmtSvc = GetVirtualisationSystemManagementService();
+            EthernetSwitchPortVlanSettingData.GetInstances();
+
+            // Create NIC resource by cloning the default NIC 
+            var vlanSettings = EthernetSwitchPortVlanSettingData.GetInstances(vmVirtMgmtSvc.Scope, "InstanceID LIKE \"%Default\"");
+
+            // Assert
+            if (vlanSettings.Count != 1)
+            {
+                var errMsg = string.Format("Internal error, could not find default EthernetSwitchPortVlanSettingData instance");
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            var defaultVlanSettings = vlanSettings.OfType<EthernetSwitchPortVlanSettingData>().First();
+
+            var newVlanSettings = new EthernetSwitchPortVlanSettingData((ManagementBaseObject)defaultVlanSettings.LateBoundObject.Clone());
+
+            //  Assign configuration to new NIC
+            newVlanSettings.LateBoundObject["AccessVlanId"] = vlan;
+            newVlanSettings.LateBoundObject["OperationMode"] = 1; // Access=1, trunk=2, private=3 ;
+            newVlanSettings.CommitObject();
+
+            // Insert NIC into vm
+            string[] newResources = new string[] { newVlanSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20) };
+            ManagementPath[] newResourcePaths = AddFeatureSettings(newResources, portPath.Path);
+
+            // assert
+            if (newResourcePaths.Length != 1)
+            {
+                var errMsg = string.Format(
+                    "Failed to properly set VLAN to {0} for NIC on port {1}",
+                    vlan,
+                    portPath.Path);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return newResourcePaths[0];
+        }
+
         private void SetBandWidthLimit(ulong limit, EthernetPortAllocationSettingData portPath)
         {
             logger.DebugFormat("Setting network rate limit to {0}", limit);
@@ -1548,101 +1740,101 @@
             }
         }
 
-

-        /// <summary>

-        /// External VSwitch has an external NIC, and we assume there is only one external NIC and one external vswitch.

-        /// </summary>

-        /// <param name="vmSettings"></param>

-        /// <returns></returns>

-        /// <throw>Throws if there is no vswitch</throw>

-        /// <remarks>

-        /// With V1 API, external ethernet port was attached to the land endpoint, which was attached to the switch.

-        /// e.g. Msvm_ExternalEthernetPort -> SwitchLANEndpoint -> SwitchPort -> VirtualSwitch

-        /// 

-        /// With V2 API, there are two kinds of lan endpoint:  one on the computer system and one on the switch

-        /// e.g. Msvm_ExternalEthernetPort -> LANEndpoint -> LANEdnpoint -> EthernetSwitchPort -> VirtualEthernetSwitch

-        /// </remarks>

-        public static VirtualEthernetSwitch GetExternalVirtSwitch(String vSwitchName)

-        {

-            // Work back from the first *bound* external NIC we find.

-            var externNICs = ExternalEthernetPort.GetInstances("IsBound = TRUE");

-            VirtualEthernetSwitch vSwitch = null;

-            // Assert

-            if (externNICs.Count == 0 )

-            {

-                var errMsg = "No ExternalEthernetPort available to Hyper-V";

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            foreach(ExternalEthernetPort externNIC in externNICs.OfType<ExternalEthernetPort>()) { 

-            // A sequence of ASSOCIATOR objects need to be traversed to get from external NIC the vswitch.

-            // We use ManagementObjectSearcher objects to execute this sequence of questions

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var endpointQuery = new RelatedObjectQuery(externNIC.Path.Path, LANEndpoint.CreatedClassName);

-            var endpointSearch = new ManagementObjectSearcher(externNIC.Scope, endpointQuery);

-            var endpointCollection = new LANEndpoint.LANEndpointCollection(endpointSearch.Get());

-

-            // assert

-            if (endpointCollection.Count < 1 )

-            {

-                var errMsg = string.Format("No adapter-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            LANEndpoint adapterEndPoint = endpointCollection.OfType<LANEndpoint>().First();

-            var switchEndpointQuery = new RelatedObjectQuery(adapterEndPoint.Path.Path, LANEndpoint.CreatedClassName);

-            var switchEndpointSearch = new ManagementObjectSearcher(externNIC.Scope, switchEndpointQuery);

-            var switchEndpointCollection = new LANEndpoint.LANEndpointCollection(switchEndpointSearch.Get());

-        

-            // assert

-            if (endpointCollection.Count < 1)

-            {

-                var errMsg = string.Format("No Switch-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        

-            LANEndpoint switchEndPoint = switchEndpointCollection.OfType<LANEndpoint>().First();

-            var switchPortQuery = new RelatedObjectQuery(switchEndPoint.Path.Path, EthernetSwitchPort.CreatedClassName);

-            var switchPortSearch = new ManagementObjectSearcher(switchEndPoint.Scope, switchPortQuery);

-            var switchPortCollection = new EthernetSwitchPort.EthernetSwitchPortCollection(switchPortSearch.Get());

-        

-            // assert

-            if (switchPortCollection.Count < 1 )

-            {

-                var errMsg = string.Format("No SwitchPort for external NIC {0} on Hyper-V server", externNIC.Name);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        

-            EthernetSwitchPort switchPort = switchPortCollection.OfType<EthernetSwitchPort>().First();

-            var vSwitchQuery = new RelatedObjectQuery(switchPort.Path.Path, VirtualEthernetSwitch.CreatedClassName);

-            var vSwitchSearch = new ManagementObjectSearcher(externNIC.Scope, vSwitchQuery);

-            var vSwitchCollection = new VirtualEthernetSwitch.VirtualEthernetSwitchCollection(vSwitchSearch.Get());

-

-            // assert

-            if (vSwitchCollection.Count < 1)

-            {

-                var errMsg = string.Format("No virtual switch for external NIC {0} on Hyper-V server", externNIC.Name);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-            vSwitch = vSwitchCollection.OfType<VirtualEthernetSwitch>().First();

-            if (vSwitch.ElementName.Equals(vSwitchName) == true)

-            {

-                return vSwitch;

-            }

-            }

-            return vSwitch;

-        }

-

+
+        /// <summary>
+        /// External VSwitch has an external NIC, and we assume there is only one external NIC and one external vswitch.
+        /// </summary>
+        /// <param name="vmSettings"></param>
+        /// <returns></returns>
+        /// <throw>Throws if there is no vswitch</throw>
+        /// <remarks>
+        /// With V1 API, external ethernet port was attached to the land endpoint, which was attached to the switch.
+        /// e.g. Msvm_ExternalEthernetPort -> SwitchLANEndpoint -> SwitchPort -> VirtualSwitch
+        /// 
+        /// With V2 API, there are two kinds of lan endpoint:  one on the computer system and one on the switch
+        /// e.g. Msvm_ExternalEthernetPort -> LANEndpoint -> LANEdnpoint -> EthernetSwitchPort -> VirtualEthernetSwitch
+        /// </remarks>
+        public static VirtualEthernetSwitch GetExternalVirtSwitch(String vSwitchName)
+        {
+            // Work back from the first *bound* external NIC we find.
+            var externNICs = ExternalEthernetPort.GetInstances("IsBound = TRUE");
+            VirtualEthernetSwitch vSwitch = null;
+            // Assert
+            if (externNICs.Count == 0 )
+            {
+                var errMsg = "No ExternalEthernetPort available to Hyper-V";
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            foreach(ExternalEthernetPort externNIC in externNICs.OfType<ExternalEthernetPort>()) { 
+            // A sequence of ASSOCIATOR objects need to be traversed to get from external NIC the vswitch.
+            // We use ManagementObjectSearcher objects to execute this sequence of questions
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var endpointQuery = new RelatedObjectQuery(externNIC.Path.Path, LANEndpoint.CreatedClassName);
+            var endpointSearch = new ManagementObjectSearcher(externNIC.Scope, endpointQuery);
+            var endpointCollection = new LANEndpoint.LANEndpointCollection(endpointSearch.Get());
+
+            // assert
+            if (endpointCollection.Count < 1 )
+            {
+                var errMsg = string.Format("No adapter-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            LANEndpoint adapterEndPoint = endpointCollection.OfType<LANEndpoint>().First();
+            var switchEndpointQuery = new RelatedObjectQuery(adapterEndPoint.Path.Path, LANEndpoint.CreatedClassName);
+            var switchEndpointSearch = new ManagementObjectSearcher(externNIC.Scope, switchEndpointQuery);
+            var switchEndpointCollection = new LANEndpoint.LANEndpointCollection(switchEndpointSearch.Get());
+        
+            // assert
+            if (endpointCollection.Count < 1)
+            {
+                var errMsg = string.Format("No Switch-based LANEndpoint for external NIC {0} on Hyper-V server", externNIC.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        
+            LANEndpoint switchEndPoint = switchEndpointCollection.OfType<LANEndpoint>().First();
+            var switchPortQuery = new RelatedObjectQuery(switchEndPoint.Path.Path, EthernetSwitchPort.CreatedClassName);
+            var switchPortSearch = new ManagementObjectSearcher(switchEndPoint.Scope, switchPortQuery);
+            var switchPortCollection = new EthernetSwitchPort.EthernetSwitchPortCollection(switchPortSearch.Get());
+        
+            // assert
+            if (switchPortCollection.Count < 1 )
+            {
+                var errMsg = string.Format("No SwitchPort for external NIC {0} on Hyper-V server", externNIC.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        
+            EthernetSwitchPort switchPort = switchPortCollection.OfType<EthernetSwitchPort>().First();
+            var vSwitchQuery = new RelatedObjectQuery(switchPort.Path.Path, VirtualEthernetSwitch.CreatedClassName);
+            var vSwitchSearch = new ManagementObjectSearcher(externNIC.Scope, vSwitchQuery);
+            var vSwitchCollection = new VirtualEthernetSwitch.VirtualEthernetSwitchCollection(vSwitchSearch.Get());
+
+            // assert
+            if (vSwitchCollection.Count < 1)
+            {
+                var errMsg = string.Format("No virtual switch for external NIC {0} on Hyper-V server", externNIC.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+            vSwitch = vSwitchCollection.OfType<VirtualEthernetSwitch>().First();
+            if (vSwitch.ElementName.Equals(vSwitchName) == true)
+            {
+                return vSwitch;
+            }
+            }
+            return vSwitch;
+        }
+
 
         private static void ModifyFeatureVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
         {
@@ -1673,35 +1865,35 @@
             }
         }
 
-        private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)

-        {

-            // Resource settings are changed through the management service

-            System.Management.ManagementPath jobPath;

-            System.Management.ManagementPath[] results;

-

-            var ret_val = vmMgmtSvc.ModifyResourceSettings(

-                resourceSettings,

-                out jobPath,

-                out results);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

+        private static void ModifyVmResources(VirtualSystemManagementService vmMgmtSvc, ComputerSystem vm, string[] resourceSettings)
+        {
+            // Resource settings are changed through the management service
+            System.Management.ManagementPath jobPath;
+            System.Management.ManagementPath[] results;
+
+            var ret_val = vmMgmtSvc.ModifyResourceSettings(
+                resourceSettings,
+                out jobPath,
+                out results);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
         private static void ModifySystemSetting(VirtualSystemManagementService vmMgmtSvc, string systemSettings)
         {
             // Resource settings are changed through the management service
@@ -1727,43 +1919,43 @@
             }
         }
 
-        public void DeleteHostKvpItem(ComputerSystem vm, string key)

-        {

-            // Obtain controller for Hyper-V virtualisation subsystem

-            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();

-

-            // Create object to hold the data.

-            KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance();

-            kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey;

-            kvpItem.LateBoundObject["Data"] = "dummy";

-            kvpItem.LateBoundObject["Source"] = 0;

-            logger.Debug("VM " + vm.Name + " will have KVP key " + key + " removed.");

-

-            String kvpStr = kvpItem.LateBoundObject.GetText(TextFormat.CimDtd20);

-

-            // Update the resource settings for the VM.

-            ManagementPath jobPath;

-

-            uint ret_val = vmMgmtSvc.RemoveKvpItems(new String[] { kvpStr }, vm.Path, out jobPath);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",

-                    vm.ElementName,

-                    vm.Name,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

+        public void DeleteHostKvpItem(ComputerSystem vm, string key)
+        {
+            // Obtain controller for Hyper-V virtualisation subsystem
+            VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
+
+            // Create object to hold the data.
+            KvpExchangeDataItem kvpItem = KvpExchangeDataItem.CreateInstance();
+            kvpItem.LateBoundObject["Name"] = WmiCallsV2.CloudStackUserDataKey;
+            kvpItem.LateBoundObject["Data"] = "dummy";
+            kvpItem.LateBoundObject["Source"] = 0;
+            logger.Debug("VM " + vm.Name + " will have KVP key " + key + " removed.");
+
+            String kvpStr = kvpItem.LateBoundObject.GetText(TextFormat.CimDtd20);
+
+            // Update the resource settings for the VM.
+            ManagementPath jobPath;
+
+            uint ret_val = vmMgmtSvc.RemoveKvpItems(new String[] { kvpStr }, vm.Path, out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to update VM {0} (GUID {1}) due to {2} (ModifyVirtualSystem call), existing VM not deleted",
+                    vm.ElementName,
+                    vm.Name,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
         public Boolean TagVm(ComputerSystem vm)
         {
             VirtualSystemManagementService vmMgmtSvc = GetVirtualisationSystemManagementService();
@@ -1774,722 +1966,722 @@
             return true;
         }
 
-        private static ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name)

-        {

-            // Tweak default settings by basing new VM on default global setting object 

-            // with designed display name.

+        private static ComputerSystem CreateDefaultVm(VirtualSystemManagementService vmMgmtSvc, string name)
+        {
+            // Tweak default settings by basing new VM on default global setting object 
+            // with designed display name.
             UInt16 startupAction = 2; // Do nothing.
             UInt16 stopAction = 4; // Shutdown.
-            VirtualSystemSettingData vs_gs_data = VirtualSystemSettingData.CreateInstance();

-            vs_gs_data.LateBoundObject["ElementName"] = name;

+            VirtualSystemSettingData vs_gs_data = VirtualSystemSettingData.CreateInstance();
+            vs_gs_data.LateBoundObject["ElementName"] = name;
             vs_gs_data.LateBoundObject["AutomaticStartupAction"] = startupAction.ToString();
             vs_gs_data.LateBoundObject["AutomaticShutdownAction"] = stopAction.ToString();
             vs_gs_data.LateBoundObject["Notes"] = new string[] { "CloudStack creating VM, do not edit. \n" };
-

-            System.Management.ManagementPath jobPath;

-            System.Management.ManagementPath defined_sys;

-            var ret_val = vmMgmtSvc.DefineSystem(

-                null,

-                new string[0],

-                vs_gs_data.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20),

-                out jobPath,

-                out defined_sys);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                JobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to create VM {0} due to {1} (DefineVirtualSystem call)",

-                    name, ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            logger.DebugFormat(CultureInfo.InvariantCulture, "Created VM {0}", name);

-

-            // Is the defined_system real?

-            var vm = new ComputerSystem(defined_sys);

-

-            // Assertion

-            if (vm.ElementName.CompareTo(name) != 0)

-            {

-                var errMsg = string.Format(

-                    "New VM created with wrong name (is {0}, should be {1}, GUID {2})",

-                    vm.ElementName,

-                    name,

-                    vm.Name);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return vm;

-        }

-

-        public VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService()

-        {

-            // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set

-            // of local instances, which should be size 1.

-            var virtSwtichSvcCollection = VirtualEthernetSwitchManagementService.GetInstances();

-            foreach (VirtualEthernetSwitchManagementService item in virtSwtichSvcCollection)

-            {

-                return item;

-            }

-

-            var errMsg = string.Format("No Hyper-V subsystem on server");

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        /// <summary>

-        /// Always produces a VHDX.

-        /// </summary>

-        /// <param name="MaxInternalSize"></param>

-        /// <param name="Path"></param>

-        public void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path)

-        {

-            // Produce description of the virtual disk in the format of a Msvm_VirtualHardDiskSettings object

-

-            // Example at http://www.getcodesamples.com/src/FC025DDC/76689747, but

-            // Is there a template we can use to fill in the settings?

-            var newVirtHDSettings = VirtualHardDiskSettingData.CreateInstance();

-            newVirtHDSettings.LateBoundObject["Type"] = 3; // Dynamic

-            newVirtHDSettings.LateBoundObject["Format"] = 3; // VHDX

-            newVirtHDSettings.LateBoundObject["Path"] = Path;

-            newVirtHDSettings.LateBoundObject["MaxInternalSize"] = MaxInternalSize;

-            newVirtHDSettings.LateBoundObject["BlockSize"] = 0; // Use defaults

-            newVirtHDSettings.LateBoundObject["LogicalSectorSize"] = 0; // Use defaults

-            newVirtHDSettings.LateBoundObject["PhysicalSectorSize"] = 0; // Use defaults

-

-            // Optional: newVirtHDSettings.CommitObject();

-

-            // Add the new vhd object as a virtual hard disk to the vm.

-            string newVirtHDSettingsString = newVirtHDSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);

-

-            // Resource settings are changed through the management service

-            System.Management.ManagementPath jobPath;

-            var imgMgr = GetImageManagementService();

-            var ret_val = imgMgr.CreateVirtualHardDisk(newVirtHDSettingsString, out jobPath);

-

-            // If the Job is done asynchronously

-            if (ret_val == ReturnCode.Started)

-            {

-                StorageJobCompleted(jobPath);

-            }

-            else if (ret_val != ReturnCode.Completed)

-            {

-                var errMsg = string.Format(

-                    "Failed to CreateVirtualHardDisk size {0}, path {1} due to {2}",

-                    MaxInternalSize,

-                    Path,

-                    ReturnCode.ToString(ret_val));

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        public ImageManagementService GetImageManagementService()

-        {

-            // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set

-            // of local instances, which should be size 1.

-

-            var coll = ImageManagementService.GetInstances();

-            foreach (ImageManagementService item in coll)

-            {

-                return item;

-            }

-

-            var errMsg = string.Format("No Hyper-V subsystem on server");

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-

-        public VirtualSystemManagementService GetVirtualisationSystemManagementService()

-        {

-            // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set

-            // of local instances, which should be size 1.

-           

-            var virtSysMgmtSvcCollection = VirtualSystemManagementService.GetInstances();

-            foreach (VirtualSystemManagementService item in virtSysMgmtSvcCollection)

-            {

-                return item;

-            }

-

-            var errMsg = string.Format("No Hyper-V subsystem on server");

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public VirtualSystemMigrationService GetVirtualisationSystemMigrationService()

-        {

-

-            var virtSysMigSvcCollection = VirtualSystemMigrationService.GetInstances();

-            foreach (VirtualSystemMigrationService item in virtSysMigSvcCollection)

-            {

-                return item;

-            }

-

-            var errMsg = string.Format("No Hyper-V migration service subsystem on server");

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        /// <summary>

-        /// Similar to http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx

-        /// </summary>

-        /// <param name="jobPath"></param>

-        /// <returns></returns>

-        private static void JobCompleted(ManagementPath jobPath)

-        {

-            ConcreteJob jobObj = null;

-            for(;;)

-            {

-                jobObj = new ConcreteJob(jobPath);

-                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)

-                {

-                    break;

-                }

-                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);

-                System.Threading.Thread.Sleep(1000);

-            }

-

-            if (jobObj.JobState != JobState.Completed)

-            {

-                var errMsg = string.Format(

-                    "Hyper-V Job failed, Error Code:{0}, Description: {1}", 

-                    jobObj.ErrorCode, 

-                    jobObj.ErrorDescription);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime);

-        }

-

-        private static void MigrationJobCompleted(ManagementPath jobPath)

-        {

-            MigrationJob jobObj = null;

-            for (;;)

-            {

-                jobObj = new MigrationJob(jobPath);

-                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)

-                {

-                    break;

-                }

-                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);

-                System.Threading.Thread.Sleep(1000);

-            }

-

-            if (jobObj.JobState != JobState.Completed)

-            {

-                var errMsg = string.Format(

-                    "Hyper-V Job failed, Error Code:{0}, Description: {1}",

-                    jobObj.ErrorCode,

-                    jobObj.ErrorDescription);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        private static void StorageJobCompleted(ManagementPath jobPath)

-        {

-            StorageJob jobObj = null;

-            for (; ; )

-            {

-                jobObj = new StorageJob(jobPath);

-                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)

-                {

-                    break;

-                }

-                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);

-                System.Threading.Thread.Sleep(1000);

-            }

-

-            if (jobObj.JobState != JobState.Completed)

-            {

-                var errMsg = string.Format(

-                    "Hyper-V Job failed, Error Code:{0}, Description: {1}",

-                    jobObj.ErrorCode,

-                    jobObj.ErrorDescription);

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-        }

-

-        public void GetProcessorResources(out uint sockets, out uint cores, out uint mhz)

-        {

-            //  Processor processors

-            cores = 0;

-            mhz = 0;

-            sockets = 0;

-            Processor.ProcessorCollection procCol = Processor.GetInstances();

-            foreach (Processor procInfo in procCol)

-            {

-                cores += procInfo.NumberOfCores;

-                mhz = procInfo.MaxClockSpeed;

-                sockets++;

-           }

-        }

-        

-        public void GetProcessorUsageInfo(out double cpuUtilization)

-        {

-            PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = 

-                            PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\"");

-            cpuUtilization = 100;

-            // Use the first one

-            foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll)

-            {

-                // Idle during a given internal 

-                // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html

-                cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime;            

-            }

-        }

-

-

-        public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs)

-        {

-            OperatingSystem0 os = new OperatingSystem0();

-            physicalRamKBs = os.TotalVisibleMemorySize;

-            freeMemoryKBs = os.FreePhysicalMemory;

-        }

-

-        public string GetDefaultVirtualDiskFolder()

-        {

-            VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances();

-            string defaultVirtualHardDiskPath = null;

-            foreach (VirtualSystemManagementServiceSettingData settings in coll)

-            {

-                defaultVirtualHardDiskPath = settings.DefaultVirtualHardDiskPath;

-            }

-

-            // assert

-            if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){

-                var errMsg = string.Format(

-                    "Hyper-V DefaultVirtualHardDiskPath is invalid!");

-                logger.Error(errMsg);

-                return null;

-            }

-            

-            return defaultVirtualHardDiskPath;

-        }

-

-        public ComputerSystem GetComputerSystem(string displayName)

-        {

-            var wmiQuery = String.Format("ElementName=\"{0}\"", displayName);

-            ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery);

-

-            // Return the first one

-            foreach (ComputerSystem vm in vmCollection)

-            {

-                return vm;

-            }

-            return null;

-        }

-

+
+            System.Management.ManagementPath jobPath;
+            System.Management.ManagementPath defined_sys;
+            var ret_val = vmMgmtSvc.DefineSystem(
+                null,
+                new string[0],
+                vs_gs_data.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20),
+                out jobPath,
+                out defined_sys);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                JobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to create VM {0} due to {1} (DefineVirtualSystem call)",
+                    name, ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            logger.DebugFormat(CultureInfo.InvariantCulture, "Created VM {0}", name);
+
+            // Is the defined_system real?
+            var vm = new ComputerSystem(defined_sys);
+
+            // Assertion
+            if (vm.ElementName.CompareTo(name) != 0)
+            {
+                var errMsg = string.Format(
+                    "New VM created with wrong name (is {0}, should be {1}, GUID {2})",
+                    vm.ElementName,
+                    name,
+                    vm.Name);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return vm;
+        }
+
+        public VirtualEthernetSwitchManagementService GetVirtualSwitchManagementService()
+        {
+            // VirtualSwitchManagementService is a singleton, most anonymous way of lookup is by asking for the set
+            // of local instances, which should be size 1.
+            var virtSwtichSvcCollection = VirtualEthernetSwitchManagementService.GetInstances();
+            foreach (VirtualEthernetSwitchManagementService item in virtSwtichSvcCollection)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        /// <summary>
+        /// Always produces a VHDX.
+        /// </summary>
+        /// <param name="MaxInternalSize"></param>
+        /// <param name="Path"></param>
+        public void CreateDynamicVirtualHardDisk(ulong MaxInternalSize, string Path)
+        {
+            // Produce description of the virtual disk in the format of a Msvm_VirtualHardDiskSettings object
+
+            // Example at http://www.getcodesamples.com/src/FC025DDC/76689747, but
+            // Is there a template we can use to fill in the settings?
+            var newVirtHDSettings = VirtualHardDiskSettingData.CreateInstance();
+            newVirtHDSettings.LateBoundObject["Type"] = 3; // Dynamic
+            newVirtHDSettings.LateBoundObject["Format"] = 3; // VHDX
+            newVirtHDSettings.LateBoundObject["Path"] = Path;
+            newVirtHDSettings.LateBoundObject["MaxInternalSize"] = MaxInternalSize;
+            newVirtHDSettings.LateBoundObject["BlockSize"] = 0; // Use defaults
+            newVirtHDSettings.LateBoundObject["LogicalSectorSize"] = 0; // Use defaults
+            newVirtHDSettings.LateBoundObject["PhysicalSectorSize"] = 0; // Use defaults
+
+            // Optional: newVirtHDSettings.CommitObject();
+
+            // Add the new vhd object as a virtual hard disk to the vm.
+            string newVirtHDSettingsString = newVirtHDSettings.LateBoundObject.GetText(System.Management.TextFormat.CimDtd20);
+
+            // Resource settings are changed through the management service
+            System.Management.ManagementPath jobPath;
+            var imgMgr = GetImageManagementService();
+            var ret_val = imgMgr.CreateVirtualHardDisk(newVirtHDSettingsString, out jobPath);
+
+            // If the Job is done asynchronously
+            if (ret_val == ReturnCode.Started)
+            {
+                StorageJobCompleted(jobPath);
+            }
+            else if (ret_val != ReturnCode.Completed)
+            {
+                var errMsg = string.Format(
+                    "Failed to CreateVirtualHardDisk size {0}, path {1} due to {2}",
+                    MaxInternalSize,
+                    Path,
+                    ReturnCode.ToString(ret_val));
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        public ImageManagementService GetImageManagementService()
+        {
+            // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set
+            // of local instances, which should be size 1.
+
+            var coll = ImageManagementService.GetInstances();
+            foreach (ImageManagementService item in coll)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+
+        public VirtualSystemManagementService GetVirtualisationSystemManagementService()
+        {
+            // VirtualSystemManagementService is a singleton, most anonymous way of lookup is by asking for the set
+            // of local instances, which should be size 1.
+           
+            var virtSysMgmtSvcCollection = VirtualSystemManagementService.GetInstances();
+            foreach (VirtualSystemManagementService item in virtSysMgmtSvcCollection)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public VirtualSystemMigrationService GetVirtualisationSystemMigrationService()
+        {
+
+            var virtSysMigSvcCollection = VirtualSystemMigrationService.GetInstances();
+            foreach (VirtualSystemMigrationService item in virtSysMigSvcCollection)
+            {
+                return item;
+            }
+
+            var errMsg = string.Format("No Hyper-V migration service subsystem on server");
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        /// <summary>
+        /// Similar to http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx
+        /// </summary>
+        /// <param name="jobPath"></param>
+        /// <returns></returns>
+        private static void JobCompleted(ManagementPath jobPath)
+        {
+            ConcreteJob jobObj = null;
+            for(;;)
+            {
+                jobObj = new ConcreteJob(jobPath);
+                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)
+                {
+                    break;
+                }
+                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);
+                System.Threading.Thread.Sleep(1000);
+            }
+
+            if (jobObj.JobState != JobState.Completed)
+            {
+                var errMsg = string.Format(
+                    "Hyper-V Job failed, Error Code:{0}, Description: {1}", 
+                    jobObj.ErrorCode, 
+                    jobObj.ErrorDescription);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            logger.DebugFormat("WMI job succeeded: {0}, Elapsed={1}", jobObj.Description, jobObj.ElapsedTime);
+        }
+
+        private static void MigrationJobCompleted(ManagementPath jobPath)
+        {
+            MigrationJob jobObj = null;
+            for (;;)
+            {
+                jobObj = new MigrationJob(jobPath);
+                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)
+                {
+                    break;
+                }
+                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);
+                System.Threading.Thread.Sleep(1000);
+            }
+
+            if (jobObj.JobState != JobState.Completed)
+            {
+                var errMsg = string.Format(
+                    "Hyper-V Job failed, Error Code:{0}, Description: {1}",
+                    jobObj.ErrorCode,
+                    jobObj.ErrorDescription);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        private static void StorageJobCompleted(ManagementPath jobPath)
+        {
+            StorageJob jobObj = null;
+            for (; ; )
+            {
+                jobObj = new StorageJob(jobPath);
+                if (jobObj.JobState != JobState.Starting && jobObj.JobState != JobState.Running)
+                {
+                    break;
+                }
+                logger.InfoFormat("In progress... {0}% completed.", jobObj.PercentComplete);
+                System.Threading.Thread.Sleep(1000);
+            }
+
+            if (jobObj.JobState != JobState.Completed)
+            {
+                var errMsg = string.Format(
+                    "Hyper-V Job failed, Error Code:{0}, Description: {1}",
+                    jobObj.ErrorCode,
+                    jobObj.ErrorDescription);
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+        }
+
+        public void GetProcessorResources(out uint sockets, out uint cores, out uint mhz)
+        {
+            //  Processor processors
+            cores = 0;
+            mhz = 0;
+            sockets = 0;
+            Processor.ProcessorCollection procCol = Processor.GetInstances();
+            foreach (Processor procInfo in procCol)
+            {
+                cores += procInfo.NumberOfCores;
+                mhz = procInfo.MaxClockSpeed;
+                sockets++;
+           }
+        }
+        
+        public void GetProcessorUsageInfo(out double cpuUtilization)
+        {
+            PerfFormattedData_Counters_ProcessorInformation.PerfFormattedData_Counters_ProcessorInformationCollection coll = 
+                            PerfFormattedData_Counters_ProcessorInformation.GetInstances("Name=\"_Total\"");
+            cpuUtilization = 100;
+            // Use the first one
+            foreach (PerfFormattedData_Counters_ProcessorInformation procInfo in coll)
+            {
+                // Idle during a given internal 
+                // See http://library.wmifun.net/cimv2/win32_perfformatteddata_counters_processorinformation.html
+                cpuUtilization = 100.0 - (double)procInfo.PercentIdleTime;            
+            }
+        }
+
+
+        public void GetMemoryResources(out ulong physicalRamKBs, out ulong freeMemoryKBs)
+        {
+            OperatingSystem0 os = new OperatingSystem0();
+            physicalRamKBs = os.TotalVisibleMemorySize;
+            freeMemoryKBs = os.FreePhysicalMemory;
+        }
+
+        public string GetDefaultVirtualDiskFolder()
+        {
+            VirtualSystemManagementServiceSettingData.VirtualSystemManagementServiceSettingDataCollection coll = VirtualSystemManagementServiceSettingData.GetInstances();
+            string defaultVirtualHardDiskPath = null;
+            foreach (VirtualSystemManagementServiceSettingData settings in coll)
+            {
+                defaultVirtualHardDiskPath = settings.DefaultVirtualHardDiskPath;
+            }
+
+            // assert
+            if (!System.IO.Directory.Exists(defaultVirtualHardDiskPath) ){
+                var errMsg = string.Format(
+                    "Hyper-V DefaultVirtualHardDiskPath is invalid!");
+                logger.Error(errMsg);
+                return null;
+            }
+            
+            return defaultVirtualHardDiskPath;
+        }
+
+        public ComputerSystem GetComputerSystem(string displayName)
+        {
+            var wmiQuery = String.Format("ElementName=\"{0}\"", displayName);
+            ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances(wmiQuery);
+
+            // Return the first one
+            foreach (ComputerSystem vm in vmCollection)
+            {
+                return vm;
+            }
+            return null;
+        }
+
         public ComputerSystem.ComputerSystemCollection GetComputerSystemCollection()
         {
             var wmiQuery = String.Format("Caption=\"Virtual Machine\"");
             return ComputerSystem.GetInstances(wmiQuery);
         }
 
-        public Dictionary<String, VmState> GetVmSync(String privateIpAddress)

-        {

-            List<String> vms = GetVmElementNames();

-            Dictionary<String, VmState> vmSyncStates = new Dictionary<string, VmState>();

-            String vmState;

-            foreach (String vm in vms)

-            {

-                 vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState);

-                 vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress));

-            }

-            return vmSyncStates;

-        }

-

-        public List<string> GetVmElementNames()

-        {

-            List<string> result = new List<string>();

-            ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances();

-

-            // Return the first one

-            foreach (ComputerSystem vm in vmCollection)

-            {

-                if (vm.Caption.StartsWith("Hosting Computer System") )

-                {

-                    continue;

-                }

-                result.Add(vm.ElementName);

-            }

-            return result;

-        }

-

-        public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings)

-        {

-            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 

-            // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);

-            var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get());

-

-            foreach (ProcessorSettingData wmiObj in wmiObjCollection)

-            {

-                return wmiObj;

-            }

-

-            var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings)

-        {

-            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 

-            // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);

-            var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get());

-

-            foreach (MemorySettingData wmiObj in wmiObjCollection)

-            {

-                return wmiObj;

-            }

-

-            var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-

-        public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings)

-        {

-            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);

-

-            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)

-            {

-                // DVD drive is '16', see http://msdn.microsoft.com/en-us/library/hh850200(v=vs.85).aspx 

-                if (wmiObj.ResourceType == 16)

-                {

-                    return wmiObj;

-                }

-            }

-

-            var errMsg = string.Format(

-                                "Cannot find the Dvd drive in VirtualSystemSettingData {0}",

-                                vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr)

-        {

-            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);

-

-            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)

-            {

-                if (wmiObj.ResourceSubType == IDE_CONTROLLER && wmiObj.Address == cntrllerAddr)

-                {

-                    return wmiObj;

-                }

-            }

-

-            var errMsg = string.Format(

-                                "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}", 

-                                cntrllerAddr, 

-                                vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public ResourceAllocationSettingData GetScsiControllerSettings(VirtualSystemSettingData vmSettings)

-        {

-            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);

-

-            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)

-            {

-                if (wmiObj.ResourceSubType == SCSI_CONTROLLER)

-                {

-                    return wmiObj;

-                }

-            }

-

-            var errMsg = string.Format(

-                                "Cannot find the Microsoft Synthetic SCSI Controller in VirtualSystemSettingData {1}",

-                                vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        /// <summary>

-        /// VM resources, typically hardware a described by a generic MSVM_ResourceAllocationSettingData object.  The hardware type being 

-        /// described is identified in two ways:  in general terms using an enum in the ResourceType field, and in terms of the implementation 

-        /// using text in the ResourceSubType field.

-        /// See http://msdn.microsoft.com/en-us/library/cc136877%28v=vs.85%29.aspx

-        /// </summary>

-        /// <param name="vmSettings"></param>

-        /// <returns></returns>

-        public ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings)

-        {

-            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 

-            // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);

-            var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get());

-

-            if (wmiObjCollection != null)

-            {

-                return wmiObjCollection;

-            }

-

-            var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm)

-        {

-            // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-

-            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 

-            // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, EthernetPortAllocationSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);

-            var wmiObjCollection = new EthernetPortAllocationSettingData.EthernetPortAllocationSettingDataCollection(wmiObjectSearch.Get());

-

-            var result = new List<EthernetPortAllocationSettingData>(wmiObjCollection.Count);

-            foreach (EthernetPortAllocationSettingData item in wmiObjCollection)

-            {

-                result.Add(item);

-            }

-            return result.ToArray();

-        }

-

-        public StorageAllocationSettingData[] GetStorageSettings(ComputerSystem vm)

-        {

-            // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, StorageAllocationSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);

-            var wmiObjCollection = new StorageAllocationSettingData.StorageAllocationSettingDataCollection(wmiObjectSearch.Get());

-

-            var result = new List<StorageAllocationSettingData>(wmiObjCollection.Count);

-            foreach (StorageAllocationSettingData item in wmiObjCollection)

-            {

-                result.Add(item);

-            }

-            return result.ToArray();

-        }

-

-

-        public EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection)

-        {

-            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 

-            // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(ethernetConnection.Path.Path, EthernetSwitchPortVlanSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(ethernetConnection.Scope, wmiObjQuery);

-            var wmiObjCollection = new EthernetSwitchPortVlanSettingData.EthernetSwitchPortVlanSettingDataCollection(wmiObjectSearch.Get());

-

-            if (wmiObjCollection.Count == 0)

-            {

-                return null;

-            }

-

-            // Assert

-            if (wmiObjCollection.Count > 1)

-            {

-                var errMsg = string.Format("Internal error, morn one VLAN settings for a single ethernetConnection");

-                var ex = new WmiException(errMsg);

-                logger.Error(errMsg, ex);

-                throw ex;

-            }

-

-            return wmiObjCollection.OfType<EthernetSwitchPortVlanSettingData>().First();

-        }

-        

-

-        public SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm)

-        {

-            // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the 

-            // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData.

-            // However, generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //

-            // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);

-            //

-            VirtualSystemSettingData vmSettings = GetVmSettings(vm);

-

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);

-            var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get());

-

-            List<SyntheticEthernetPortSettingData> results = new List<SyntheticEthernetPortSettingData>(wmiObjCollection.Count);

-            foreach (SyntheticEthernetPortSettingData item in wmiObjCollection)

-            {

-                results.Add(item);

-            }

-

-            return results.ToArray();

-        }

-

-        public string GetDefaultDataRoot()

-        {

-            string defaultRootPath = null;

-            VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance();

-            defaultRootPath = vs_mgmt_data.DefaultVirtualHardDiskPath;

-            if (defaultRootPath == null) {

-                defaultRootPath = Path.GetPathRoot(Environment.SystemDirectory)  +

-                    "\\Users\\Public\\Documents\\Hyper-V\\Virtual hard disks";

-            }

-

-            return defaultRootPath;

-        }

-

-        public VirtualSystemSettingData GetVmSettings(ComputerSystem vm)

-        {

-            // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the 

-            // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);

-            var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get());

-

-            // When snapshots are taken into account, there can be multiple settings objects

-            // take the first one that isn't a snapshot

-            foreach (VirtualSystemSettingData wmiObj in wmiObjCollection)

-            {

-                if (wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Realized" ||

-                    wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Planned")

-                {

-                    return wmiObj;

-                }

-            }

-

-            var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings)

-        {

-            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 

-            // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.

-            // Instead, we use the System.Management to code the equivalant of 

-            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);

-            //

-            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, KvpExchangeComponentSettingData.CreatedClassName);

-

-            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain

-            // the virtualisation objects.

-            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);

-            var wmiObjCollection = new KvpExchangeComponentSettingData.KvpExchangeComponentSettingDataCollection(wmiObjectSearch.Get());

-

-            foreach (KvpExchangeComponentSettingData wmiObj in wmiObjCollection)

-            {

-                return wmiObj;

-            }

-

-            var errMsg = string.Format("No KvpExchangeComponentSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);

-            var ex = new WmiException(errMsg);

-            logger.Error(errMsg, ex);

-            throw ex;

-        }

-

-        public void GetSummaryInfo(Dictionary<string, VmStatsEntry> vmProcessorInfo, List<System.Management.ManagementPath> vmsToInspect)

-        {

-            // Process info available from WMI, 

-            // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx

-            uint[] requestedInfo = new uint[] {  // TODO: correct?

-                    0, // Name

-                    1, // ElementName

-                    4, // Number of processes

-                    101 // ProcessorLoad

-                };

-

-            System.Management.ManagementBaseObject[] sysSummary;

-            var vmsvc = GetVirtualisationSystemManagementService();

-            System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray();

-            vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary);

-

-            foreach (var summary in sysSummary)

-            {

-

-                var summaryInfo = new SummaryInformation(summary);

-

-                logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " +

-                                summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad);

-                var vmInfo = new VmStatsEntry

-                {

-                    cpuUtilization = summaryInfo.ProcessorLoad,

-                    numCPUs = summaryInfo.NumberOfProcessors,

-                    networkReadKBs = 1,

-                    networkWriteKBs = 1,

-                    entityType = "vm"

-                };

-                vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo);

-            }

-        }

+        public Dictionary<String, VmState> GetVmSync(String privateIpAddress)
+        {
+            List<String> vms = GetVmElementNames();
+            Dictionary<String, VmState> vmSyncStates = new Dictionary<string, VmState>();
+            String vmState;
+            foreach (String vm in vms)
+            {
+                 vmState = EnabledState.ToCloudStackState(GetComputerSystem(vm).EnabledState);
+                 vmSyncStates.Add(vm, new VmState(vmState, privateIpAddress));
+            }
+            return vmSyncStates;
+        }
+
+        public List<string> GetVmElementNames()
+        {
+            List<string> result = new List<string>();
+            ComputerSystem.ComputerSystemCollection vmCollection = ComputerSystem.GetInstances();
+
+            // Return the first one
+            foreach (ComputerSystem vm in vmCollection)
+            {
+                if (vm.Caption.StartsWith("Hosting Computer System") )
+                {
+                    continue;
+                }
+                result.Add(vm.ElementName);
+            }
+            return result;
+        }
+
+        public ProcessorSettingData GetProcSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // ProcessorSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ProcessorSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new ProcessorSettingData.ProcessorSettingDataCollection(wmiObjectSearch.Get());
+
+            foreach (ProcessorSettingData wmiObj in wmiObjCollection)
+            {
+                return wmiObj;
+            }
+
+            var errMsg = string.Format("No ProcessorSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public MemorySettingData GetMemSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // MemorySettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, MemorySettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new MemorySettingData.MemorySettingDataCollection(wmiObjectSearch.Get());
+
+            foreach (MemorySettingData wmiObj in wmiObjCollection)
+            {
+                return wmiObj;
+            }
+
+            var errMsg = string.Format("No MemorySettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+
+        public ResourceAllocationSettingData GetDvdDriveSettings(VirtualSystemSettingData vmSettings)
+        {
+            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
+
+            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
+            {
+                // DVD drive is '16', see http://msdn.microsoft.com/en-us/library/hh850200(v=vs.85).aspx 
+                if (wmiObj.ResourceType == 16)
+                {
+                    return wmiObj;
+                }
+            }
+
+            var errMsg = string.Format(
+                                "Cannot find the Dvd drive in VirtualSystemSettingData {0}",
+                                vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public ResourceAllocationSettingData GetIDEControllerSettings(VirtualSystemSettingData vmSettings, string cntrllerAddr)
+        {
+            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
+
+            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
+            {
+                if (wmiObj.ResourceSubType == IDE_CONTROLLER && wmiObj.Address == cntrllerAddr)
+                {
+                    return wmiObj;
+                }
+            }
+
+            var errMsg = string.Format(
+                                "Cannot find the Microsoft Emulated IDE Controlle at address {0} in VirtualSystemSettingData {1}", 
+                                cntrllerAddr, 
+                                vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public ResourceAllocationSettingData GetScsiControllerSettings(VirtualSystemSettingData vmSettings)
+        {
+            var wmiObjCollection = GetResourceAllocationSettings(vmSettings);
+
+            foreach (ResourceAllocationSettingData wmiObj in wmiObjCollection)
+            {
+                if (wmiObj.ResourceSubType == SCSI_CONTROLLER)
+                {
+                    return wmiObj;
+                }
+            }
+
+            var errMsg = string.Format(
+                                "Cannot find the Microsoft Synthetic SCSI Controller in VirtualSystemSettingData {1}",
+                                vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        /// <summary>
+        /// VM resources, typically hardware a described by a generic MSVM_ResourceAllocationSettingData object.  The hardware type being 
+        /// described is identified in two ways:  in general terms using an enum in the ResourceType field, and in terms of the implementation 
+        /// using text in the ResourceSubType field.
+        /// See http://msdn.microsoft.com/en-us/library/cc136877%28v=vs.85%29.aspx
+        /// </summary>
+        /// <param name="vmSettings"></param>
+        /// <returns></returns>
+        public ResourceAllocationSettingData.ResourceAllocationSettingDataCollection GetResourceAllocationSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // ResourceAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, ResourceAllocationSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new ResourceAllocationSettingData.ResourceAllocationSettingDataCollection(wmiObjectSearch.Get());
+
+            if (wmiObjCollection != null)
+            {
+                return wmiObjCollection;
+            }
+
+            var errMsg = string.Format("No ResourceAllocationSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public EthernetPortAllocationSettingData[] GetEthernetConnections(ComputerSystem vm)
+        {
+            // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, EthernetPortAllocationSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new EthernetPortAllocationSettingData.EthernetPortAllocationSettingDataCollection(wmiObjectSearch.Get());
+
+            var result = new List<EthernetPortAllocationSettingData>(wmiObjCollection.Count);
+            foreach (EthernetPortAllocationSettingData item in wmiObjCollection)
+            {
+                result.Add(item);
+            }
+            return result.ToArray();
+        }
+
+        public StorageAllocationSettingData[] GetStorageSettings(ComputerSystem vm)
+        {
+            // ComputerSystem -> VirtualSystemSettingData -> EthernetPortAllocationSettingData
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, StorageAllocationSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new StorageAllocationSettingData.StorageAllocationSettingDataCollection(wmiObjectSearch.Get());
+
+            var result = new List<StorageAllocationSettingData>(wmiObjCollection.Count);
+            foreach (StorageAllocationSettingData item in wmiObjCollection)
+            {
+                result.Add(item);
+            }
+            return result.ToArray();
+        }
+
+
+        public EthernetSwitchPortVlanSettingData GetVlanSettings(EthernetPortAllocationSettingData ethernetConnection)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // EthernetPortAllocationSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(ethernetConnection.Path.Path, EthernetSwitchPortVlanSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(ethernetConnection.Scope, wmiObjQuery);
+            var wmiObjCollection = new EthernetSwitchPortVlanSettingData.EthernetSwitchPortVlanSettingDataCollection(wmiObjectSearch.Get());
+
+            if (wmiObjCollection.Count == 0)
+            {
+                return null;
+            }
+
+            // Assert
+            if (wmiObjCollection.Count > 1)
+            {
+                var errMsg = string.Format("Internal error, morn one VLAN settings for a single ethernetConnection");
+                var ex = new WmiException(errMsg);
+                logger.Error(errMsg, ex);
+                throw ex;
+            }
+
+            return wmiObjCollection.OfType<EthernetSwitchPortVlanSettingData>().First();
+        }
+        
+
+        public SyntheticEthernetPortSettingData[] GetEthernetPortSettings(ComputerSystem vm)
+        {
+            // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the 
+            // SyntheticEthernetPortSettingData, via the VirtualSystemSettingData.
+            // However, generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //
+            // string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
+            //
+            VirtualSystemSettingData vmSettings = GetVmSettings(vm);
+
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, SyntheticEthernetPortSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);
+            var wmiObjCollection = new SyntheticEthernetPortSettingData.SyntheticEthernetPortSettingDataCollection(wmiObjectSearch.Get());
+
+            List<SyntheticEthernetPortSettingData> results = new List<SyntheticEthernetPortSettingData>(wmiObjCollection.Count);
+            foreach (SyntheticEthernetPortSettingData item in wmiObjCollection)
+            {
+                results.Add(item);
+            }
+
+            return results.ToArray();
+        }
+
+        public string GetDefaultDataRoot()
+        {
+            string defaultRootPath = null;
+            VirtualSystemManagementServiceSettingData vs_mgmt_data = VirtualSystemManagementServiceSettingData.CreateInstance();
+            defaultRootPath = vs_mgmt_data.DefaultVirtualHardDiskPath;
+            if (defaultRootPath == null) {
+                defaultRootPath = Path.GetPathRoot(Environment.SystemDirectory)  +
+                    "\\Users\\Public\\Documents\\Hyper-V\\Virtual hard disks";
+            }
+
+            return defaultRootPath;
+        }
+
+        public VirtualSystemSettingData GetVmSettings(ComputerSystem vm)
+        {
+            // An ASSOCIATOR object provides the cross reference from the ComputerSettings and the 
+            // VirtualSystemSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vm.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vm.Path.Path, VirtualSystemSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vm.Scope, wmiObjQuery);
+            var wmiObjCollection = new VirtualSystemSettingData.VirtualSystemSettingDataCollection(wmiObjectSearch.Get());
+
+            // When snapshots are taken into account, there can be multiple settings objects
+            // take the first one that isn't a snapshot
+            foreach (VirtualSystemSettingData wmiObj in wmiObjCollection)
+            {
+                if (wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Realized" ||
+                    wmiObj.VirtualSystemType == "Microsoft:Hyper-V:System:Planned")
+                {
+                    return wmiObj;
+                }
+            }
+
+            var errMsg = string.Format("No VirtualSystemSettingData for VM {0}, path {1}", vm.ElementName, vm.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public KvpExchangeComponentSettingData GetKvpSettings(VirtualSystemSettingData vmSettings)
+        {
+            // An ASSOCIATOR object provides the cross reference from the VirtualSystemSettingData and the 
+            // KvpExchangeComponentSettingData, but generated wrappers do not expose a ASSOCIATOR OF query as a method.
+            // Instead, we use the System.Management to code the equivalant of 
+            //  string query = string.Format( "ASSOCIATORS OF {{{0}}} WHERE ResultClass = {1}", vmSettings.path, resultclassName);
+            //
+            var wmiObjQuery = new RelatedObjectQuery(vmSettings.Path.Path, KvpExchangeComponentSettingData.CreatedClassName);
+
+            // NB: default scope of ManagementObjectSearcher is '\\.\root\cimv2', which does not contain
+            // the virtualisation objects.
+            var wmiObjectSearch = new ManagementObjectSearcher(vmSettings.Scope, wmiObjQuery);
+            var wmiObjCollection = new KvpExchangeComponentSettingData.KvpExchangeComponentSettingDataCollection(wmiObjectSearch.Get());
+
+            foreach (KvpExchangeComponentSettingData wmiObj in wmiObjCollection)
+            {
+                return wmiObj;
+            }
+
+            var errMsg = string.Format("No KvpExchangeComponentSettingData in VirtualSystemSettingData {0}", vmSettings.Path.Path);
+            var ex = new WmiException(errMsg);
+            logger.Error(errMsg, ex);
+            throw ex;
+        }
+
+        public void GetSummaryInfo(Dictionary<string, VmStatsEntry> vmProcessorInfo, List<System.Management.ManagementPath> vmsToInspect)
+        {
+            // Process info available from WMI, 
+            // See http://msdn.microsoft.com/en-us/library/hh850062(v=vs.85).aspx
+            uint[] requestedInfo = new uint[] {  // TODO: correct?
+                    0, // Name
+                    1, // ElementName
+                    4, // Number of processes
+                    101 // ProcessorLoad
+                };
+
+            System.Management.ManagementBaseObject[] sysSummary;
+            var vmsvc = GetVirtualisationSystemManagementService();
+            System.Management.ManagementPath[] vmPaths = vmsToInspect.ToArray();
+            vmsvc.GetSummaryInformation(requestedInfo, vmPaths, out sysSummary);
+
+            foreach (var summary in sysSummary)
+            {
+
+                var summaryInfo = new SummaryInformation(summary);
+
+                logger.Debug("VM " + summaryInfo.Name + "(elementName " + summaryInfo.ElementName + ") has " +
+                                summaryInfo.NumberOfProcessors + " CPUs, and load of " + summaryInfo.ProcessorLoad);
+                var vmInfo = new VmStatsEntry
+                {
+                    cpuUtilization = summaryInfo.ProcessorLoad,
+                    numCPUs = summaryInfo.NumberOfProcessors,
+                    networkReadKBs = 1,
+                    networkWriteKBs = 1,
+                    entityType = "vm"
+                };
+                vmProcessorInfo.Add(summaryInfo.ElementName, vmInfo);
+            }
+        }
 
         public string GetVmNote(System.Management.ManagementPath sysPath)
         {
@@ -2506,242 +2698,242 @@
 
             return null;
         }
-    }

-

-    public class WmiException : Exception

-    {

-        public WmiException()

-        {

-        }

-

-        public WmiException(string message)

-            : base(message)

-        {

-        }

-

-        public WmiException(string message, Exception inner)

-            : base(message, inner)

-        {

-        }

-    }

-

-    /// <summary>

-    /// Covers V2 API, see

-    /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx

-    /// </summary>

-    public static class ReturnCode

-    {

-        public const UInt32 Completed = 0;

-        public const UInt32 Started = 4096;

-        public const UInt32 Failed = 32768;

-        public const UInt32 AccessDenied = 32769;

-        public const UInt32 NotSupported = 32770;

-        public const UInt32 Unknown = 32771;

-        public const UInt32 Timeout = 32772;

-        public const UInt32 InvalidParameter = 32773;

-        public const UInt32 SystemInUse = 32774;

-        public const UInt32 InvalidState = 32775;

-        public const UInt32 IncorrectDataType = 32776;

-        public const UInt32 SystemNotAvailable = 32777;

-        public const UInt32 OutofMemory = 32778;

-        public static string ToString(UInt32 value)

-        {

-            string result = "Unknown return code";

-            switch (value)

-            {

-                case Completed: result = "Completed"; break;

-                case Started: result = "Started"; break;

-                case Failed: result = "Failed"; break;

-                case AccessDenied: result = "AccessDenied"; break;

-                case NotSupported: result = "NotSupported"; break;

-                case Unknown: result = "Unknown"; break;

-                case Timeout: result = "Timeout"; break;

-                case InvalidParameter: result = "InvalidParameter"; break;

-                case SystemInUse: result = "SystemInUse"; break;

-                case InvalidState: result = "InvalidState"; break;

-                case IncorrectDataType: result = "IncorrectDataType"; break;

-                case SystemNotAvailable: result = "SystemNotAvailable"; break;

-                case OutofMemory: result = "OutofMemory"; break;

-            }

-            return result;

-        }

-    }

-

-    /// <summary>

-    /// Covers V2 API, see

-    /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx

-    /// </summary>

-    public static class JobState

-    {

-        public const UInt16 New = 2;

-        public const UInt16 Starting = 3;

-        public const UInt16 Running = 4;

-        public const UInt16 Suspended = 5;

-        public const UInt16 ShuttingDown = 6;

-        public const UInt16 Completed = 7;

-        public const UInt16 Terminated = 8;

-        public const UInt16 Killed = 9;

-        public const UInt16 Exception = 10;

-        public const UInt16 Service = 11;

-        public static string ToString(UInt16 value)

-        {

-            string result = "Unknown JobState code";

-            switch (value)

-            {

-                case New: result = "New"; break;

-                case Starting: result = "Starting"; break;

-                case Running: result = "Running"; break;

-                case Suspended: result = "Suspended"; break;

-                case ShuttingDown: result = "ShuttingDown"; break;

-                case Completed: result = "Completed"; break;

-                case Terminated: result = "Terminated"; break;

-                case Killed: result = "Killed"; break;

-                case Exception: result = "Exception"; break;

-                case Service: result = "Service"; break;

-            }

-            return result;

-        }

-    }

-

-    /// <summary>

-    /// V2 API (see http://msdn.microsoft.com/en-us/library/hh850279(v=vs.85).aspx)

-    /// has removed 'Paused' and 'Suspended' as compared to the

-    /// V1 API (see http://msdn.microsoft.com/en-us/library/cc723874%28v=vs.85%29.aspx)

-    /// However, Paused and Suspended appear on the VM state transition table

-    /// (see http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods)

-    /// </summary>

-    public class RequiredState

-    {

-        public const UInt16 Enabled = 2;        // Turns the VM on.

-        public const UInt16 Disabled = 3;       // Turns the VM off.

-        public const UInt16 ShutDown = 4;

-        public const UInt16 Offline = 6;

-        //public const UInt16 Test = 7;

-        public const UInt16 Defer = 8;

-        // public const UInt16 Quiesce = 9;

-        // public const UInt16 Reboot = 10;        // A hard reset of the VM.

-        public const UInt16 Reset = 11;         // For future use.

-        public const UInt16 Paused = 9;     // Pauses the VM.

-        public const UInt16 Suspended = 32779;  // Saves the state of the VM.

-

-        public static string ToString(UInt16 value)

-        {

-            string result = "Unknown RequiredState code";

-            switch (value)

-            {

-                case Enabled: result = "Enabled"; break;

-                case Disabled: result = "Disabled"; break;

-                case ShutDown: result = "ShutDown"; break;

-                case Offline: result = "Offline"; break;

-                case Defer: result = "Defer"; break;

-                case Reset: result = "Reset"; break;

-            }

-            return result;

-        }

-    }

-

-    /// <summary>

-    /// V2 API specifies the states below in its  state transition graph at

-    /// http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods

-    /// However, the CIM standard has additional possibilities based on the description

-    /// of EnabledState.

-    /// The previous V1 API is described by 

-    /// http://msdn.microsoft.com/en-us/library/cc136822%28v=vs.85%29.aspx

-    /// </summary>

-        public class EnabledState

-    {

-            /// <summary>

-            /// The state of the VM could not be determined.

-            /// </summary>

-        public const UInt16 Unknown = 0;

-            /// <summary>

-            /// The VM is running.

-            /// </summary>

-        public const UInt16 Enabled = 2;

-            /// <summary>

-            /// The VM is turned off.

-            /// </summary>

-        public const UInt16 Disabled = 3;

-            /// <summary>

-            /// The VM is paused.

-            /// </summary>

-        public const UInt16 Paused = 32768;

-            /// <summary>

-            /// The VM is in a saved state.

-            /// </summary>

-        public const UInt16 Suspended = 32769;

-            /// <summary>

-            /// The VM is starting. This is a transitional state between 3 (Disabled)

-            /// or 32769 (Suspended) and 2 (Enabled) initiated by a call to the 

-            /// RequestStateChange method with a RequestedState parameter of 2 (Enabled).

-            /// </summary>

-        public const UInt16 Starting = 32770;

-            /// <summary>

-            /// Starting with Windows Server 2008 R2 this value is not supported. 

-            /// If the VM is performing a snapshot operation, the element at index 1 

-            /// of the OperationalStatus property array will contain 32768 (Creating Snapshot), 

-            /// 32769 (Applying Snapshot), or 32770 (Deleting Snapshot).

-            /// </summary>

-        public const UInt16 Snapshotting = 32771;

-            /// <summary>

-            /// The VM is saving its state. This is a transitional state between 2 (Enabled)

-            /// and 32769 (Suspended) initiated by a call to the RequestStateChange method 

-            /// with a RequestedState parameter of 32769 (Suspended).

-            /// </summary>

-        public const UInt16 Saving = 32773;

-            /// <summary>

-            /// The VM is turning off. This is a transitional state between 2 (Enabled) 

-            /// and 3 (Disabled) initiated by a call to the RequestStateChange method 

-            /// with a RequestedState parameter of 3 (Disabled) or a guest operating system 

-            /// initiated power off.

-            /// </summary>

-        public const UInt16 Stopping = 32774;

-            /// <summary>

-            /// The VM is pausing. This is a transitional state between 2 (Enabled) and 32768 (Paused) initiated by a call to the RequestStateChange method with a RequestedState parameter of 32768 (Paused).

-            /// </summary>

-        public const UInt16 Pausing = 32776;

-            /// <summary>

-            /// The VM is resuming from a paused state. This is a transitional state between 32768 (Paused) and 2 (Enabled).

-            /// </summary>

-        public const UInt16 Resuming = 32777;

-

-        public static string ToString(UInt16 value)

-        {

-            string result = "Unknown";

-            switch (value)

-            {

-                case Enabled: result = "Enabled"; break;

-                case Disabled: result = "Disabled"; break;

-                case Paused: result = "Paused"; break;

-                case Suspended: result = "Suspended"; break;

-                case Starting: result = "Starting"; break;

-                case Snapshotting: result = "Snapshotting"; break; // NOT used

-                case Saving: result = "Saving"; break;

-                case Stopping: result = "Stopping"; break;

-                case Pausing: result = "Pausing"; break;

-                case Resuming: result = "Resuming"; break;

-            }

-            return result;

-        }

-

-        public static string ToCloudStackState(UInt16 value)

-        {

-            string result = "Unknown";

-            switch (value)

-            {

-                case Enabled: result = "Running"; break;

-                case Disabled: result = "Stopped"; break;

-                case Paused: result = "Unknown"; break;

-                case Suspended: result = "Unknown"; break;

-                case Starting: result = "Starting"; break;

-                case Snapshotting: result = "Unknown"; break; // NOT used

-                case Saving: result = "Saving"; break;

-                case Stopping: result = "Stopping"; break;

-                case Pausing: result = "Unknown"; break;

-                case Resuming: result = "Starting"; break; 

-            }

-            return result;

-        }

+    }
+
+    public class WmiException : Exception
+    {
+        public WmiException()
+        {
+        }
+
+        public WmiException(string message)
+            : base(message)
+        {
+        }
+
+        public WmiException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+
+    /// <summary>
+    /// Covers V2 API, see
+    /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx
+    /// </summary>
+    public static class ReturnCode
+    {
+        public const UInt32 Completed = 0;
+        public const UInt32 Started = 4096;
+        public const UInt32 Failed = 32768;
+        public const UInt32 AccessDenied = 32769;
+        public const UInt32 NotSupported = 32770;
+        public const UInt32 Unknown = 32771;
+        public const UInt32 Timeout = 32772;
+        public const UInt32 InvalidParameter = 32773;
+        public const UInt32 SystemInUse = 32774;
+        public const UInt32 InvalidState = 32775;
+        public const UInt32 IncorrectDataType = 32776;
+        public const UInt32 SystemNotAvailable = 32777;
+        public const UInt32 OutofMemory = 32778;
+        public static string ToString(UInt32 value)
+        {
+            string result = "Unknown return code";
+            switch (value)
+            {
+                case Completed: result = "Completed"; break;
+                case Started: result = "Started"; break;
+                case Failed: result = "Failed"; break;
+                case AccessDenied: result = "AccessDenied"; break;
+                case NotSupported: result = "NotSupported"; break;
+                case Unknown: result = "Unknown"; break;
+                case Timeout: result = "Timeout"; break;
+                case InvalidParameter: result = "InvalidParameter"; break;
+                case SystemInUse: result = "SystemInUse"; break;
+                case InvalidState: result = "InvalidState"; break;
+                case IncorrectDataType: result = "IncorrectDataType"; break;
+                case SystemNotAvailable: result = "SystemNotAvailable"; break;
+                case OutofMemory: result = "OutofMemory"; break;
+            }
+            return result;
+        }
+    }
+
+    /// <summary>
+    /// Covers V2 API, see
+    /// http://msdn.microsoft.com/en-us/library/hh850031%28v=vs.85%29.aspx
+    /// </summary>
+    public static class JobState
+    {
+        public const UInt16 New = 2;
+        public const UInt16 Starting = 3;
+        public const UInt16 Running = 4;
+        public const UInt16 Suspended = 5;
+        public const UInt16 ShuttingDown = 6;
+        public const UInt16 Completed = 7;
+        public const UInt16 Terminated = 8;
+        public const UInt16 Killed = 9;
+        public const UInt16 Exception = 10;
+        public const UInt16 Service = 11;
+        public static string ToString(UInt16 value)
+        {
+            string result = "Unknown JobState code";
+            switch (value)
+            {
+                case New: result = "New"; break;
+                case Starting: result = "Starting"; break;
+                case Running: result = "Running"; break;
+                case Suspended: result = "Suspended"; break;
+                case ShuttingDown: result = "ShuttingDown"; break;
+                case Completed: result = "Completed"; break;
+                case Terminated: result = "Terminated"; break;
+                case Killed: result = "Killed"; break;
+                case Exception: result = "Exception"; break;
+                case Service: result = "Service"; break;
+            }
+            return result;
+        }
+    }
+
+    /// <summary>
+    /// V2 API (see http://msdn.microsoft.com/en-us/library/hh850279(v=vs.85).aspx)
+    /// has removed 'Paused' and 'Suspended' as compared to the
+    /// V1 API (see http://msdn.microsoft.com/en-us/library/cc723874%28v=vs.85%29.aspx)
+    /// However, Paused and Suspended appear on the VM state transition table
+    /// (see http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods)
+    /// </summary>
+    public class RequiredState
+    {
+        public const UInt16 Enabled = 2;        // Turns the VM on.
+        public const UInt16 Disabled = 3;       // Turns the VM off.
+        public const UInt16 ShutDown = 4;
+        public const UInt16 Offline = 6;
+        //public const UInt16 Test = 7;
+        public const UInt16 Defer = 8;
+        // public const UInt16 Quiesce = 9;
+        // public const UInt16 Reboot = 10;        // A hard reset of the VM.
+        public const UInt16 Reset = 11;         // For future use.
+        public const UInt16 Paused = 9;     // Pauses the VM.
+        public const UInt16 Suspended = 32779;  // Saves the state of the VM.
+
+        public static string ToString(UInt16 value)
+        {
+            string result = "Unknown RequiredState code";
+            switch (value)
+            {
+                case Enabled: result = "Enabled"; break;
+                case Disabled: result = "Disabled"; break;
+                case ShutDown: result = "ShutDown"; break;
+                case Offline: result = "Offline"; break;
+                case Defer: result = "Defer"; break;
+                case Reset: result = "Reset"; break;
+            }
+            return result;
+        }
+    }
+
+    /// <summary>
+    /// V2 API specifies the states below in its  state transition graph at
+    /// http://msdn.microsoft.com/en-us/library/hh850116(v=vs.85).aspx#methods
+    /// However, the CIM standard has additional possibilities based on the description
+    /// of EnabledState.
+    /// The previous V1 API is described by 
+    /// http://msdn.microsoft.com/en-us/library/cc136822%28v=vs.85%29.aspx
+    /// </summary>
+        public class EnabledState
+    {
+            /// <summary>
+            /// The state of the VM could not be determined.
+            /// </summary>
+        public const UInt16 Unknown = 0;
+            /// <summary>
+            /// The VM is running.
+            /// </summary>
+        public const UInt16 Enabled = 2;
+            /// <summary>
+            /// The VM is turned off.
+            /// </summary>
+        public const UInt16 Disabled = 3;
+            /// <summary>
+            /// The VM is paused.
+            /// </summary>
+        public const UInt16 Paused = 32768;
+            /// <summary>
+            /// The VM is in a saved state.
+            /// </summary>
+        public const UInt16 Suspended = 32769;
+            /// <summary>
+            /// The VM is starting. This is a transitional state between 3 (Disabled)
+            /// or 32769 (Suspended) and 2 (Enabled) initiated by a call to the 
+            /// RequestStateChange method with a RequestedState parameter of 2 (Enabled).
+            /// </summary>
+        public const UInt16 Starting = 32770;
+            /// <summary>
+            /// Starting with Windows Server 2008 R2 this value is not supported. 
+            /// If the VM is performing a snapshot operation, the element at index 1 
+            /// of the OperationalStatus property array will contain 32768 (Creating Snapshot), 
+            /// 32769 (Applying Snapshot), or 32770 (Deleting Snapshot).
+            /// </summary>
+        public const UInt16 Snapshotting = 32771;
+            /// <summary>
+            /// The VM is saving its state. This is a transitional state between 2 (Enabled)
+            /// and 32769 (Suspended) initiated by a call to the RequestStateChange method 
+            /// with a RequestedState parameter of 32769 (Suspended).
+            /// </summary>
+        public const UInt16 Saving = 32773;
+            /// <summary>
+            /// The VM is turning off. This is a transitional state between 2 (Enabled) 
+            /// and 3 (Disabled) initiated by a call to the RequestStateChange method 
+            /// with a RequestedState parameter of 3 (Disabled) or a guest operating system 
+            /// initiated power off.
+            /// </summary>
+        public const UInt16 Stopping = 32774;
+            /// <summary>
+            /// The VM is pausing. This is a transitional state between 2 (Enabled) and 32768 (Paused) initiated by a call to the RequestStateChange method with a RequestedState parameter of 32768 (Paused).
+            /// </summary>
+        public const UInt16 Pausing = 32776;
+            /// <summary>
+            /// The VM is resuming from a paused state. This is a transitional state between 32768 (Paused) and 2 (Enabled).
+            /// </summary>
+        public const UInt16 Resuming = 32777;
+
+        public static string ToString(UInt16 value)
+        {
+            string result = "Unknown";
+            switch (value)
+            {
+                case Enabled: result = "Enabled"; break;
+                case Disabled: result = "Disabled"; break;
+                case Paused: result = "Paused"; break;
+                case Suspended: result = "Suspended"; break;
+                case Starting: result = "Starting"; break;
+                case Snapshotting: result = "Snapshotting"; break; // NOT used
+                case Saving: result = "Saving"; break;
+                case Stopping: result = "Stopping"; break;
+                case Pausing: result = "Pausing"; break;
+                case Resuming: result = "Resuming"; break;
+            }
+            return result;
+        }
+
+        public static string ToCloudStackState(UInt16 value)
+        {
+            string result = "Unknown";
+            switch (value)
+            {
+                case Enabled: result = "Running"; break;
+                case Disabled: result = "Stopped"; break;
+                case Paused: result = "Unknown"; break;
+                case Suspended: result = "Unknown"; break;
+                case Starting: result = "Starting"; break;
+                case Snapshotting: result = "Unknown"; break; // NOT used
+                case Saving: result = "Saving"; break;
+                case Stopping: result = "Stopping"; break;
+                case Pausing: result = "Unknown"; break;
+                case Resuming: result = "Starting"; break; 
+            }
+            return result;
+        }
 
         public static string ToCloudStackPowerState(UInt16 value)
         {
@@ -2761,5 +2953,5 @@
             }
             return result;
         }
-    }

-}

+    }
+}
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
index 12fc39d..7888e43 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
@@ -177,7 +177,6 @@
     protected final int _retry = 24;
     protected final int _sleep = 10000;
     protected static final int DEFAULT_DOMR_SSHPORT = 3922;
-    private final int maxid = 4094;
     private String _clusterGuid;
 
     // Used by initialize to assert object configured before
@@ -535,11 +534,15 @@
             }
             int vlanId = Integer.parseInt(BroadcastDomainType.getValue(broadcastUri));
             int publicNicInfo = -1;
-            publicNicInfo = getVmNics(vmName, maxid);
+            publicNicInfo = getVmFreeNicIndex(vmName);
             if (publicNicInfo > 0) {
-                modifyNicVlan(vmName, vlanId, publicNicInfo);
+                modifyNicVlan(vmName, vlanId, publicNicInfo, true, cmd.getNic().getName());
+                return new PlugNicAnswer(cmd, true, "success");
             }
-            return new PlugNicAnswer(cmd, true, "success");
+            String msg = " Plug Nic failed for the vm as it has reached max limit of NICs to be added";
+            s_logger.warn(msg);
+            return new PlugNicAnswer(cmd, false, msg);
+
         } catch (Exception e) {
             s_logger.error("Unexpected exception: ", e);
             return new PlugNicAnswer(cmd, false, "Unable to execute PlugNicCommand due to " + e.toString());
@@ -563,7 +566,7 @@
             int publicNicInfo = -1;
             publicNicInfo = getVmNics(vmName, vlanId);
             if (publicNicInfo > 0) {
-                modifyNicVlan(vmName, maxid, publicNicInfo);
+                modifyNicVlan(vmName, 2, publicNicInfo, false, "");
             }
             return new UnPlugNicAnswer(cmd, true, "success");
         } catch (Exception e) {
@@ -1765,6 +1768,37 @@
         return new IpAssocAnswer(cmd, results);
     }
 
+
+    protected int getVmFreeNicIndex(String vmName) {
+        GetVmConfigCommand vmConfig = new GetVmConfigCommand(vmName);
+        URI agentUri = null;
+        int nicposition = -1;
+        try {
+            String cmdName = GetVmConfigCommand.class.getName();
+            agentUri =
+                    new URI("https", null, _agentIp, _port,
+                            "/api/HypervResource/" + cmdName, null, null);
+        } catch (URISyntaxException e) {
+            String errMsg = "Could not generate URI for Hyper-V agent";
+            s_logger.error(errMsg, e);
+        }
+        String ansStr = postHttpRequest(s_gson.toJson(vmConfig), agentUri);
+        Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
+        s_logger.debug("GetVmConfigCommand response received "
+                + s_gson.toJson(result));
+        if (result.length > 0) {
+            GetVmConfigAnswer ans = ((GetVmConfigAnswer)result[0]);
+            List<NicDetails> nics = ans.getNics();
+            for (NicDetails nic : nics) {
+                if (nic.getState() == false) {
+                    nicposition = nics.indexOf(nic);
+                    break;
+                }
+            }
+        }
+        return nicposition;
+    }
+
     protected int getVmNics(String vmName, int vlanid) {
         GetVmConfigCommand vmConfig = new GetVmConfigCommand(vmName);
         URI agentUri = null;
@@ -1816,8 +1850,9 @@
         }
     }
 
-    protected void modifyNicVlan(String vmName, int vlanId, int pos) {
-        ModifyVmNicConfigCommand modifynic = new ModifyVmNicConfigCommand(vmName, vlanId, pos);
+    protected void modifyNicVlan(String vmName, int vlanId, int pos, boolean enable, String switchLabelName) {
+        ModifyVmNicConfigCommand modifyNic = new ModifyVmNicConfigCommand(vmName, vlanId, pos, enable);
+        modifyNic.setSwitchLableName(switchLabelName);
         URI agentUri = null;
         try {
             String cmdName = ModifyVmNicConfigCommand.class.getName();
@@ -1828,7 +1863,7 @@
             String errMsg = "Could not generate URI for Hyper-V agent";
             s_logger.error(errMsg, e);
         }
-        String ansStr = postHttpRequest(s_gson.toJson(modifynic), agentUri);
+        String ansStr = postHttpRequest(s_gson.toJson(modifyNic), agentUri);
         Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
         s_logger.debug("executeRequest received response "
                 + s_gson.toJson(result));