public IEnumerable <VariablesHierarchyInfoDto> GetVariablesHierarchy(short projectID)
        {
            var nodes = new List <VariablesHierarchyInfoDto>();

            // Global
            var globalNode = new VariablesHierarchyInfoDto(VariableScope.Global, 0, "Settings");

            globalNode.Variables.AddRange(this.GetVariables(VariableScope.Global, 0));
            nodes.Add(globalNode);

            // Project
            Project project;

            using (var uow = _unitOfWorkFactory.Create())
            {
                project = uow.Repository <Project>()
                          .Get(
                    p => p.ProjectID == projectID,
                    p => p.TargetGroups,
                    p => p.Environments,
                    p => p.DeploymentPlans)
                          .SingleOrDefault();
            }
            var projectNode = new VariablesHierarchyInfoDto(VariableScope.Project, projectID, project.Name);

            projectNode.Variables.AddRange(this.GetVariables(VariableScope.Project, project.ProjectID));
            nodes.Add(projectNode);

            // Target Groups
            foreach (var tg in project.TargetGroups.OrderBy(g => g.Name))
            {
                var tgNode = new VariablesHierarchyInfoDto(VariableScope.TargetGroup, tg.TargetGroupID, tg.Name);
                tgNode.Variables.AddRange(this.GetVariables(VariableScope.TargetGroup, tg.TargetGroupID));
                if (!tgNode.Variables.IsNullOrEmpty())
                {
                    projectNode.Children.Add(tgNode);
                }
            }

            // Project Environments
            foreach (var pe in project.Environments.OrderBy(e => e.Name))
            {
                var peNode = new VariablesHierarchyInfoDto(VariableScope.Environment, pe.ProjectEnvironmentID, pe.Name);
                peNode.Variables.AddRange(this.GetVariables(VariableScope.Environment, pe.ProjectEnvironmentID));
                if (!peNode.Variables.IsNullOrEmpty())
                {
                    projectNode.Children.Add(peNode);
                }
            }

            // Target Group Environments
            var projectTargets = _projectTargetService.GetAllForProjectAs <ProjectTargetDto>(projectID);

            foreach (var tg in project.TargetGroups.OrderBy(g => g.Name))
            {
                foreach (var pe in project.Environments.OrderBy(e => e.Name))
                {
                    var name  = "{0} / {1}".FormatString(tg.Name, pe.Name);
                    var tgeID = _targetGroupEnvironmentService.GetCombinationID(tg.TargetGroupID, pe.ProjectEnvironmentID);
                    if (!tgeID.HasValue)
                    {
                        continue;
                    }

                    var tgeNode = new VariablesHierarchyInfoDto(VariableScope.TargetGroupEnvironment, tgeID.Value, name);
                    tgeNode.Variables.AddRange(this.GetVariables(VariableScope.TargetGroupEnvironment, tgeID.Value));

                    // Project Targets
                    var projectTargetsForCombination = projectTargets.Where(t =>
                                                                            t.TargetGroupID == tg.TargetGroupID &&
                                                                            t.ProjectEnvironmentID == pe.ProjectEnvironmentID)
                                                       .ToList();
                    foreach (var pt in projectTargetsForCombination)
                    {
                        var ptNode = new VariablesHierarchyInfoDto(
                            VariableScope.ProjectTarget, pt.ProjectTargetID, pt.TargetName);
                        ptNode.Variables.AddRange(this.GetVariables(VariableScope.ProjectTarget, pt.ProjectTargetID));
                        if (!ptNode.Variables.IsNullOrEmpty())
                        {
                            tgeNode.Children.Add(ptNode);
                        }
                    }

                    if (!tgeNode.Variables.IsNullOrEmpty() || tgeNode.Children.Any(c => !c.Variables.IsNullOrEmpty()))
                    {
                        projectNode.Children.Add(tgeNode);
                    }
                }
            }

            // Deployment Plans
            foreach (var dp in project.DeploymentPlans.OrderBy(p => p.Name))
            {
                var dpNode = new VariablesHierarchyInfoDto(VariableScope.DeploymentPlan, dp.DeploymentPlanID, dp.Name);
                dpNode.Variables.AddRange(this.GetVariables(VariableScope.DeploymentPlan, dp.DeploymentPlanID));

                // Deployment Plan Steps
                var steps = _deploymentPlanStepService.GetAllForDeploymentPlan(dp.DeploymentPlanID);
                foreach (var ds in steps.OrderBy(s => s.ExecutionOrder))
                {
                    var dsNode = new VariablesHierarchyInfoDto(
                        VariableScope.DeploymentStep, ds.DeploymentPlanStepID, ds.Name);
                    dsNode.Variables.AddRange(this.GetVariables(VariableScope.DeploymentStep, ds.DeploymentPlanStepID));
                    if (!dsNode.Variables.IsNullOrEmpty())
                    {
                        dpNode.Children.Add(dsNode);
                    }
                }

                if (!dpNode.Variables.IsNullOrEmpty() || dpNode.Children.Any(c => !c.Variables.IsNullOrEmpty()))
                {
                    projectNode.Children.Add(dpNode);
                }
            }

            return(nodes);
        }
        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);
                    }
                }
            }
        }