private void ExecuteDeploymentSteps(DeploymentJob job)
        {
            var planSteps = _deploymentPlanStepService.GetEnabledForDeploymentPlan(job.DeploymentPlanID)
                .OrderBy(s => s.ExecutionOrder)
                .ToList();

            if (planSteps.IsNullOrEmpty())
                return;

            var targetGroupIDs = _targetGroupService.GetAllForProject(job.ProjectID)
                .OrderBy(g => g.Name)
                .Select(g => g.TargetGroupID)
                .ToArray();

            var environmentName = _projectEnvironmentService.GetByKey(job.ProjectEnvironmentID)
                .Name;

            foreach (var planStep in planSteps)
            {
                var jobStep = new DeploymentJobStep
                    {
                        DeploymentJobID = job.DeploymentJobID,
                        DeploymentPlanStepID = planStep.DeploymentPlanStepID,
                        Status = DeploymentStatus.Running,
                        StartTime = DateTime.UtcNow,
                        ExecutionReference = Guid.NewGuid()
                    };
                _deploymentJobStepService.Insert(jobStep);

                try
                {
                    var script = _scriptService.GetWithParameters(planStep.ScriptID);

                    if (planStep.AllTargetGroups)
                    {
                        this.ExecuteDeploymentStepOnTargets(script, planStep, job, environmentName,
                            jobStep.DeploymentJobStepID, targetGroupIDs);
                    }
                    else if (planStep.TargetGroupID.HasValue)
                    {
                        this.ExecuteDeploymentStepOnTargets(script, planStep, job, environmentName,
                            jobStep.DeploymentJobStepID, planStep.TargetGroupID.Value);
                    }
                    else  // Execute on deployment server
                    {
                        jobStep.ExecutedScript = _variableService.ResolveVariables(
                            script, planStep, job, environmentName);
                        jobStep.ExecutionOutput = "Waiting for output...";
                        _deploymentJobStepService.Update(jobStep);

                        var descriptor = new ScriptJobDescriptor
                            {
                                ScriptType = script.ScriptType,
                                ScriptBody = jobStep.ExecutedScript,
                                SuccessKeywords = script.SuccessKeywords,
                                FailureKeywords = script.FailureKeywords
                            };
                        var result = _scriptExecutionService.ExecuteScript(descriptor);

                        jobStep.ExecutionOutput = result.Output;
                        if (!result.IsSuccessful)
                            throw new Exception("Script execution on deployment server was not successful.");
                    }

                    jobStep.Status = DeploymentStatus.Finished;
                }
                catch (Exception ex)
                {
                    jobStep.Status = DeploymentStatus.Failed;
                    throw new Exception("Deployment step [{0}] failed.".FormatString(planStep.Name), ex);
                }
                finally
                {
                    jobStep.EndTime = DateTime.UtcNow;
                    _deploymentJobStepService.Update(jobStep);
                }
            }
        }
        private void ExecuteDeploymentStepOnTargets(
            Script script, DeploymentPlanStep planStep, DeploymentJob job, string environmentName,
            int deploymentJobStepID, params short[] targetGroupIDs)
        {
            foreach (var targetGroupID in targetGroupIDs)
            {
                var targetGroupEnvironmentID = _targetGroupEnvironmentService
                    .GetCombinationID(targetGroupID, job.ProjectEnvironmentID);

                var projectTargets = _projectTargetService
                    .GetAllForTargetGroupAndEnvironment(targetGroupID, job.ProjectEnvironmentID)
                    .OrderBy(t => t.Target.Name)
                    .ToList();

                foreach (var projectTarget in projectTargets)
                {
                    var targetID = projectTarget.TargetID;

                    var jobStepTarget = new DeploymentJobStepTarget
                    {
                        DeploymentJobStepID = deploymentJobStepID,
                        TargetID = targetID,
                        Status = DeploymentStatus.Running,
                        StartTime = DateTime.UtcNow,
                        ExecutionReference = Guid.NewGuid()
                    };
                    _deploymentJobStepTargetService.Insert(jobStepTarget);

                    var target = _targetService.GetWithCredential(targetID);

                    try
                    {
                        var username = target.UsernameWithDomain;
                        var password = _credentialService.DecryptPassword(target.Credential.Password);
                        var tempPassword = Guid.NewGuid().ToString();

                        var scriptBody = _variableService.ResolveVariables(script, planStep, job, environmentName,
                            targetGroupID, targetGroupEnvironmentID, projectTarget.ProjectTargetID,
                            target.ComputerName, username, tempPassword);

                        // Don't log real password.
                        jobStepTarget.ExecutedScript = scriptBody.Replace(tempPassword, "**********");
                        jobStepTarget.ExecutionOutput = "Waiting for output...";
                        _deploymentJobStepTargetService.Update(jobStepTarget);

                        scriptBody = scriptBody.Replace(tempPassword, password);

                        var descriptor = new ScriptJobDescriptor
                        {
                            ScriptType = script.ScriptType,
                            ScriptBody = scriptBody,
                            SuccessKeywords = script.SuccessKeywords,
                            FailureKeywords = script.FailureKeywords,
                            RemoteExecution = planStep.RemoteExecution,
                            TargetID = target.TargetID
                        };
                        var result = _scriptExecutionService.ExecuteScript(descriptor);

                        jobStepTarget.ExecutionOutput = result.Output;
                        if (!result.IsSuccessful)
                            throw new Exception("Script execution on target [{0}] was not successful."
                                .FormatString(target.Name));

                        jobStepTarget.Status = DeploymentStatus.Finished;
                    }
                    catch (Exception ex)
                    {
                        jobStepTarget.Status = DeploymentStatus.Failed;
                        throw new Exception("Deployment step [{0}] failed for target [{1}]."
                            .FormatString(planStep.Name, target.Name), ex);
                    }
                    finally
                    {
                        jobStepTarget.EndTime = DateTime.UtcNow;
                        _deploymentJobStepTargetService.Update(jobStepTarget);
                    }
                }
            }
        }