private static void KillAndResetVirtualMachine(HypervVirtualMachine virtualMachine, HypervMachineDescription specification)
        {
            virtualMachine.Terminate();

            DateTimeOffset killTime = DateTimeOffset.Now + TimeSpan.FromMilliseconds(GlobalConstants.DefaultMaximumMachineShutdownTime);
            while ((virtualMachine.State != HypervVirtualMachineState.TurnedOff) && (DateTimeOffset.Now <= killTime))
            {
                Thread.Sleep(10);
            }

            virtualMachine.RestoreToSnapshot(specification.SnapshotToReturnTo);
        }
        private void ShutdownVirtualMachine(MachineDescription environment, ITestSectionBuilder sectionBuilder)
        {
            var specification = environment as HypervMachineDescription;
            if (specification == null)
            {
                throw new InvalidEnvironmentSpecificationException();
            }

            // See if the host machine is alive
            var host = specification.HostMachineId;
            var hostSpecification = m_EnvironmentById(host);
            if (hostSpecification == null)
            {
                sectionBuilder.AddErrorMessage(
                            string.Format(
                                CultureInfo.InvariantCulture,
                                "Could not locate VM host: {0}",
                                hostSpecification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            Diagnostics.Log(
                LevelToLog.Debug,
                HyperVConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Terminating Hyper-V virtual machine {0} [image: {1}] on host {2}",
                    specification.Name,
                    specification.Image,
                    hostSpecification.Name));

            // Connect to the Hyper-V host for the given environment
            var virtualMachine = new HypervVirtualMachine(specification.Image);
            try
            {
                virtualMachine.Terminate();
            }
            catch (FailedToRestoreEnvironmentException)
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Failed to shut down virtual machine: {0}",
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw;
            }

            var killTime = DateTimeOffset.Now + TimeSpan.FromMilliseconds(GlobalConstants.DefaultMaximumMachineShutdownTime);
            while ((virtualMachine.State != HypervVirtualMachineState.TurnedOff) && (DateTimeOffset.Now <= killTime))
            {
                Thread.Sleep(10);
            }

            try
            {
                virtualMachine.RestoreToSnapshot(specification.SnapshotToReturnTo);
            }
            catch (FailedToRestoreEnvironmentException)
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Failed to restore virtual machine snapshot [{0}] for machine {1}",
                        specification.SnapshotToReturnTo,
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw;
            }

            Diagnostics.Log(
                LevelToLog.Debug,
                HyperVConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Hyper-V virtual machine {0} terminated",
                    specification.Name));

            sectionBuilder.AddInformationMessage(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Virtual machine shut down: {0}",
                    specification.NetworkName));
            sectionBuilder.FinalizeAndStore(true);
        }
        /// <summary>
        /// Load the environment.
        /// </summary>
        /// <param name="environment">The specification for the environment.</param>
        /// <param name="pingTimeoutInMilliseconds">The number of milliseconds that the ping operation should wait for a response.</param>
        /// <param name="maximumWaitTimeInMilliseconds">
        ///     The number of milliseconds that the operation should wait for the machine to come online.
        /// </param>
        /// <param name="pingCycleTimeInMilliseconds">The amount of time the operation should wait between consecutive ping operations.</param>
        /// <param name="sectionBuilder">
        /// The object used to write information to the report about the starting and stopping of the environment.
        /// </param>
        /// <returns>An action that should be used to return the environment to its previous state in case the environment load fails.</returns>
        protected override Action LoadEnvironment(
            MachineDescription environment,
            int pingTimeoutInMilliseconds,
            int maximumWaitTimeInMilliseconds,
            int pingCycleTimeInMilliseconds,
            ITestSectionBuilder sectionBuilder)
        {
            var specification = environment as HypervMachineDescription;
            if (specification == null)
            {
                throw new InvalidEnvironmentSpecificationException();
            }

            // See if the host machine is alive
            var host = specification.HostMachineId;
            var hostSpecification = m_EnvironmentById(host);
            if (hostSpecification == null)
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Unable to locate host machine: {0}",
                        hostSpecification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            // See if the host is awake and if not try to wake it up.
            var physicalHostSpecification = hostSpecification as PhysicalMachineDescription;
            var canStartRemotely = physicalHostSpecification != null && physicalHostSpecification.CanStartRemotely;
            if (!MachineHelpers.WakeNetworkedMachineAndWaitForNetworkSignIn(
                hostSpecification.NetworkName,
                hostSpecification.MacAddress,
                Diagnostics,
                canStartRemotely,
                pingTimeoutInMilliseconds,
                maximumWaitTimeInMilliseconds,
                pingCycleTimeInMilliseconds))
            {
                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Unable to start host machine: {0}",
                        hostSpecification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);

                throw new CouldNotLoadEnvironmentException();
            }

            // Connect to the Hyper-V host for the given environment
            var virtualMachine = new HypervVirtualMachine(specification.Image);
            if (virtualMachine.State == HypervVirtualMachineState.Paused || virtualMachine.State == HypervVirtualMachineState.Running)
            {
                sectionBuilder.AddWarningMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Virtual machine running unexpectedly: {0}",
                        specification.NetworkName));
                sectionBuilder.AddWarningMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Resetting virtual machine: {0}",
                        specification.NetworkName));

                KillAndResetVirtualMachine(virtualMachine, specification);
            }

            virtualMachine.Start();

            Diagnostics.Log(
                LevelToLog.Debug,
                HyperVConstants.LogPrefix,
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Started Hyper-V virtual machine {0} [image: {1}] on host {2}",
                    specification.Name,
                    specification.Image,
                    hostSpecification.Name));

            sectionBuilder.AddInformationMessage(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Started machine: {0}",
                    specification.NetworkName));

            return () =>
            {
                Diagnostics.Log(
                    LevelToLog.Debug,
                    HyperVConstants.LogPrefix,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Terminating Hyper-V virtual machine {0} [image: {1}] on host {2}",
                        specification.Name,
                        specification.Image,
                        hostSpecification.Name));

                KillAndResetVirtualMachine(virtualMachine, specification);

                sectionBuilder.AddErrorMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Terminated machine: {0}",
                        specification.NetworkName));
                sectionBuilder.FinalizeAndStore(false);
            };
        }