private void DoPrepareDeploymentToClusteredEnvironment(EnvironmentInfo environmentInfo, Lazy <string> artifactsBinariesDirPathProvider)
        {
            string clusterGroupName = environmentInfo.GetFailoverClusterGroupNameForProject(DeploymentInfo.ProjectName);

            if (string.IsNullOrEmpty(clusterGroupName))
            {
                throw new InvalidOperationException(string.Format("There is no cluster group defined for project '{0}' in environment '{1}'.", DeploymentInfo.ProjectName, environmentInfo.Name));
            }

            string failoverClusterMachineName = environmentInfo.FailoverClusterMachineName;

            if (string.IsNullOrEmpty(failoverClusterMachineName))
            {
                throw new InvalidOperationException(string.Format("Environment '{0}' has no failover cluster machine name defined.", environmentInfo.Name));
            }

            string currentNodeName =
                _failoverClusterManager.GetCurrentNodeName(failoverClusterMachineName, clusterGroupName);

            if (string.IsNullOrEmpty(currentNodeName))
            {
                throw new InvalidOperationException(string.Format("Cluster group '{0}' has no current node in a cluster '{1}' in environment '{2}'.", clusterGroupName, environmentInfo.FailoverClusterMachineName, environmentInfo.Name));
            }

            PostDiagnosticMessage(string.Format("Current node: '{0}'.", currentNodeName), DiagnosticMessageType.Trace);

            List <string> possibleNodeNames =
                _failoverClusterManager.GetPossibleNodeNames(failoverClusterMachineName, clusterGroupName)
                .ToList();

            PostDiagnosticMessage(string.Format("Possible nodes: {0}.", string.Join(", ", possibleNodeNames.Select(n => string.Format("'{0}'", n)))), DiagnosticMessageType.Trace);

            if (possibleNodeNames.Count < 2)
            {
                throw new InvalidOperationException(string.Format("There is only one possible node for cluster group '{0}' in a cluster '{1}' in environment '{2}'.", clusterGroupName, environmentInfo.FailoverClusterMachineName, environmentInfo.Name));
            }

            // update nt service on all machines other than current owner node
            CollectedCredentials cachedCollectedCredentials = null;

            Func <string, Func <CollectedCredentials> > collectCredentialsFunc =
                machineName =>
                () =>
            {
                // ReSharper disable AccessToModifiedClosure
                if (cachedCollectedCredentials != null)
                {
                    return(cachedCollectedCredentials);
                }
                // ReSharper restore AccessToModifiedClosure

                if (UseLocalSystemUser)
                {
                    cachedCollectedCredentials = new CollectedCredentials(LocalSystemUserName);
                }
                else
                {
                    EnvironmentUser environmentUser =
                        environmentInfo.GetEnvironmentUser(_projectInfo.NtServiceUserId);

                    string environmentUserPassword =
                        PasswordCollectorHelper.CollectPasssword(
                            _passwordCollector,
                            DeploymentInfo.DeploymentId,
                            environmentInfo,
                            machineName,
                            environmentUser,
                            OnDiagnosticMessagePosted);

                    cachedCollectedCredentials =
                        new CollectedCredentials(
                            environmentUser.UserName,
                            environmentUserPassword);
                }

                return(cachedCollectedCredentials);
            };

            foreach (string possibleNodeName in possibleNodeNames)
            {
                string machineName = possibleNodeName;

                if (string.Equals(machineName, currentNodeName, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                DoPrepareCommonDeploymentSteps(
                    _projectInfo.NtServiceName,
                    machineName,
                    environmentInfo.NtServicesBaseDirPath,
                    absoluteLocalPath => EnvironmentInfo.GetNetworkPath(machineName, absoluteLocalPath),
                    artifactsBinariesDirPathProvider,
                    collectCredentialsFunc(machineName),
                    false);
            }

            // move cluster group to another node
            string targetNodeName =
                possibleNodeNames.FirstOrDefault(nodeName => nodeName != currentNodeName);

            PostDiagnosticMessage(string.Format("Target node: '{0}'.", targetNodeName), DiagnosticMessageType.Trace);

            if (string.IsNullOrEmpty(targetNodeName))
            {
                throw new InvalidOperationException(string.Format("There is no node in cluster '{0}' that we can move cluster group '{1}' to.", failoverClusterMachineName, clusterGroupName));
            }

            AddSubTask(
                new MoveClusterGroupToAnotherNodeDeploymentStep(
                    _failoverClusterManager,
                    failoverClusterMachineName,
                    clusterGroupName,
                    targetNodeName));

            // update nt service on the machine that was the previous owner node
            string previousMachineName = currentNodeName;

            DoPrepareCommonDeploymentSteps(
                _projectInfo.NtServiceName,
                previousMachineName,
                environmentInfo.NtServicesBaseDirPath,
                absoluteLocalPath => EnvironmentInfo.GetNetworkPath(previousMachineName, absoluteLocalPath),
                artifactsBinariesDirPathProvider,
                collectCredentialsFunc(previousMachineName),
                false);
        }
        private void DoPrepareDeploymentToClusteredEnvironment(Lazy <string> artifactsBinariesDirPathProvider, NtServiceProjectInfo extendedServiceProjectInfo)
        {
            string clusterGroupName = _environmentInfo.GetFailoverClusterGroupNameForProject(extendedServiceProjectInfo.Name);

            if (string.IsNullOrEmpty(clusterGroupName))
            {
                throw new InvalidOperationException(string.Format("There is no cluster group defined for project '{0}' in environment '{1}'.", extendedServiceProjectInfo.Name, _environmentInfo.Name));
            }

            string failoverClusterMachineName = _environmentInfo.FailoverClusterMachineName;

            if (string.IsNullOrEmpty(failoverClusterMachineName))
            {
                throw new InvalidOperationException(string.Format("Environment '{0}' has no failover cluster machine name defined.", _environmentInfo.Name));
            }

            string currentNodeName =
                _failoverClusterManager.GetCurrentNodeName(failoverClusterMachineName, clusterGroupName);

            if (string.IsNullOrEmpty(currentNodeName))
            {
                throw new InvalidOperationException(string.Format("Cluster group '{0}' has no current node in a cluster '{1}' in environment '{2}'.", clusterGroupName, _environmentInfo.FailoverClusterMachineName, _environmentInfo.Name));
            }

            PostDiagnosticMessage(string.Format("Current node: '{0}'.", currentNodeName), DiagnosticMessageType.Trace);

            List <string> possibleNodeNames =
                _failoverClusterManager.GetPossibleNodeNames(failoverClusterMachineName, clusterGroupName)
                .ToList();

            PostDiagnosticMessage(string.Format("Possible nodes: {0}.", string.Join(", ", possibleNodeNames.Select(n => string.Format("'{0}'", n)))), DiagnosticMessageType.Trace);

            if (possibleNodeNames.Count < 2)
            {
                throw new InvalidOperationException(string.Format("There is only one possible node for cluster group '{0}' in a cluster '{1}' in environment '{2}'.", clusterGroupName, _environmentInfo.FailoverClusterMachineName, _environmentInfo.Name));
            }

            foreach (string possibleNodeName in possibleNodeNames)
            {
                string machineName = possibleNodeName;

                if (string.Equals(machineName, currentNodeName, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                DoPrepareCommonDeploymentSteps(
                    absoluteLocalPath => EnvironmentInfo.GetNetworkPath(machineName, absoluteLocalPath),
                    artifactsBinariesDirPathProvider);
            }

            // move cluster group to another node
            string targetNodeName =
                possibleNodeNames.FirstOrDefault(nodeName => nodeName != currentNodeName);

            PostDiagnosticMessage(string.Format("Target node: '{0}'.", targetNodeName), DiagnosticMessageType.Trace);

            if (string.IsNullOrEmpty(targetNodeName))
            {
                throw new InvalidOperationException(string.Format("There is no node in cluster '{0}' that we can move cluster group '{1}' to.", failoverClusterMachineName, clusterGroupName));
            }

            AddSubTask(
                new MoveClusterGroupToAnotherNodeDeploymentStep(
                    _failoverClusterManager,
                    failoverClusterMachineName,
                    clusterGroupName,
                    targetNodeName));

            // update nt service on the machine that was the previous owner node
            string previousMachineName = currentNodeName;

            DoPrepareCommonDeploymentSteps(
                absoluteLocalPath => EnvironmentInfo.GetNetworkPath(previousMachineName, absoluteLocalPath),
                artifactsBinariesDirPathProvider);
        }